实体框架

时间:2017-03-07 21:04:28

标签: c# entity-framework ef-fluent-api

我正在尝试首先在Entity Framework代码中创建具有相同类型关系的公司的数据模型。我想单向创建关系,所以当一家公司将另一家公司作为其客户时,另一家公司不会自动将该公司作为供应商。

public class Company {
    [Key]
    public string Id { set; get; }
    public string Name { set; get; }

    public virtual ICollection<Company> Customers { set; get; }
    public virtual ICollection<Company> Suppliers { set; get; }
}

当我像这样更新数据库时,我最终得到一个名为“CompanyCompanies”的连接表。

公司

| Company_Id | Company_Id1 |
|------------|-------------|
| 1234       | 1234        |

我想创建两个表来连接这些值,如下所示:

CompanyCustomers

| Company_Id | Customer_Id |
|------------|-------------|
| 1234       | 1234        |

CompanySuppliers

| Company_Id | Supplier_Id |
|------------|-------------|
| 1234       | 1234        |

我看了很多流利的api并试图定义那里的关系,但我似乎无法理解如何做到这一点。我发现了很多使用不同实体的例子,但只有this answer与自身有关系。但是,当我从该问题实现解决方案并更新数据库时,我收到一条错误消息,指出连接已超时。

modelBuilder.Entity<Company>()
    .HasMany(c => c.Customers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanyCustomer");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("CustomerId");
    });
  

错误号:-2,状态:0,类:11   执行超时已到期。
  操作完成之前经过的超时时间或服务器没有响应。

当我尝试使用CompanyCustomer和CompanySupplier时,我得到了antoher错误

  

参数@objname不明确或声称@objtype(COLUMN)错误。

我还尝试为关系创建一个新对象,并让Company对象包含CompanyCustomers列表,但是当我用这个更新数据库时,我得到了一个包含三列的连接表。

public class CompanyCustomer
{
    [Key, Column(Order = 0)]
    [ForeignKey("Company")]
    public string CompanyId { set; get; }
    [Key, Column(Order = 1)]
    [ForeignKey("Customer")]
    public string CustomerId { set; get; }

    public virtual Company Company { set; get; }
    public virtual Company Customer { set; get; }
}

CompanyCustomer

| CompanyId | CustomerID | Company_Id |
|-----------|------------|------------|
| 1234      | 1234       | 1234       |

我不明白我如何在同一个实体之间建立几种关系类型。我可以在流畅的api的帮助下完成这项工作,还是必须重新设计我的模型?

2 个答案:

答案 0 :(得分:2)

流畅的配置

modelBuilder.Entity<Company>()
    .HasMany(c => c.Customers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanyCustomer");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("CustomerId");
    });

确实是配置第一个关系的正确方法。你需要为第二个做类似的事情:

modelBuilder.Entity<Company>()
    .HasMany(c => c.Suppliers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanySupplier");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("SupplierId");
    });

在我干净的EF测试环境中(如果重要的话,最新的EF6.1.3)产生以下迁移:

CreateTable(
    "dbo.Company",
    c => new
        {
            Id = c.String(nullable: false, maxLength: 128),
            Name = c.String(),
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.CompanyCustomer",
    c => new
        {
            CompanyId = c.String(nullable: false, maxLength: 128),
            CustomerId = c.String(nullable: false, maxLength: 128),
        })
    .PrimaryKey(t => new { t.CompanyId, t.CustomerId })
    .ForeignKey("dbo.Company", t => t.CompanyId)
    .ForeignKey("dbo.Company", t => t.CustomerId)
    .Index(t => t.CompanyId)
    .Index(t => t.CustomerId);

CreateTable(
    "dbo.CompanySupplier",
    c => new
        {
            CompanyId = c.String(nullable: false, maxLength: 128),
            SupplierId = c.String(nullable: false, maxLength: 128),
        })
    .PrimaryKey(t => new { t.CompanyId, t.SupplierId })
    .ForeignKey("dbo.Company", t => t.CompanyId)
    .ForeignKey("dbo.Company", t => t.SupplierId)
    .Index(t => t.CompanyId)
    .Index(t => t.SupplierId);

这正是你想要的。

您获得的例外情况如何,它们可能与您使用数据库的实验有关。确保要么从干净的数据库开始,要么删除Company实体(如果它存在的话CompanyCustomer) ,相应的DbSet和流畅的配置,更新数据库以清理上一个混乱,然后再试一次。

答案 1 :(得分:0)

您只需使用属性即可。您的问题是您在错误的属性上使用[ForeignKey]属性 - 它应该在导航属性上。

[ForeignKey(nameof(CompanyId))]
public virtual Company Company { set; get; }

[ForeignKey(nameof(CustomerId))]
public virtual Company Customer { set; get; }

此外,您可以将[InverseProperty]属性添加到模型上的集合中。这有助于理解关系导航。

[InverseProperty(nameof(CompanyCustomer.Company))]
public virtual ICollection<Company> Customers { set; get; }