实体框架代码在使用接口时首先生成奇怪的数据库模式

时间:2011-05-09 11:04:10

标签: interface mapping associations ef-code-first 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; }
    }

对于上述模型,它生成以下表结构

预订 - &gt; BookId,标题,作者

笔 - &gt; PenId,Color

标签 - &gt; TagId,Name,BookBookId,PenPenId

当我插入以下数据时

            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();

它不会插入第二本书的标签数据

我想要实现的是我想实现一个三表标记系统 shown here坚持我的班级结构

1 个答案:

答案 0 :(得分:1)

是的,它不会存储其中一本书的标签信息,因为您的标签实例只能与单本书相关联。这需要BookTag之间的多对多关系,但您的关系是一对多关系。 PenTag之间的关系也是一对多关系。 Tag表中的外键清晰可见。

问题是EF代码首先跳过ICollection<ITaggable> Items - 代码首先不适用于接口。您必须将标记定义为:

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; }
}

这会在BookTag以及PenTag之间的多对多之间映射多对多。如果您还希望收集ITaggable,则可以展示连接BooksPens的其他媒体资源。

如果您真的想要一对多的关系,那么您不能指望该标记会与多本书相关联,在这种情况下,您的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作为计算属性。从这些例子中可以明显看出任何关系的组合。

编辑:

如果您不想在Tag中公开导航属性,则必须使用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();
    }
}

可以在ADO.NET team blog找到更流畅的api参考,但这不符合数据(适用于CTP5)。