实体框架6,许多外键

时间:2016-05-27 08:45:33

标签: entity-framework foreign-keys

我在这个问题上需要帮助,因为经过几个小时的调查后,我被困住了。

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

数据模型创建使用Fluent API创建了所有外键。但这不会有帮助,当我尝试从任何表格中选择数据时,我收到错误"无效的columna名称' 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})

事实上,每当我尝试获取数据时,我都会收到错误,例如&#34;无效的列名CABAJUSTES_CODAJUSTE&#34;和&#34;无效的列名CABAJUSTES_COMPANY&#34;。我无法映射第二个外键。

我该怎么办?

提前致谢。

1 个答案:

答案 0 :(得分:1)

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

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

首先是示例中的预期结构

  • 一个Company包含许多Article个和Invoice个。{}
  • 一个Invoice拥有许多InvoiceRow个。
  • 每个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 });
    }
}

最后生成的迁移

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

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如何用于映射实体。

祝你好运!