Entity Framework - Проблема дискриминатора с TPH - PullRequest
1 голос
/ 28 апреля 2011

Я получаю Invalid column name 'Discriminator' при сохранении записи.(Code First, EF4.1)

У меня есть сущность, которую я хочу отслеживать через EF:

public class Audit
 public virtual string p1
 public virtual string p2

У меня есть специализация UserAudit, которая не добавляет новых виртуальных свойств, она просто устанавливаетбаза готова для аудита

public class UserAudit : Audit
 public UserAudit() { p1 = someval; }

И конфиг:

public class AuditConfiguration : EntityTypeConfiguration<Audit>
  {
    public AuditConfiguration()
    {
      ToTable("_AUDIT");
      HasKey(c => c.Id);
      Property(c => c.Id).HasColumnName("AUDIT_ID");
    }
  }

И репозиторий:

public class AuditRepository : IAuditRepository
  {
    public void LogAudit(Audit audit)
    {
      using (var db = new AuditContext())
      {
        db.Audits.Add(audit);
        db.SaveChanges();
      }
    }
  }

Что мне нужно сделать, чтобы сказать EFигнорировать / обрабатывать специализацию правильно, когда я repo.LogAudit( userAudit );?

Ответы [ 3 ]

5 голосов
/ 28 апреля 2011

Из сообщения об исключении Invalid column name 'Discriminator' Я бы пришел к выводу, что вы не позволили EF 4.1 создать таблицу базы данных _AUDIT, потому что в противном случае EF создал бы столбец с именем Discriminator для таблицы.Возможно, у вас есть таблица базы данных без такого столбца.Когда EF пытается сохранить объект, он хочет сохранить значение, представляющее конкретный тип, который вы сохраняете, в столбце дискриминатора - но этот столбец не существует.Отсюда и исключение.

Редактировать

Итак, вам нужен столбец дискриминатора.Вы можете определить свой собственный пользовательский столбец дискриминатора следующим образом:

public class AuditConfiguration : EntityTypeConfiguration<Audit>
{
    public AuditConfiguration()
    {
        ToTable("_AUDIT");
        HasKey(c => c.Id);
        Property(c => c.Id).HasColumnName("AUDIT_ID");

        Map<Audit>(m => m.Requires("Type").HasValue<byte>(0).IsRequired());
        Map<UserAudit>(m => m.Requires("Type").HasValue<byte>(1).IsRequired());
    }
}

При этом будет использоваться необнуляемый tinyint столбец Type в таблице _AUDIT, значение которой 0 для base Audit введите объекты и значение 1 для производных объектов типа UserAudit.

1 голос
/ 26 июня 2011

В моем случае не-EF-модель наследовала от EF-модели. Вместо наследования я скопировал все свойства в модель без EF, и это было для меня решением.

public class ApplicationContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
}

public class Person
{
    public int PersonId { get; set; }
    public string Name { get; set; }
}

До:

public class PersonWithExtraInfo:Person
{
    public string ExtraInfo { get; set; }
}

После того, как:

public class PersonWithExtraInfo
{
    public int PersonId { get; set; }
    public string Name { get; set; }
    public string ExtraInfo { get; set; }
}
1 голос
/ 28 апреля 2011

@ Слаума абсолютно прав, и вы должны использовать его решение.Я просто добавляю объяснение, почему это происходит.

Наследование в сущностях должно моделироваться в базе данных, потому что, когда вы загружаете сущность из базы данных, EF должна знать, материализуется ли она Audit или UserAudit экземпляром.По умолчанию EF использует что-то под названием наследование таблиц на иерархию, где базовый тип и все подтипы хранятся в одной таблице.Для поддержки такого сценария EF ожидает дополнительный столбец в таблице, вызываемый по умолчанию Discriminator.Этот столбец будет использоваться для различения хранимого экземпляра - по умолчанию он включает имена типов.

...