【问题标题】:Get ignored properties in Entity Framework在实体框架中获取被忽略的属性
【发布时间】:2016-08-14 02:09:51
【问题描述】:

我使用 EF 开发一个框架。我想获取一个实体的所有被忽略的属性来构建一些特殊的查询。我该怎么做?

public class Customer
{
    public int Id { get; set; }
    public DateTime BirthDate { get; set; }
    public int Age { get; set; }
}

public class CustomerContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>().Ignore(customer => customer.Age);
        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Customer> Customers { get; set; }
}

public static class DbContextExtensions
{
    public static List<string> GetIgnoredProperties(this DbContext context, string entityTypeName)
    {
         // ???
    }
}

【问题讨论】:

  • 嗯,我看错了你的问题。但是,无论如何我都会发布一个替代方案,使用反射和 [NotMapped] 属性。
  • 您使用的是哪个版本的 EntityFramework?
  • 我想知道您采取了哪些方法来完成这项工作?

标签: c# entity-framework ef-code-first entity-framework-6 entity-framework-5


【解决方案1】:

我知道这不是在回答您最初的问题,并且在我的 cmets 中我提到您应该使用反射,但这只是因为我读错了您的问题。

这里有一个使用反射的替代方法,如果你不正确的话。

如果您将[NotMapped] 属性分配给您想忽略的类的属性,您可以使用反射检索所有[NotMapped] 属性。以下是如何实现这一目标的示例。

var resultArray = yourClassInstance.GetType().GetProperties()
                            .Where(prop => Attribute.IsDefined(prop, typeof(NotMappedAttribute)));

希望这对您有所帮助。

【讨论】:

  • Fluent API 中 [NotMapped] 的等价物是像您一样使用忽略,但是如果您的类已经定义了属性,我认为放置 [NotMapped] 没有任何害处您要忽略的属性上的属性。流利的 API 方式和类上的普通属性可以很好地协同工作。
【解决方案2】:

您可以通过调用DbModelBuilder.Build 来实现您想要的。它将根据 DbModelBuilder 的配置设置创建一个 DbModelDbModel 公开了一个 ConceptualModel 来保存上下文使用的类型。 EdmModel 包含在上下文中声明的每种类型,并且对于每种类型,它包含在其配置期间未被 DbModelBuilder 忽略的属性。因此,要实现您想要的,您必须将每个实体类型的属性与 EdmModel 中存在的属性相交。它将给出它们之间的增量,然后是忽略的属性。这是一个例子:

public class CustomerContext : DbContext
{
    private static IReadOnlyDictionary<Type, IReadOnlyCollection<PropertyInfo>> _ignoredProperties;
    /// Hold the ignored properties configured from fluent mapping
    public static IReadOnlyDictionary<Type, IReadOnlyCollection<PropertyInfo>> IgnoredProperties
    {
        get
        {
            return _ignoredProperties;
        }
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>().Ignore(customer => customer.Age);

        // Build ignored properties only if they are not                
        if (_ignoredProperties == null)
        {                
            var model = modelBuilder.Build(this.Database.Connection);                
            var mappedEntityTypes = new Dictionary<Type, IReadOnlyCollection<PropertyInfo>>();
            foreach (var entityType in model.ConceptualModel.EntityTypes)
            {
                var type = Type.GetType(entityType.FullName);
                var typeProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                var mappedProperties = entityType.DeclaredProperties.Select(t => t.Name)
                    .Union(entityType.NavigationProperties.Select(t => t.Name));
                mappedEntityTypes.Add(type, new ReadOnlyCollection<PropertyInfo>(
                    typeProperties.Where(t => !mappedProperties.Contains(t.Name)).ToList()));
            }
            _ignoredProperties = new ReadOnlyDictionary<Type, IReadOnlyCollection<PropertyInfo>>(mappedEntityTypes);
        }

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Customer> Customers { get; set; }
}

IgnoreProperties 属性是一个单例,将在您第一次使用上下文时被初始化。在此之前它将为空,因此必须确保在初始化之前没有任何东西使用它。它是只读的,因此您不必担心意外清除该集合。实体类型用作键,值公开一个包含被忽略属性的集合。使用示例:

var properties = CustomerContext.IgnoredProperties[typeof(Customer)];

缺点:

使用这种方法是 DbModel 将被构建两次,一次收集被忽略的属性,第二次由 EntityFramework 来缓存 DbCompiledModel 以供将来使用 ObjectContext 创造。它会对 DbContext 的冷启动产生影响,这意味着您将在第一次对上下文执行查询时,它会慢一些。这将取决于 DbContext 的大小。暖查询不应该受到影响。 OnModelCreating will be called once anyway.

优点:

DbModelBuilder 配置所做的所有更改都将自动反映在 IgnoredProperties 属性中。

【讨论】:

  • 我希望得到您的诚实意见。你认为利大于弊吗?我为您的努力 +1。
  • 这取决于应用程序的工作方式。如果它没有太多的停机时间,那么它值得付出代价,因为只有热身受到影响。另一方面,如果应用程序启动和停止真的很频繁,就像桌面应用程序一样,它不会是 IMO。我将更新我的答案以提供一些基准。顺便感谢您的支持。
  • 我暂时删除了基准,因为它们是错误的,没有调用 OnModelCreateing。
猜你喜欢
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多