令人困惑的情况 我有一种情况,我有2个实体,其中1个继承自另一个,需要映射到2个单独的表,但代码使用应该围绕2个实体的基础。
详情
public class Team
{
public virtual int Id { get; set; }
public virtual ICollection<Employee> Members { get; set; }
}
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Team> Teams { get; set; }
}
public class EmployeeInfo : Employee
{
public virtual int Id { get; set; }
public virtual decimal Amount { get; set; }
}
我们有一个现有的数据库模式,其中Employee和EmployeeInfo是单独的表,在EmployeeInfo_Id和Employee_Id之间有一个FK。
在我们的系统中,“管理员”将向系统添加员工,其中包含一组私人信息(比上面列出的更多属性),如薪水,并将其添加到团队。系统的其他区域将使用Team或Employee对象进行各种其他操作。如果可以完成映射,我们希望编写超级简单的代码。
当经理创建新员工时,我们希望代码看起来像这样:
public void Foo(string name, decimal pay)
{
// create the employee
var employee = new EmployeeInfo();
employee.Name = name;
employee.Pay = pay;
// add him/her to the team
_team.Employees.Add(employee); // the idea being that consumers of the Team entity would not get the separate employee info properties
// save the context
_context.SaveChanges();
}
最终结果是EmployeeInfo表中输入的EmployeeInfo属性和基本Employee数据被输入到Employee表中,并通过关联表TeamEmployees添加到Team。
到目前为止,我正在尝试当前的映射,并且我得到一个名为“Discriminator”的无效列。仅将员工添加到团队时。
public class TeamConfiguration : EntityTypeConfiguration<Team>
{
public TeamConfiguration()
{
ToTable("Team");
HasKey(t => t.Id);
HasMany(t => t.Members).WithMany(m => m.Teams)
.Map(m =>
{
m.MapLeftKey("Team_Id");
m.MapRightKey("Employee_Id");
m.ToTable("TeamEmployees");
});
}
}
public class EmployeeConfiguration : EntityTypeConfiguration<Employee>
{
public EmployeeConfiguration()
{
ToTable("Employee");
ToTable("EmployeeInfo");
HasKey(t => t.Id);
Property(p => p.Name);
HasMany(m => m.Teams)
.WithMany(t => t.Members)
.Map(m =>
{
m.MapLeftKey("Employee_Id");
m.MapRightKey("Team_Id");
m.ToTable("TeamEmployees");
});
}
}
另外,如果我从团队和员工之间取得多对多的结果,我会在Employee_Id上找到一个FK例外的EmployeeInfo_Id。
谢谢,JR。
答案 0 :(得分:3)
Discriminator
是使用Table Per Hierarchy
方法时添加到表格中的列。
我认为你所寻找的是“每种类型的表(TPT)”。按如下方式装饰您的EmployeeInfo
课程:
[Table("EmployeeInfo")]
public class EmployeeInfo : Employee
或在下面添加OnModelCreating
事件:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<EmployeeInfo>().ToTable("EmployeeInfo");
...
}
或者,创建以下类,并在modelBuilder.Configurations.Add(new EmployeeInfoConfiguration());
方法中使用它OnModelCreating
:
public class EmployeeInfoConfiguration : EntityTypeConfiguration<EmployeeInfo>
{
public EmployeeInfoConfiguration()
{
ToTable("EmployeeInfo");
}
}
这将导致EF创建具有必要约束的EmployeeInfo
表。
此外,最好在对象的构造函数中初始化集合以防止出现null异常。例如,在Team
class:
public Team()
{
this.Employees = new HashSet<Employee>();
}
我完全复制了您的代码,并更改了以下部分:
public class Team
{
public Team()
{
this.Members = new HashSet<Employee>();
}
public virtual int Id { get; set; }
public virtual ICollection<Employee> Members { get; set; }
}
public class Employee
{
public Employee()
{
this.Teams = new HashSet<Team>();
}
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Team> Teams { get; set; }
}
[Table("EmployeeInfo")]
public class EmployeeInfo : Employee
{
public virtual int Id { get; set; }
public virtual decimal Amount { get; set; }
}
在DbContext中,没有变化:
public partial class TestEntities : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<EmployeeInfo> Employee_Info { get; set; }
public DbSet<Team> Teams { get; set; }
}
以及您正在使用的Foo
方法:
public static void Foo(string name, decimal pay)
{
var _team = new Team();
var context = new TestEntities();
context.Teams.Add(_team);
// create the employee
var employee = new EmployeeInfo();
employee.Name = name;
employee.Amount = pay;
context.Employees.Add(employee);
context.SaveChanges();
// add him/her to the team
_team.Members.Add(employee);
// save the context
context.SaveChanges();
}
最后,从ToTable("EmployeeInfo");
移除EmployeeConfiguration
部分,因为您已在模式创建活动中正确提及此内容。
有关Table Per Type方法的更多信息,请查看this great article。