【问题标题】:How to distinguish Navigation Properties from regular ones when using GetProperties?使用 GetProperties 时如何区分导航属性和常规属性?
【发布时间】:2015-02-09 14:58:52
【问题描述】:

有没有办法区分实体框架类(数据库优先)上的常规集合属性和导航属性?

我目前正在检查对象 is ICollectionIsVirtual 是否存在,但我认为这可能会在某人已声明为虚拟集合的常规属性上触发。

问题:还有其他方法可以区分导航属性与其他属性吗?

上下文:我使用它来比较任何对象的值,但我希望它忽略导航属性(以忽略循环引用等)。

foreach (var item in (IEnumerable)obj)
{
    list2.MoveNext();
    var item2 = list2.Current;
    foreach (PropertyInfo propInfo in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        Object v1 = propInfo.GetValue(item);
        Object v2 = propInfo.GetValue(item2);

        Primitive = (v1 == null && v2 == null) || IsPrimitive(v1.GetType());

        if (Primitive)
        {
            Assert.AreEqual(v1, v2);
        }
        else
        {
            // Ignore Navigation Properties
            // Currently assuming Virtual properties to be Navigation...
            if (propInfo.GetGetMethod().IsVirtual) continue;
            CompareObjects(v1, v2);
        }
    }
}

【问题讨论】:

  • "" is ICollection.
  • 我不明白你想说什么?
  • 您对虚拟字符串属性的检查将失败。
  • 哦,不知道。另一个原因是我需要更多地了解导航属性,以便更好地将它们与常规属性区分开来。

标签: c# entity-framework reflection


【解决方案1】:

好吧,如果你想知道导航属性的名称和实体相关的标量属性,我建议你使用这段代码:

using (var db = new YourContext())
{
    var workspace = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
    var itemCollection = (ObjectItemCollection)(workspace.GetItemCollection(DataSpace.OSpace));
    var entityType = itemCollection.OfType<EntityType>().Single(e => itemCollection.GetClrType(e) == typeof(YourEntity));
    
    foreach (var navigationProperty in entityType.NavigationProperties)
    {
        Console.WriteLine(navigationProperty.Name);
    }
    
    foreach (var property in entityType.Properties)
    {
        Console.WriteLine(property.Name);
    }
}

【讨论】:

    【解决方案2】:

    使用 GetProperties() 时的一个解决方案是创建一个 IEntity 接口并将其应用于所有实体。然后,您可以通过检查它们是否实现 IEntity 和多实体导航来跳过单个实体导航属性 如果它们是 ICollection 类型。

    所以在你的 foreach 中,

    if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.ICollection<>)) continue;
    if (property.PropertyType.GetInterfaces().Contains(typeof(IEntity))) continue;
    

    这是一个使用此逻辑仅返回可更新属性的简单方法:

    private IEnumerable<PropertyInfo> GetUpdateableProperties<T>(T entity) where T : IEntity
        {
            return entity.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty)
                .Where(property =>
                    property.CanWrite &&
                    !property.PropertyType.GetInterfaces().Contains(typeof(IEntity)) &&
                    !(property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
                    );
        }
    

    【讨论】:

    • 这在排序中可以工作,但是如果你有一个类有一个ICollection 不是导航属性怎么办。个人无法想象一个场景,但仍然需要考虑。还有单对象导航属性呢?
    • 我修改了我的答案以处理单个对象导航。我看不到实体框架的实体属性如何成为导航属性的 ICollection 接受,所以我不介意。但您可以检查 ICollection 是否属于 IEntity。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多