实体框架 CTP5 代码优先:将一个类与另一个类的多个集合映射

发布于 2024-10-18 04:49:22 字数 2370 浏览 3 评论 0原文

使用 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 中得到两个表,一个简单的 <仅包含 CompanyId 列的 code>Companies 表和包含以下列的 People 表(“FKRN”表示“外键关系名称”,由SQL Server 中的 EF):

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

最后三列与 Companies 表的主键 CompanyId 均具有外键关系。

现在我有几个问题:

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

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

  • 3 ) 有没有办法在 People 表中仅使用一个外键 CompanyId 来定义此模型?当然,我需要在 Person 类中添加一个区分的附加列(例如 bool IsFemale)。 Person 要么是 FemaleEmployees 的一部分,要么是 MaleEmployees 集合的一部分,绝不会同时存在于两者中(在本例中自然如此),因此使用 SQL,我可以通过类似 的方式获取这些集合>WHERE IsFemale = true/false AND CompanyId = 1。我想知道是否可以给 EntityFramework 一个提示,以这种方式加载两个集合。 (在这里,我想避免通过 FemalePersonMalePerson 类来扩展模型,它们都从 Person 派生为基类,然后用于实例每层次结构表映射,因为这些派生类是空的、人为的,除了启用到 SQL Server 的映射之外没有其他用途。)只有一个外键 CompanyId 就可以让我做到这一点non-nullable 这对于两个外键是不可能的(同一行中的两个外键永远不能为非空)。

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

With EF CTP5 Code-First I am trying to map a class model which contains multiple collections in one class pointing to another class. Here is an example of what I mean:

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; }
}

If I let the database create from this model with a DbContext without further customization, like so:

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

... then I get two tables in SQL Server, a simple Companies table with only a CompanyId column and a People table with the following columns ("FKRN" means "Foreign Key Relationship Name", as created by EF in SQL Server):

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

The last three columns have all a foreign key relationship to the primary key CompanyId of the Companies table.

Now I have several questions:

  • 1) Why do I get three foreign key columns in the People table? I actually expected two. If I remove the property public Company Company { get; set; } from the Person the third column CompanyCompanyId2 disappears but I also lose the reference property in the class.

  • 2) Let's say I drop the Company property from the Person table (I don't need it really in my model). Is there a way to give the two remaining foreign key columns another name than the auto-created CompanyCompanyId and CompanyCompanyId1? (For instance FCompanyId and MCompanyId to indicate the relation to the FemaleEmployees and MaleEmployees collections.)

  • 3) Is there any way to define this model with only one foreign key CompanyId in the People table? Surely I would need a differentiating additional column in the Person class (like bool IsFemale). A Person is either part of the FemaleEmployees or the MaleEmployees collection, never in both (naturally in this example), so with SQL I could fetch those collections by something like WHERE IsFemale = true/false AND CompanyId = 1. I am wondering if I could give EntityFramework a hint to load the two collections this way. (Here I would like to avoid to extend the model by a FemalePerson and MalePerson class which both derive from Person as base class and then use for instance Table-Per-Hierarchy mapping, since these derived classes would be empty and artificial and had no other purpose except enabling the mapping to SQL Server.) Having only one foreign key CompanyId would allow me to make it non-nullable which isn't possible with two foreign keys (both can never be non-null in the same row).

Thank you for feedback and suggestions in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

人疚 2024-10-25 04:49:22
  • 对于问题 (1):EF 无法将类 Person 中的单个引用属性 Company 映射到两个不同的集合端点 FemaleEmployeesMaleEmployees 同时位于 Company 类中。映射约定假设 Company 中实际上存在第三个端点,该端点未在模型中公开。因此,创建了第三个外键。

  • 对于问题 (2):使用 EF 4.1 候选版本 现在可以使用 在 Fluent API 中指定外键的数据库列名称(这在 EF CTP5 中是不可能的) ForeignKeyNavigationPropertyConfiguration 类的 Map 方法:

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

编辑

现在只是为了结束这个老问题:(3)(将一个实体中的两个导航属性与另一个实体的同一端点相关)是不可能的,例如:特定实体框架代码优先多对2模型映射 .. (我记得许多其他问题正在为这种情况寻找解决方案,但没有成功)

  • To question (1): EF cannot map the single reference property Company in class Person to two different collection endpoints FemaleEmployees and MaleEmployees in class Company at the same time. The mapping conventions assume that there is actually a third endpoint in Company which isn't exposed in the model. Therefore a third foreign key is created.

  • To question (2): With the EF 4.1 Release Candidate it is now possible to specify the database column name of foreign keys in the Fluent API (which wasn't possible with EF CTP5) by using the Map method of the ForeignKeyNavigationPropertyConfiguration class:

    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);
    
  • To question (3): I still have no idea.

Edit

Just to close this old question now: (3) (relating two navigation properties in one entity to the same endpoint of another entity) is not possible, for example: Specific Entity Framework Code First Many to 2 Model Mapping ... (and I remember many other questions which were looking for a solution for such a scenario without success)

回忆凄美了谁 2024-10-25 04:49:22

我认为你可以这样做:

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不知道这个规则

I think you could do this:

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; }
}

You just have one CompanyID FK at People table.

You can load Male Employees using EF context:

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

I think that your approach isn´t so good, because, what happens when I add a male to Company.FemaleEmployees? EF dont know this rules

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文