Configuring Existing DataBase with Many-to-Many using Code First

With CTP5 of Code First, you can easily map existing database schema to classes in your project.  It allows you to configure what class and property gets mapped to what table and column in the database. Code First gives you two options to configure the mapping. You can either use DataAnnotation such as attributes or use the fluent api to explicitly control every single detail about the mapping. In the existing database schema, I had a many-to-many table and I was wondering what would be the cleanest way to map that to an association in my code first. Let’s see an example.

Suppose we have a database consisting of Authors and books as shown below.

image

In the code first I have Author and Book entity and each has a collection to the other as shown below.

[Table("Author")]

    public class Author

    {

        public Author()

        {

            Books = new HashSet<Book>();

        }

        public int AuthorId { get; set; }

        public string Name { get; set; }

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

    }

 

    public class Book

    {

        public Book()

        {

            Authors = new HashSet<Author>();

        }

        public int BookId { get; set; }

        public string Title { get; set; }

        public virtual ICollection<Author> Authors { get; set; }

    }

On the above classes I have mapped Author class to Author table using Table attribute. At this point I am not done because the default mapping looks for BookAuthors table to map the many-to-many association  between Author and Book where as the many-to-many table in our database is called BookAuthor. Some how we need to tell Code First that many-to-many association should be mapped to BookAuthor table. I really wanted to use Data Annotations to map an association to a table unlike the usual where we map a class to a table.  I don’t know if its possible using Data Annotations but with fluent api, I can override the OnModelCreating method of the derived DbContext and use the Map method to control the table name. Code below shows the code needed.

public partial class PracticeEntities : DbContext

    {

        public PracticeEntities()

            : base("Data Source=.;Initial Catalog=Practice;Integrated Security=True;") { }

 

        public DbSet<Author> Authors { get; set; }

        public DbSet<Book> Books { get; set; }

 

        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)

        {

            modelBuilder.Entity<Author>().HasMany(a => a.Books).WithMany(b => b.Authors).Map(m =>

            {

                m.MapLeftKey(a => a.AuthorId,"AuthorId");

                m.MapRightKey(b => b.BookId, "BookId");

                m.ToTable("BookAuthor");

            });

            base.OnModelCreating(modelBuilder);

        }

    }

No Comments