EF 4.1 Отображение наследования в отношениях «многие ко многим» - PullRequest
3 голосов
/ 06 июня 2011

Непонятная ситуация У меня есть ситуация, когда у меня есть 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 представляют собой отдельные таблицы с FK между EmployeeInfo_Id и Employee_Id.

В нашей системе «менеджеры» будут добавлять сотрудников в систему с набором личной информации (больше свойств, чем указано выше), например, оплату, и добавлять их в команду.Другие области системы будут использовать объекты 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.

Пока я пробую текущие сопоставленияи я получаю неверный столбец с именем «Дискриминатор».Когда просто добавляете сотрудника в команду.

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

Кроме того, если я вычеркну многовариантное соотношение между командой и сотрудником, я получу исключение FK для Employee_Id для EmployeeInfo_Id.

Спасибо, JR.

1 Ответ

3 голосов
/ 11 июня 2011

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 таблицу с необходимыми ограничениями.

Также хорошо инициализировать ваши коллекции в конструкторах ваших объектов, чтобы исключить нулевое исключение. Например, в Team классе:

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, прочитайте эту замечательную статью .

...