【问题标题】:Entity Framework 6 with POCO Using Only Some Classes带有 POCO 的实体框架 6 仅使用某些类
【发布时间】:2016-05-11 20:26:57
【问题描述】:

我在另一个 VS 项目中使用了多个相互关联的类,例如:

namespace MyOtherProject
{
    public class A {
        public string Name {get;set;}
    }

    public class B {
        public int Value {get;set;}
        public A Child {get;set;}
    }
}

现在我想在 EF 中首先将这些类用作代码的 POCO。但是我不需要数据库中的所有类,而只需要其中的一些。所以我创建了一个上下文:

public class MyContext : DbContext
{
    public MyContext () : base("MyContext ")
    {
    }

    public DbSet<B> Bs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

当我尝试运行该项目时,出现此错误:

System.Data.Entity.ModelConfiguration.ModelValidationException:一或 在模型生成过程中检测到更多的验证错误: MyProject.A:名称:模式中的每个类型名称都必须是唯一的。类型 名称“A”已定义。

请注意,错误中的命名空间与A类的定义不同,因为我的A类是在另一个(共享)项目中定义的。相反,命名空间是上下文之一。

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application 我读到这个:

您可以省略 DbSet 和 DbSet 声明,它的工作原理是一样的。实体框架将 隐式包含它们,因为 Student 实体引用了 注册实体和注册实体引用课程 实体。

我的假设(未证实)是 EF 看到 B 引用了 A,但没有 A 类型的数据集,所以它在内部生成了一个 A 类,然后突然发现有两个这样的类。

任何人都知道确切的问题是什么以及我可以做些什么来解决它?我有太多不需要的类,所以我不想为我拥有的每个类创建数据集。

【问题讨论】:

  • Database.SetInitializer(new CreateDatabaseIfNotExists());您可以在上下文构造函数中添加上述代码并检查
  • 有时这个问题与您的 DB_migration 相关
  • 数据库已经存在,无法创建。
  • 如果你有数据库已经存在,你可以使用 DropCreateDatabaseAlways 选项如果创建了新的数据库那么我们可以理解问题是在迁移中
  • 你可以使用上下迁移的方法来解决你的问题..!

标签: c# entity-framework-6


【解决方案1】:

首先,从DbSet&lt;Type1&gt; 获取所有泛型类型参数(Type1Type2...)。然后,您应该检查每种类型的内部属性类型,即对其他类型的引用(作为直接链接或通过ICollection 设置), - 如果此内部类型最初不存在 tablesTypes 设置我们会忽略它们。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {         
        //other stuff.....

        Func<Type, bool> genericFilter = x => typeof(IEnumerable).IsAssignableFrom(x) && x.GenericTypeArguments.Length == 1;

        //All types of your context tables
        var tablesTypes = GetType().GetProperties()
            .Where(x => genericFilter(x.PropertyType))
            .Select(x => x.PropertyType.GenericTypeArguments.First());

        var namespaces2ignore = new List<string> { "Namespace2Ignore1", "Namespace2Ignore2" };
        var toIgnore = new List<Type>();
        foreach (var type in tablesTypes)
            //Ignore internal types, which not exist at tablesTypes
            toIgnore.AddRange(type.GetProperties()
                .Select(x => genericFilter(x.PropertyType) ? x.PropertyType.GenericTypeArguments.First() : x.PropertyType)
                .Where(x => !tablesTypes.Contains(x) && namespaces2ignore.Contains(x.Namespace)
                /*or as you suggested: && typeof(A).Assembly == x.Assembly*/
            ).ToList());            

        modelBuilder.Ignore(toIgnore);
    }

如果您想在特定对类型属性上添加条件,您可以执行以下操作:

    foreach (var type in tablesTypes)
        foreach(var prop in type.GetProperties()
            .Select(x => new { type = genericFilter(x.PropertyType) ? x.PropertyType.GenericTypeArguments.First() : x.PropertyType, prop = x })
            .Where(x => !tablesTypes.Contains(x.type) && namespaces2ignore.Contains(x.type.Namespace)                
        ).ToList())
            if(!(type == typeof(TestType) && prop.prop.Name == "Test"))
                toIgnore.Add(prop.type);

现在不会排除名称为“Test”、类型为 TestType 的属性。

【讨论】:

  • 这不会也删除字符串、int 等简单类型的任何属性吗?所以也许我还必须检查属性的类型是否在我的程序集中,类型不正确,但这很容易添加。
  • 是的,很好的评论。在这种情况下,您可以检查 - 是在特定程序集中声明的当前类型,还是属于某些命名空间列表(如我的更正答案所示)
  • 有没有办法忽略属性而不是类型?基于他们的 PropertyInfo
  • 为什么不呢?您可以添加新过滤器,如我修改后的答案所示。
  • 使用您的建议和来自stackoverflow.com/questions/31066906/… 的一些提示,我成功修复了它。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2014-03-02
  • 2015-12-26
  • 2016-01-28
  • 2014-01-30
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多