5

使用 EF CTP5 Code-First,我试图映射一个类模型,该模型包含一个类中的多个集合,指向另一个类。这是我的意思的一个例子:

public class Company
{
    public int CompanyId { get; set; }
    public IList<Person> FemaleEmployees { get; set; }
    public IList<Person> MaleEmployees { get; set; }
}

public class Person
{
    public int PersonId { get; set; }
    public Company Company { get; set; }
}

如果我让数据库从此模型创建DbContext而无需进一步定制,如下所示:

public class MyContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Person> People { get; set; }
}

...然后我在 SQL Server 中得到两个表,一个Companies只有一CompanyId列的简单表和一个People包含以下列的表(“FKRN”表示“外键关系名称”,由 EF 在 SQL Server 中创建):

PersonId            int     not nullable
CompanyCompanyId    int     nullable       FKRN: Company_FemaleEmployees
CompanyCompanyId1   int     nullable       FKRN: Company_MaleEmployees
CompanyCompanyId2   int     nullable       FKRN: Person_Company

CompanyId最后三列与表的主键都有外键关系Companies

现在我有几个问题:

  • 1)为什么我在表中得到三个外键列People?我实际上期望两个。如果我public Company Company { get; set; }Person第三列中删除属性CompanyCompanyId2会消失,但我也会丢失类中的引用属性。

  • 2)假设我Company从表中删除了属性Person(我的模型中并不需要它)。有没有办法给剩下的两个外键列另一个名称而不是自动创建的CompanyCompanyIdand CompanyCompanyId1?(例如FCompanyIdandMCompanyId表示与FemaleEmployeesMaleEmployees集合的关系。)

  • 3) 有没有办法用表CompanyId中的一个外键来定义这个模型People?当然,我需要在Person类中添加一个与众不同的列(如bool IsFemale)。Person 要么是集合的一部分,要么FemaleEmployeesMaleEmployees集合的一部分,从不在两者中(在这个例子中很自然),所以使用 SQL 我可以通过类似WHERE IsFemale = true/false AND CompanyId = 1. 我想知道是否可以给 EntityFramework 提示以这种方式加载两个集合。(在这里我想避免通过一个FemalePersonMalePerson类来扩展模型,这两个类都派生自Person作为基类,然后使用例如 Table-Per-Hierarchy 映射,因为这些派生类将是空的和人为的,除了启用到 SQL Server 的映射之外没有其他目的。)只有一个外键可以让CompanyId我做到non-nullable使用两个外键是不可能的(在同一行中两者都不能是非空的)。

提前感谢您的反馈和建议!

4

2 回答 2

3
  • 问题(1):EF 不能同时将Company类中的单个引用属性映射Person到两个不同的集合端点FemaleEmployeesMaleEmployeesCompany中。映射约定假定实际上存在第三个端点,Company该端点未在模型中公开。因此,创建了第三个外键。

  • 问题 (2):使用EF 4.1 Release CandidateMap ,现在可以通过使用类的方法在 Fluent API 中指定外键的数据库列名称(这在 EF CTP5 中是不可能的)ForeignKeyNavigationPropertyConfiguration

    modelBuilder.Entity<Company>()
                .HasMany(c => c.FemaleEmployees)
                .WithOptional()
                .Map(conf => conf.MapKey("FCompanyId"))
                .WillCascadeOnDelete(false);
    
    modelBuilder.Entity<Company>()
                .HasMany(c => c.MaleEmployees)
                .WithOptional()
                .Map(conf => conf.MapKey("MCompanyId"))
                .WillCascadeOnDelete(false);
    
  • 对问题(3):我仍然不知道。

编辑

只是现在关闭这个老问题:(3)(将一个实体中的两个导航属性与另一个实体的同一端点相关联)是不可能的,例如:Specific Entity Framework Code First Many to 2 Model Mapping ...(和我记住许多其他问题,这些问题正在为这种情况寻找解决方案但没有成功)

于 2011-03-16T18:43:48.987 回答
2

我认为你可以这样做:

public class Company
{
    public int CompanyId { get; set; }
    public ICollection<Person> Employees { get; set; }
    public IEnumerable<Person> MaleEmployees {
        get
        {
            Employees.Where(x=> !x.IsFemale);
        }
    }
}

public class Person
{
    public int PersonId { get; set; }
    public Company Company { get; set; }
}

您在 People 表中只有一个 CompanyID FK。

您可以使用 EF 上下文加载男性员工:

context.Entry(companyInstance)
    .Collection(p => p.Employees)
    .Query()
    .Where(u => !u.IsFemale)
    .Load();

我认为您的方法不太好,因为当我将男性添加到 Company.FemaleEmployees 时会发生什么?EF不知道这个规则

于 2011-02-23T12:03:19.833 回答