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

发布于 2024-11-05 18:07:27 字数 1908 浏览 0 评论 0原文

我有以下类和接口。

 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 --> 书号、书名、作者

笔 --> PenId、颜色

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

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

我想要完成的是我想实现一个三表标记系统 此处显示 遵循我的类结构

I have following Classes and interfaces..

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

For the above model it generates the following table structure

Book -->
BookId , Title , Author

Pen -->
PenId , Color

Tag -->
TagId , Name ,BookBookId , PenPenId

And when i insert the following data

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

It does not insert the Tag data for the second book

What i want to accomplish is that i want to implement a three table tagging system
shown here adhering to my class structure

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

豆芽 2024-11-12 18:07:27

是的,它不会存储其中一本书的标签信息,因为您的标签实例只能与一本书相关联。这需要 BookTag 之间存在多对多关系,但您的关系是一对多的。 PenTag 之间的关系也是一对多的。通过 Tag 表中的外键可以清楚地看到这一点。

问题是 ICollectionEF 代码优先会跳过 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 之间的多对多以及 PenPen 之间的多对多代码>标签。如果您还想要 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 作为计算属性。从这些例子中任何关系的组合都应该是显而易见的。

编辑:

如果您不想在标签中公开导航属性,则必须使用 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 团队博客 但它不符合数据(适用于 CTP5)。

Yes it will not store the tag info for one of the books because your tag instance can be associated only with single book. That would require your many-to-many relation between Book and Tag but your relation is one-to-many. Relation between Pen and Tag is also one-to-many. That is clearly visible by foreign keys in Tag table.

The problem is that ICollection<ITaggable> Items is skipped by EF code first - code first doesn't work with interfaces. You must define your Tag as:

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

This will map many-to-many between Book and Tag and many-to-many between Pen and Tag. If you want also collection of ITaggable you can expose another property concatenating Books and Pens.

If you really want one-to-many relation then you cannot expect that tag will be associated with multiple books and in such case your Tag entity should look like:

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

Again you can create Items as computed property. Any combination of relation should be obvious from these examples.

Edit:

If you don't want to expose navigation properties in Tag you must use 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();
    }
}

Further fluent api reference can be found on ADO.NET team blog but it is not up to data (it is for CTP5).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文