【问题标题】:Entity framework 6, same column for many foreign keys实体框架 6,许多外键的同一列
【发布时间】:2016-05-27 08:45:32
【问题描述】:

我需要有关此问题的帮助,因为经过数小时的调查后,我陷入了困境。

我使用 Entity Framework 6 从现有的旧数据库创建了一个数据模型(我使用的是 Code First 方法)。这个数据库是面向多公司的,所以它的大部分表都有一个“公司”列,它被用作几乎所有主键和外键的一部分。

数据模型创建使用 Fluent API 创建了所有外键。但这没有帮助,当我尝试从任何表中选择数据时,我收到错误“invalid columna name 'TABLE_COLUMN'。因为在这个数据库中,通常每个表中的列都有不同的名称,并且实体框架无法确定关系,因此需要映射列名。

所以,我可以使用 DataAnnotations 解决问题,例如:

        [Key]
    [Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [ForeignKey("BLOQHOR"), InverseProperty("CODHOR")]
    public int NUMHOR { get; set; }

    [Key]
    [Column(Order = 2)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [ForeignKey("BLOQHOR"), InverseProperty("DISTAINIC")]
    public int DISTAINIC { get; set; }

    [Key]
    [Column(Order = 3)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [ForeignKey("BLOQHOR"), InverseProperty("COMPANY")]
    public int COMPANY{ get; set; }

现在发生了什么?

该表还有另一个外键,它也需要 COMPANY 列。因为数据注释不允许我使用该列两次,所以我无法使该表正常工作。

我再说一遍,在数据模型中,它为第二个外键创建了一个流畅的 api 定义,但它不起作用。

            modelBuilder.Entity<CABAJUSTES>()
            .HasMany(e => e.AJUSBLOQ)
            .WithRequired(e => e.CABAJUSTES)
            .HasForeignKey(e => new { e.NUMAJUST, e.COMPANY})

事实上,每次我尝试获取数据时,都会收到诸如“无效的列名 CABAJUSTES_CODAJUSTE”和“无效的列名 CABAJUSTES_COMPANY”之类的错误。而且我无法映射第二个外键。

我能做什么?

提前致谢。

【问题讨论】:

    标签: entity-framework foreign-keys


    【解决方案1】:

    遵循您的表格结构有点困难,因此我尝试使用一些任何人都应该能够遵循的常见实体来设置一个全面的示例。如果这不能完全描述您的问题,请发表评论。

    注意故意使用了非常糟糕的外键来确保实体框架中的帮助自动映射对我没有帮助,并表明这适用于您可能拥有的任何遗留数据库设计。

    首先是示例中的预期结构

    • 一个Company 拥有许多Articles 和许多Invoices。
    • 一个Invoice 拥有多个InvoiceRows。
    • 每个InvoiceRow 都可以选择引用Article

    实际的实体

    class Company
    {
        public int TheCompanyKey { get; set; }
    
        public virtual ICollection<Invoice> Its_Invoices { get; set; }
        public virtual ICollection<Article> Its_Articles { get; set; }
    }
    
    class Invoice
    {
        public int Its_CompanyKey { get; set; }
        public int TheInvoiceKey { get; set; }
    
        public string InvoiceNumber { get; set; }
        public DateTime InvoiceDate { get; set; }
    
        public virtual Company Its_Company { get; set; }
        public virtual ICollection<InvoiceRow> Its_Rows { get; set; }
    }
    
    class InvoiceRow
    {
        public int Rows_Company_Key { get; set; }
        public int Its_InvoiceID { get; set; }
        public int RowNumber { get; set; }
    
        public int? Its_Articles_ID { get; set; }
        public string Text { get; set; }
        public double Price { get; set; }
    
        public virtual Invoice Its_Invoice { get; set; }
        public virtual Article Its_Article { get; set; }
    }
    
    class Article
    {
        public int TheArticleCompany_Key { get; set; }
        public int TheArticleKey { get; set; }
    
        public string ArticleNumber { get; set; }
        public double Cost { get; set; }
        public double TargetPrice { get; set; }
    
        public virtual Company Its_Company { get; set; }
    }
    

    带有 OnModelCreating() 的 DbContext

    有多种方法可以生成所需的结构,具体取决于您认为是自上而下还是自下而上。我对建模的看法是从基表开始,然后描述孩子与它们的关系。

    class MyContext : DbContext
    {
        public MyContext() : base("name=MyContext")
        {
        }
    
        public virtual IDbSet<Company> Companies { get; set; }
        public virtual IDbSet<Invoice> Invoices { get; set; }
        public virtual IDbSet<InvoiceRow> InvoiceRows { get; set;}
        public virtual IDbSet<Article> Articles { get; set; }
    
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<Company>()
                .HasKey(e => e.TheCompanyKey);
    
            modelBuilder.Entity<Article>()
                .HasKey(e => new { e.TheArticleCompany_Key, e.TheArticleKey })
                .HasRequired(e => e.Its_Company).WithMany(e => e.Its_Articles).HasForeignKey(e => e.TheArticleCompany_Key);
    
            modelBuilder.Entity<Invoice>()
                .HasKey(e => new { e.Its_CompanyKey, e.TheInvoiceKey })
                .HasRequired(e => e.Its_Company).WithMany(e => e.Its_Invoices).HasForeignKey(e => e.Its_CompanyKey);
    
            modelBuilder.Entity<InvoiceRow>()
                .HasKey(e => new { e.Rows_Company_Key, e.Its_InvoiceID, e.RowNumber });
    
            modelBuilder.Entity<InvoiceRow>()
                .HasRequired(e => e.Its_Invoice).WithMany(e => e.Its_Rows)
                .HasForeignKey(e => new { e.Rows_Company_Key, e.Its_InvoiceID }).WillCascadeOnDelete();
    
            modelBuilder.Entity<InvoiceRow>()
                .HasOptional(e => e.Its_Article)
                .WithMany()
                .HasForeignKey(e => new { e.Rows_Company_Key, e.Its_Articles_ID });
        }
    }
    

    终于生成的迁移

    Package Manager Console 窗口中运行add-migration multikeys 会导致以下迁移:

    public partial class multikeys : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Articles",
                c => new
                    {
                        TheArticleCompany_Key = c.Int(nullable: false),
                        TheArticleKey = c.Int(nullable: false),
                        ArticleNumber = c.String(),
                        Cost = c.Double(nullable: false),
                        TargetPrice = c.Double(nullable: false),
                    })
                .PrimaryKey(t => new { t.TheArticleCompany_Key, t.TheArticleKey })
                .ForeignKey("dbo.Companies", t => t.TheArticleCompany_Key, cascadeDelete: true)
                .Index(t => t.TheArticleCompany_Key);
    
            CreateTable(
                "dbo.Companies",
                c => new
                    {
                        TheCompanyKey = c.Int(nullable: false, identity: true),
                    })
                .PrimaryKey(t => t.TheCompanyKey);
    
            CreateTable(
                "dbo.Invoices",
                c => new
                    {
                        Its_CompanyKey = c.Int(nullable: false),
                        TheInvoiceKey = c.Int(nullable: false),
                        InvoiceNumber = c.String(),
                        InvoiceDate = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => new { t.Its_CompanyKey, t.TheInvoiceKey })
                .ForeignKey("dbo.Companies", t => t.Its_CompanyKey, cascadeDelete: true)
                .Index(t => t.Its_CompanyKey);
    
            CreateTable(
                "dbo.InvoiceRows",
                c => new
                    {
                        Rows_Company_Key = c.Int(nullable: false),
                        Its_InvoiceID = c.Int(nullable: false),
                        RowNumber = c.Int(nullable: false),
                        Its_Articles_ID = c.Int(),
                        Text = c.String(),
                        Price = c.Double(nullable: false),
                    })
                .PrimaryKey(t => new { t.Rows_Company_Key, t.Its_InvoiceID, t.RowNumber })
                .ForeignKey("dbo.Articles", t => new { t.Rows_Company_Key, t.Its_Articles_ID })
                .ForeignKey("dbo.Invoices", t => new { t.Rows_Company_Key, t.Its_InvoiceID }, cascadeDelete: true)
                .Index(t => new { t.Rows_Company_Key, t.Its_Articles_ID })
                .Index(t => new { t.Rows_Company_Key, t.Its_InvoiceID });
    
        }
    
        public override void Down()
        {
            DropForeignKey("dbo.Articles", "TheArticleCompany_Key", "dbo.Companies");
            DropForeignKey("dbo.InvoiceRows", new[] { "Rows_Company_Key", "Its_InvoiceID" }, "dbo.Invoices");
            DropForeignKey("dbo.InvoiceRows", new[] { "Rows_Company_Key", "Its_Articles_ID" }, "dbo.Articles");
            DropForeignKey("dbo.Invoices", "Its_CompanyKey", "dbo.Companies");
            DropIndex("dbo.InvoiceRows", new[] { "Rows_Company_Key", "Its_InvoiceID" });
            DropIndex("dbo.InvoiceRows", new[] { "Rows_Company_Key", "Its_Articles_ID" });
            DropIndex("dbo.Invoices", new[] { "Its_CompanyKey" });
            DropIndex("dbo.Articles", new[] { "TheArticleCompany_Key" });
            DropTable("dbo.InvoiceRows");
            DropTable("dbo.Invoices");
            DropTable("dbo.Companies");
            DropTable("dbo.Articles");
        }
    }
    

    总结

    我相信这描述了 OP 问题,并且通过一些研究可以很好地理解如何使用 Fluent 来映射实体。

    祝你好运!

    【讨论】:

    • 感谢您的帮助。最后我注意到这个问题正在发生,因为我有 2 个具有 fluent API 的不同文件,并且我正在对不正确的文件进行更改。注意到这一点后,我能够正确配置外键,您的示例也有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2019-02-23
    • 2022-08-21
    • 2023-03-06
    相关资源
    最近更新 更多