#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. Как теперь определяются ваши таблицы?