Проблема множественного наследования с EF 4.1 - PullRequest
1 голос
/ 24 августа 2011

Я не уверен, что я делаю неправильно, но у меня проблема с множественным наследованием и построением моей модели. Я получаю сообщение об ошибке " Свойство 'Id' не объявлено для типа ... ". Все работало нормально, прежде чем я добавил класс ContextEntity и у меня была модель TPC. Каждый (не абстрактный) производный объект имеет свой собственный идентификатор и собственную таблицу. Другие классы всегда существовали, и мои отображения работали нормально. Вот мои занятия:

public abstract class Entity
    {
        public virtual Guid Id { get; set; } 
        public DateTime DateCreated { get; set; }
        public DateTime DateModified { get; set; }
        public EntityStatus EntityStatus { get; set; }
        public byte[] RowVersion { get; set; }
    }


    public abstract class ContextEntity : Entity
    {
        public string Description { get; set; }
        public ICollection<Comment> Comments { get; set; }
        public virtual Contact Owner { get; set; }
    }


    public abstract class Document : ContextEntity
    {

        public virtual Subscription Subscription { get; set; }

    }

    //This is the Class I want as a table
    public class Rfi : Document
    {
        public string Number { get; set; }
        public string Subject { get; set; }

    }

До того, как у меня была ContextEntity, у меня была только Entity. Не все мои объекты будут использовать ContextEntity. У меня есть этот файл сопоставления:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
    where TEntity : Entity
    {
        protected EntityConfiguration()
        {
            HasKey(e => e.Id);

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

Когда у меня только что был базовый тип Entity, он прекрасно работал. Поэтому я подумал, что добавлю еще один сопоставитель конфигурации, например так:

public class ContextEntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
        where TEntity : ContextEntity
    {
        protected BridgeEntityConfiguration()
        {

            HasKey(e => e.Id);

            Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(e => e.RowVersion).IsRowVersion();
            HasMany(e => e.Comments).WithMany().Map(m =>
                                                        {
                                                            m.MapLeftKey("CommentId");
                                                            m.MapRightKey("EntityId");
                                                            m.ToTable("Entity_Comments");
                                                        });
            HasMany(e => e.Attachments).WithMany().Map(m =>
                                                           {
                                                               m.MapLeftKey("AttachmentId");
                                                               m.MapRightKey("EntityId");
                                                               m.ToTable("Entity_Attachments");
                                                           });
        }
    }

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

RfiMapping: ContextEntityConfiguration<Rfi>

Я предполагаю, что EF не знает, что делать со всеми вложенными базовыми классами?

Ответы [ 2 ]

0 голосов
/ 25 августа 2011

Проблема была связана со свойством Subscription в моем классе Document. В этом классе было свойство, которое должно быть нулевым. Как только я добавил отображение для класса Subscription и обновил свойство null able, все работало нормально. Не уверен, почему это дало мне ошибку в моем классе Rfi, но проблема была не в этом классе.

0 голосов
/ 24 августа 2011

Вы не можете получить RfiMapping из ContextEntityConfiguration<Rfi>. Это будет означать, что вы пытаетесь настроить, например, свойство Id в своем классе Rfi. При добавлении в конфигурацию модели в основном это выглядит так:

modelBuilder.Entity<Rfi>()
    .HasKey(r => r.Id);
// etc.

Но Id объявляется объявленным в базовом классе Entity, поэтому вы не можете определить сопоставления для такого свойства в производной сущности. Это то, что говорит исключение.

Если вы хотите определить сопоставления для свойств базового класса, вы также должны использовать этот класс в вашей конфигурации сопоставления:

modelBuilder.Entity<Entity>()
    .HasKey(r => r.Id);
// etc.

Я считаю, что общая конфигурация, полученная из EntityTypeConfiguration<TEntity>, - плохая идея. Производные классы конфигурации должны всегда иметь дело с одной конкретной сущностью (также может быть абстрактной сущностью) и определять сопоставления для нее.

Итак, у вас должны быть следующие конфигурации:

public class EntityConfiguration : EntityTypeConfiguration<Entity>
public class ContextEntityConfiguration : EntityTypeConfiguration<ContextEntity>
public class DocumentConfiguration : EntityTypeConfiguration<Document>
public class RfiConfiguration : EntityTypeConfiguration<Rfi>

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

Вот пример приложения, которое показывает, что оно также не может работать с вашим старым отображением (без ContextEntity). Вы можете проверить и сравнить различия с вашей реальной моделью. Должно быть какое-то важное отличие, потому что вы говорите, что ваша старая модель работает. Я опустил несколько скалярных свойств, чтобы упростить пример.

  • Создание нового консольного приложения .NET 4 в VS2010
  • Добавить ссылку на EntityFramework.dll
  • Удалите содержимое Program.cs и вставьте следующее
  • Запустить приложение (оно вылетит)

->

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;

namespace EFWrongMapping
{
    public abstract class Entity
    {
        public virtual Guid Id { get; set; }
        public DateTime DateCreated { get; set; }
        public DateTime DateModified { get; set; }
    }

    public abstract class Document : Entity
    {
        public string Name { get; set; }
    }

    public class Rfi : Document
    {
        public string Number { get; set; }
        public string Subject { get; set; }
    }

    public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
        where TEntity : Entity
    {
        protected EntityConfiguration()
        {
            // The following is not allowed if TEntity is Rfi or generally any other
            // type than Entity (which makes it useless to create a generic configuration)
            HasKey(e => e.Id);
            Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }

    public class RfiMapping : EntityConfiguration<Rfi>
    {
        public RfiMapping()
        {
        }
    }

    public class MyContext : DbContext
    {
        public DbSet<Entity> Entities { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new RfiMapping());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new MyContext())
            {
                // just try to build model and initialize DB
                var initializer = new DropCreateDatabaseIfModelChanges<MyContext>();
                try
                {
                    initializer.InitializeDatabase(context);
                }
                catch (Exception e)
                {
                    // We will land here with exception:
                    // "The property 'Id' is not a declared property on type 'Rfi'"
                    throw;
                }
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...