Код Entity Framework сначала генерирует странную схему базы данных при использовании интерфейсов

#interface #mapping #associations #ef-code-first #entity-framework-4.1

#интерфейс #отображение #ассоциации #ef-code-first #сущность-фреймворк-4.1 #сопоставление #entity-framework-4.1

Вопрос:

У меня есть следующие классы и интерфейсы..

  public interface ITaggable
    {
         ICollection<Tag> Tags { get; set; }
    }

 public class Book :ITaggable
    {
        [DatabaseGenerated(DatabaseGenerationOption.Identity)] 
        public Guid BookId { get;set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public virtual ICollection<Tag> Tags {get; set;}
    }

public class Pen:ITaggable
    {
        [DatabaseGenerated(DatabaseGenerationOption.Identity)]
        public Guid PenId { get; set; }
        public string Color { get; set; }
        public virtual ICollection<Tag> Tags {get; set;}
    }

public class Tag
    {
        [DatabaseGenerated(DatabaseGenerationOption.Identity)] 
        public Guid TagId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<ITaggable> Items { get; set; }
    }
  

Для вышеупомянутой модели она генерирует следующую структуру таблицы

Book -> BookID, название, автор

Перо -> PenId , цвет

Тег -> Идентификатор тега , Имя , идентификатор книги , идентификатор переписки

И когда я вставляю следующие данные

             Tag tag = new Tag();
            tag.Name = "Stationary";

            Book b1 = new Book();
            b1.Title = "Head first c#";
            b1.Author = "Betty";
            b1.Tags = new List<Tag>() { tag };

            Book b2 = new Book();
            b2.Title = "Head first Java";
            b2.Author = "Katty";
            b2.Tags = new List<Tag>() { tag };

            Pen p = new Pen();
            p.Color = "Red";
            p.Tags = new List<Tag>() { tag };

            context.Books.Add(b1);
            context.Books.Add(b2);
            context.Pens.Add(p);
            context.SaveChanges();
  

Он не вставляет данные тега для второй книги

Чего я хочу достичь, так это того, что я хочу реализовать систему тегов из трех таблиц, показанную здесь, в соответствии со структурой моего класса

Ответ №1:

Да, он не будет хранить информацию о теге для одной из книг, потому что ваш экземпляр тега может быть связан только с одной книгой. Для этого потребовалось бы ваше отношение «многие ко многим» между Book и Tag , но ваше отношение — «один ко многим». Отношение между Pen и Tag также один ко многим. Это хорошо видно по внешним ключам в Tag таблице.

Проблема в том, что ICollection<ITaggable> Items пропускается EF code first — code first не работает с интерфейсами. Вы должны определить свой тег как:

 public class Tag
{
    [DatabaseGenerated(DatabaseGenerationOption.Identity)] 
    public Guid TagId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }
    public virtual ICollection<Pen> Pens { get; set; }
}
  

Это приведет к сопоставлению многие-ко-многим между Book и Tag и многие-ко-многим между Pen и Tag . Если вы хотите также коллекцию ITaggable , вы можете предоставить другое свойство, объединяющее Books и Pens .

Если вы действительно хотите отношение «один ко многим», то вы не можете ожидать, что тег будет связан с несколькими книгами, и в таком случае ваша Tag сущность должна выглядеть как:

 public class Tag
{
    [DatabaseGenerated(DatabaseGenerationOption.Identity)] 
    public Guid TagId { get; set; }
    public string Name { get; set; }
    public virtual Book Book { get; set; }
    public virtual Pen Pen { get; set; }
}
  

Снова вы можете создать Items как вычисляемое свойство. Любая комбинация отношений должна быть очевидна из этих примеров.

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

Если вы не хотите предоставлять свойства навигации в теге, вы должны использовать fluent-api:

 public class Context : DbContext
{
    public DbSet<Book> Books { get; set; }
    public DbSet<Pen> Pens { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Book>()
                    .HasMany(b => b.Tags)
                    .WithMany();

        modelBuilder.Entity<Pen>()
                    .HasMany(p => p.Tags)
                    .WithMany();
    }
}
  

Дополнительную беглую ссылку на api можно найти на ADO.NET командный блог но это не зависит от данных (это для CTP5).

Комментарии:

1. Итак, для каждого класса (который нуждается в тегировании), который я добавляю в свою систему, мне придется добавить (public virtual ICollection<NewClass> NewClasses {get; set;}) в мой класс тегов .. я думаю, что это будет не очень хороший дизайн…. есть ли какой-либо другой обходной путь

2. я могу использовать базовый класс вместо интерфейса

3. Если вы хотите получить доступ из Tag к помеченным классам, другого решения нет. Вы можете вообще не включать эти свойства навигации в Tag , но вам придется использовать fluent api для отображения ваших отношений, и вы не сможете получить доступ к связанным объектам из Tag . Базовый класс введет отображение наследования в вашу модель, что приведет к другим последствиям.

4. хорошо .. можете ли вы дать мне какую-либо ссылку на ссылки flent api, где я могу найти похожие решения…

5. Как теперь определяются ваши таблицы?