出于审计系统的目的,我需要能够在保存实体之前通过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);

08-17 16:42