J'ai une entité en l'obtenant de DbEntityEntry.Entity
. Cela renvoie le proxy Entity Framework pour l'entité.
Comment accéder à l'objet sous-jacent en tant que type d'origine au lieu du proxy?
Sinon, je dois essayer dynamiquement de convertir le proxy en type d'entité. Voici un début ..
var theEntityType = entityEntry.Entity;
if (theEntityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies")
theEntityType = entityType.BaseType;
// Now I need to cast to the correct type
var entityObject = (theEntityType)entityEntry.Entity; // THIS WON'T WORK BECAUSE `theEntityType` is dynamic.
// My entites also don't implement IConvertible
Tout d'abord, je dois dire qu'il n'y a pas d'objet sous-jacent. Un proxy ne n'emballe pas un objet d'entité (motif décorateur), il en tire (héritage). Donc, nous ne pouvons pas décompresser l’entité, nous ne pouvons que convertir un proxy en objet de base. La conversion (contrairement au casting) crée toujours un nouvel objet.
Pour cette conversion, nous pouvons exploiter le fait que la plupart du temps, en renvoyant les mandataires par EF, le type de temps de compilation d'un proxy est le type de base. En d'autres termes, si un proxy est entré en tant qu'argument d'une méthode générique, le paramètre générique sera déduit en tant que type de base. Cette fonctionnalité nous permet de créer une méthode qui fait ce que vous voulez:
T UnProxy<T>(DbContext context, T proxyObject) where T : class
{
var proxyCreationEnabled = context.Configuration.ProxyCreationEnabled;
try
{
context.Configuration.ProxyCreationEnabled = false;
T poco = context.Entry(proxyObject).CurrentValues.ToObject() as T;
return poco;
}
finally
{
context.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
}
}
Explication
L'objet proxy entre dans la méthode. Son type est inféré en tant que type de base POCO. Nous pouvons maintenant temporairement désactiver ProxyCreationEnabled
sur le contexte et copier l'objet proxy dans un objet de son type POCO de base. Cette action de copie utilise avec gratitude quelques fonctionnalités EF.
En travaillant avec EF 6, j’ai utilisé le code suivant pour obtenir le type d’entité POCO sous-jacent à partir du type de proxy,
var entityType = ObjectContext.GetObjectType(dbEntitymodifiedEntry.Entity.GetType());
ObjectContext.GetObjectType
: Renvoie l'objet POCO à partir d'un proxy
référence: https://docs.Microsoft.com/en-us/ef/ef6/fundamentals/proxies
Si vous devez effectuer cela depuis un projet qui n'a pas accès à EF ou à DBContext et que vous ne savez pas si le type que vous référencez est un proxy, vous pouvez procéder de la manière suivante:
public Type GetType
{
get
{
var thisType = _baseObject.GetType();
if (thisType.Namespace == "System.Data.Entity.DynamicProxies")
return thisType.BaseType;
return thisType;
}
}
La réponse proposée comporte un certain nombre de problèmes - par exemple, elle ne conserve pas les propriétés définies dans les classes partielles pour les classes POCO générées et elle recharge une entité à partir de la base de données (qui a également un impact sur les performances).
Vous pouvez essayer de désactiver les mandataires avant de demander des modifications, mais cela ne vous aidera peut-être pas si des entités ont déjà été chargées - ce seront déjà des types de proxy (cela dépend probablement de la version de EF, mais cela a fonctionné travailler une autre fois dans mon expérience). Vous devez également le matérialiser avant de renvoyer les mandataires - ce n’est pas évident, mais c’est juste une requête différée qui doit être matérialisée:
context.Configuration.ProxyCreationEnabled = false;
var changes = context.ChangeTracker.Entries().ToArray();
Utilisez AutoMapper 4.2.1 C'est le fait d'avoir DynamicMap qui peut supprimer le proxy de l'objet.
var parents = parentsRepo.GetAll().ToList();
Mapper.CreateMap<Parent,ParentDto>();
var parentsDto = Mapper.DynamicMap<List<ParentDto>>(parents);
Pour obtenir un objet convivial JSON dans EF Core, j'ai utilisé cette méthode:
T UnProxy<T>(T efObject) where T : new()
{
var type = efObject.GetType();
if (type.Namespace == "Castle.Proxies")
{
var baseType = type.BaseType;
var returnObject = new T();
foreach (var property in baseType.GetProperties())
{
var propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
if (propertyType.Namespace == "System")
{
var value = property.GetValue(efObject);
property.SetValue(returnObject, value);
}
}
return returnObject;
}
return efObject;
}