开发者

Entity Framework Code first generating weird database schema when using interfaces

开发者 https://www.devze.com 2023-03-03 17:50 出处:网络
I have following Classes and interfaces.. public interface ITaggable { ICollection<Tag> Tags { get; set; }

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 --> 开发者_如何学JAVAPenId , 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


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).

0

精彩评论

暂无评论...
验证码 换一张
取 消