Entity Framework 4.1 RC: Code First EntityTypeConfiguration проблема наследования

Я пытаюсь использовать общий класс EntityTypeConfiguration для настройки первичного ключа для всех моих объектов, чтобы каждый производный класс конфигурации не повторялся. Все мои объекты реализуют общий интерфейс IEntity (который говорит, что каждый объект должен иметь свойство Id типа int).

Мой базовый класс конфигурации выглядит следующим образом:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>

    where TEntity : class , IEntity {

    public EntityConfiguration() {

        HasKey( e => e.Id );

        Property( e => e.Id ).HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );

    }

}

Каждый объект имеет собственный класс конфигурации, расширяющий его следующим образом:

public class CustomerConfiguration : EntityConfiguration<Customer> {

    public CustomerConfiguration() : base() {

        // Entity specific configuration here

    }

}

Он компилируется отлично, но проблема, с которой я столкнулась, заключается в том, что во время выполнения я получаю следующее исключение, возникающее, когда EF 4.1 RC пытается создать модель:

Исключение System.InvalidOperationException необработанное сообщение = ключевой компонент "Идентификатор" не является объявленным введите "Клиент". Убедитесь, что не были явно исключены из модели и что это действительный примитив имущество. Источник = EntityFramework

Если я изменю класс CustomerConfiguration для расширения от EntityTypeConfiguration <Customer> и повторите конфигурацию первичного ключа, тогда он отлично работает, но я теряю способность обмениваться общей конфигурацией (DRY - это мотивация).

  • Я делаю что-то не так здесь?
  • Есть ли другой способ совместного использования общей конфигурации между объектами?

Для справки относятся другие классы:

public interface IEntity {

    int Id { get; set; }

}

public class Customer : IEntity {

    public virtual int Id { get; set; }

    public virtual string name { get; set; }

}

Спасибо!

Ответ 1

Я не думаю, что вам нужно пройти все это. EF 4.1 Code First использует много условных конфигураций, и через это свойство Id определяется как первичный ключ. Поэтому, реализуя интерфейс IEntity на своих сущностях, вы устанавливаете их с идентификатором в качестве первичного ключа.

Вот ссылка на блог команды ADO.NET, в котором объясняется, как работает соглашение о первичных ключах. Соглашения для первого кода

Ответ 2

Похоже, что эти конфигурации имеют некоторые проблемы с интерфейсом. Он работает, если вы измените IEntity на EntityBase:

public class EntityBase
{
    public virtual int Id { get; set; }
}

public class Customer : EntityBase
{
    public virtual string Name { get; set; }
}

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
    where TEntity : EntityBase
{
    public EntityConfiguration()
    {
        HasKey(e => e.Id);
        Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

public class CustomerConfiguration : EntityConfiguration<Customer>
{
    public CustomerConfiguration()
        : base()
    {
        ...
    }
}

Ответ 3

Вы можете просто создать статический метод для класса и передать в него объект. Например:

public class CustomerConfiguration : EntityConfiguration<Customer>
{
    public CustomerConfiguration()
        : base()
    {
        ...
        EntityConfiguration.Configure(this);
    }
}

public static class EntityConfiguration
{
    public static void Configure<TEntity>(EntityTypeConfiguration<TEntity> entity) where TEntity : EntityBase
    {
        entity.HasKey(e => e.Id);
        entity.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

Ответ 4

У меня есть аналогичная проблема с EF5.0, когда у меня есть общий абстрактный класс с свойством Id и реализация для абстрактных членов и самоопределенных свойств. Посмотрите, как код сущности, сначала ищет только свойства сопоставленного класса. Я попытался использовать отражатель - кажется, я прав, но не уверен об этом на 100%.

И, к счастью, нашли решение для этого:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {                
            modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
            modelBuilder.Entity<MyEntity>()
               .Map(m =>
               {
                   **m.MapInheritedProperties();**                   
               });
        }

поэтому в моем случае: для сопоставления свойств из базового класса я должен добавить одну строку кода m.MapInheritedProperties()...