出于审计系统的目的,我需要能够在保存实体之前通过ChangeTracker / ObjectStateManager检索实体的导航属性。检索到导航属性后,我将遍历每个导航属性并保存其名称,类型和主键。
我正在使用以下代码来做到这一点:
var context = new SomeDbContext();
var entity = context.SomeEntities.Find(1);
entity.MakeSomeChanges();
entity.MakeMoreChanges();
context.ObjectContext.DetectChanges();
var stateManager = context.ObjectContext.ObjectStateManager;
var stateEntry = stateManager.GetObjectStateEntry(entity);
var entityType = stateEntry.EntitySet.ElementType as EntityType;
// from here I can work with the navigation properties.
foreach (var property in entityType.NavigationProperties)
{
// process nav property
}
这种方法对基本实体非常有用,但是我遇到的问题是试图在从基本实体继承的实体上找到导航属性。例如,给定以下结构:
public class ParentEntity
{
public int Id { get; set; }
}
public class ChildEntity : ParentEntity
{
public int NavigationEntityId { get; set; }
public virtual NavigationEntity NavigationEntity { get; set; }
}
public class NavigationEntity
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildEntity> ChildEntities { get; set; }
}
我如何在ChildEntity上找到导航属性?如果我使用与SomeEntity相同的方法,则会发生以下情况:
var context = new SomeDbContext();
var navEntity = context.NavigationEntities.Find(1);
var childEntity = new ChildEntity();
navEntity.ChildEntities.Add(childEntity);
context.ObjectContext.DetectChanges();
var stateManager = context.ObjectContext.ObjectStateManager;
var stateEntry = stateManager.GetObjectStateEntry(childEntity);
// entityType here turns into ParentEntity, which does not have nav properties
var entityType = stateEntry.EntitySet.ElementType as EntityType;
var properties = entityType.NavigationProperties;
// properties.Count() == 0
有什么办法可以将ParentEntity转换为ChildEntity?
也许我可以采用另一种方法来获取变更跟踪器中实体的导航属性?
最佳答案
问题是您返回到感兴趣的子类型的EntitySet
。但是EntitySet
是在基本类型上定义的:通过以下方式获得ChildEntity
:
db.ParentEntities.OfType<ChildEntity>()
因此,您必须以其他方式获取导航属性。我为此目的使用了这个小功能:
IEnumerable<NavigationProperty> GetNavigationProperies<T>(DbContext context,
T entity = default(T))
where T : class
{
var oc = ((IObjectContextAdapter)context).ObjectContext;
var entityType = oc.MetadataWorkspace
.GetItems(DataSpace.OSpace).OfType<EntityType>()
.FirstOrDefault (et => et.Name == typeof(T).Name);
return entityType != null
? entityType.NavigationProperties
: Enumerable.Empty<NavigationProperty>();
}
您可以在不指定具体对象和指定泛型类型参数的情况下调用此方法...
var navprops = GetNavigationProperies<ChildEntity>(db);
或与对象并依靠类型推断...
var navprops = GetNavigationProperies(db, childEntity);