简体   繁体   中英

How handle these two models in code first approach using Entity Framework 7?

Problem

I am coding proof of concept ASP.NET 5 MVC6 that will simulate a library. I am using CTP6 and beta3.

How to define their relationship in Entity Framework 7 using code first approach?

Shelf and Books need a join table. As I see it, this application will consider one shelf at a time and the books on that self. In other words, one shelf has a one to many relationship with books.

Models

Shelf model:

public class Shelf
{
    public int ShelfId { get; set; }

    public string ShelfName { get; set; }

    public ShelfType MyProperty { get; set; }

    public virtual List<Book> Books { get; set; }

    public DateTime Created { get; set; }

    public string CreatedBy { get; set; }

    public DateTime Updated { get; set; }

    public string UpdatedBy { get; set; }

}

Book model:

public class Book
{
    public int BookId { get; set; }

    public string BookName { get; set; }

    public string BookAuthor { get; set; }

    public string BookGenre { get; set; }

    public DateTime BookPublishedDate { get; set; }

    public string Description { get; set; }

    public DateTime Created { get; set; }

    public string CreatedBy { get; set; }

    public DateTime Updated { get; set; }

    public string UpdatedBy { get; set; }

}

Goal

I would like to implement something like this in ASP.NET 5. Since TPH and other features are not yet implemented in EF7, am I on the right track?

In other words, I am thinking the following:

  • ShelfBookViewModel (after all I need a view model to show a shelf and the books, or the book and be able to nagivate back to the shelf). I probably will just name it ShelfBook. This seems to be the wrong approach.
  • I would prefer EF7 being able to figure out I have a join and creating viewmodels for separate concerns. Otherwise, this is a violation of SOLID code practices. Something like given below (from the link earlier).
  • Join tables have not been implemented in EF7 yet and I am asking in vain?

I have not been able to get the following to work as shown below:

 modelBuilder.Entity<Shelf>() 
            .HasMany(p => p.Shelfs) 
            .WithMany(t => t.Books) 
            .Map(mc => 
               { 
                   mc.ToTable("ShelfJoinBook"); 
                   mc.MapLeftKey("ShelfId"); 
                   mc.MapRightKey("BookId"); 
               });

Thank you for your time in reading my question. I hope others find this useful.

To answer your question about many-to-many, you should define your mapping as follows (and, necessarily, update your model classes):

modelBuilder.Entity<Shelf>() 
    .HasMany(p => p.Books) 
    .WithMany(t => t.Shelves) // doesn't exist 
    .Map(mc => 
       { 
           mc.ToTable("BookShelves"); 
           mc.MapLeftKey("ShelfId"); 
           mc.MapRightKey("BookId"); 
       });

which would require you to add an ICollection<Shelf> Shelves { get; set; } ICollection<Shelf> Shelves { get; set; } ICollection<Shelf> Shelves { get; set; } to Book . But, if you did so you'd then have the following (this is my MCVE version of your example):

public class Shelf
{
    public int ShelfId { get; set; }
    public virtual ICollection<Book> Books { get; set; }
}

public class Book
{
    public int BookId { get; set; }
    public virtual ICollection<Shelf> Shelves { get; set; }
}

and then you'd no longer need the mapping anyway, since EF would generate all the relations for you by convention, including the join table that would be visible only in the database itself.

However – from your actual model classes and your discussion around them – it appears you really only need one-to-many, in which case, you should accept Pynt's answer, and ignore mine.

EDIT

As pointed out by Gert Arnold in comments, EF7 does not currently (no longer?) supports generated join tables, which means we'll have to roll our own, which is probably better anyway .

Here's a way I think I might do my own, simple, join tables from now on, if EF will no longer do them for me (warning — I'm just trying to close the loop on this issue ... I'm not bothering to try this in a compiler, so YMMV):

public class Shelf
{
    public int ShelfId { get; set; }
    public virtual ICollection<BookShelf> BookShelves { get; set; }
    public virtual IQueryable<Book> Books
    {
        get
        {
            return BookShelves.Where(s => s.ShelfId == ShelfId)
                              .Select(s => s.Book);
        }
    }
}

public class Book
{
    public int BookId { get; set; }
    public virtual ICollection<BookShelf> BookShelves { get; set; }
    public virtual IQueryable<Shelf> Shelves
    {
        get
        {
            return BookShelves.Where(s => s.BookId == BookId)
                              .Select(s => s.Shelf);
        }
    }
}

public class BookShelf
{
    [Key]
    public int BookId { get; set; }
    [ForeignKey("BookId")]
    public Book Book { get; set; }
    [Key]
    public int ShelfId { get; set; }
    [ForeignKey("ShelfId")]
    public Shelf Shelf { get; set; }
}

I tackle similar situations like this, though it may not fit your needs. I use data annotations as I've not bothered to learn how to setup the Foreign Key via the lambda mapping. With the below setup you can have one instance of a book per shelf, and the shelves can have many books. I've moved the relationship properties to the bottom of the classes for easy visualization.

Shelf model:

public class Shelf
{
    public int ShelfId { get; set; }

    public string ShelfName { get; set; }

    public ShelfType MyProperty { get; set; }

    public DateTime Created { get; set; }

    public string CreatedBy { get; set; }

    public DateTime Updated { get; set; }

    public string UpdatedBy { get; set; }

    public virtual ICollection<Book> Books { get; set; }
}

Book model:

using System.ComponentModel.DataAnnotations.Schema;
public class Book
{
    public int BookId { get; set; }

    public string BookName { get; set; }

    public string BookAuthor { get; set; }

    public string BookGenre { get; set; }

    public DateTime BookPublishedDate { get; set; }

    public string Description { get; set; }

    public DateTime Created { get; set; }

    public string CreatedBy { get; set; }

    public DateTime Updated { get; set; }

    public string UpdatedBy { get; set; }

    public int ShelfId { get; set; }
    [ForeignKey("ShelfId")]
    public Shelf Shelf { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM