6

如果这个问题已经在某个地方得到回答,请原谅我,我一直很难找到解决这个问题的方法。

我正在尝试在 MVC4 项目上设置 EF Code First。我有一个从 Person 继承的 User 和 Customer。然后我有一个模板对象,它与客户具有多对多关系,与用户具有一对多关系。这是我的设置方式:

楷模

public class Person
{
    [Key]
    public int PersonID { get; set; }

    public string LastName { get; set; }
    public string FirstName { get; set; }

    public string FullName
    {
        get
        {
            return String.Format("{0} {1}", FirstName, LastName);
        }
    }

    public string Email { get; set; }

    public virtual List<Template> Templates { get; set; }
}

public class User : Person
{
    .... 
}

public class Customer : Person
{
    ....
}

public class Template
{
    public int TemplateId { get; set; }
    public string TemplateName { get; set; }

    public virtual List<Customer> Customers { get; set; }

    [ForeignKey("User")]
    public int UserId { get; set; }
    public virtual User User { get; set; }
}

语境

public class ProjectContext : DbContext
{
    public ProjectContext()
        : base("name=ProjectDB")
    {
    }

    public DbSet<Template> Templates { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions
            .Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<Template>()
            .HasMany(x => x.Customers)
            .WithMany(x => x.Templates)
            .Map(x => x.MapLeftKey("TemplateId")
                .MapRightKey("PersonId")
                .ToTable("TemplateCustomer")
            );
    }
}

如果我将 Person DBSet 从上下文中删除,这可以正常工作,但会设置 TPT 继承。我想使用 TPH 继承,但是当我在上下文中使用 Person DBSet 启用迁移时,它会阻塞:

NavigationProperty“模板”无效。AssociationType 'MvcProject.Models.Template_Customers' 中 FromRole 'Template_Customers_Target' 的类型 'MvcProject.Models.Customer' 必须与声明此 NavigationProperty 的类型 'MvcProject.Models.Person' 完全匹配。

我在哪里错了?

4

2 回答 2

14

您不能从基础实体继承导航属性。它们总是必须在关系的另一端所引用的类中声明。

  • Template.Customers是指Customer(而不是Person),因此反向导航属性Templates必须在Customer(而不是Person)中声明
  • Template.User是指User(而不是Person),因此反向导航属性Templates必须在User(而不是Person)中声明

因此,基本上您必须将Templates集合从Person两个派生类中移出:

public class Person
{
    // no Templates collection here
}

public class User : Person
{
    //... 
    public virtual List<Template> Templates { get; set; }
}

public class Customer : Person
{
    //...
    public virtual List<Template> Templates { get; set; }
}

然后你可以像这样使用 Fluent API 定义这两种关系:

modelBuilder.Entity<Template>()
    .HasMany(t => t.Customers)
    .WithMany(c => c.Templates) // = Customer.Templates
    .Map(x => x.MapLeftKey("TemplateId")
               .MapRightKey("PersonId")
               .ToTable("TemplateCustomer"));

modelBuilder.Entity<Template>()
    .HasRequired(t => t.User)
    .WithMany(u => u.Templates) // = User.Templates
    .HasForeignKey(t => t.UserId);
于 2013-03-27T20:21:42.637 回答
0

将您的 HasMany 选择器更改为 People:

    modelBuilder.Entity<Template>()
        .HasMany(x => x.People) // here
        .WithMany(x => x.Templates)
        .Map(x => x.MapLeftKey("TemplateId")
            .MapRightKey("PersonId")
            .ToTable("TemplateCustomer")
        );
于 2013-03-27T17:15:15.163 回答