获取继承实体的导航属性

时间:2014-09-26 15:28:54

标签: c# .net entity-framework entity-framework-6

出于审计系统的目的,我需要能够在保存实体之前通过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吗? 或者,我可以采用不同的方法来检索更改跟踪器中实体的导航属性?

1 个答案:

答案 0 :(得分:2)

问题是你回到了你感兴趣的子类型的EntitySet。但EntitySet是在基类型上定义的:你得到ChildEntity s by ...

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);