Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Fluent API instead of InverseProperty and navigational properties

I have a database model where there is a relationship between models which gives Code First some issues. Below is an constructed example.

One reader can have read several books, and one book can have been read by several readers. Also, each reader might have a favorite book.

//not-working model
public class BookReader
{
    public virtual List<Book> ReadBooks { get; set; }
    public virtual Book FavoriteBook { get; set; }
    public int ID { get; set; }
}

public class Book
{
    public string BookName { get; set; }
    public int ID { get; set; }
}

This does not work very well. If, in the code, multiple readers are set to have read the same book only one of the readers will get it saved to the db (presumably the last set).

Also, if BookReader.FavoriteBook and BookReader.ReadBooks contain the same book and db.SaveChanges() creates this new book (not an existing db entity) it will result in this error:
An error occurred while saving entities that do not expose foreign key properties for their relationships.

Here is my fix with InverseProperty and navigational properties.

//working model
public class BookReader
{
    [InverseProperty("CurrentReaders")]
    public virtual List<Book> ReadBooks { get; set; }
    public virtual Book FavoriteBook { get; set; }

    public int ID { get; set; }
}

public class Book
{
    public string BookName { get; set; }
    public int ID { get; set; }
    //new, unwanted, property
    public virtual List<BookReader> CurrentReaders { get; set; }
}


I do not wish to change the model like this. Is there a way this can be done with Fluent API without changing the model?

I've posted a similar question earlier, but deleted it because the question turned out irrelevant to the problem

like image 753
Jens Avatar asked Oct 03 '22 07:10

Jens


1 Answers

Use WithMany() to configure many to many relationship without navigation property in Book entity:

modelBuilder.Entity<BookReader>()
    .HasMany(r => r.ReadBooks)
    .WithMany();

This will create junction table BookReaderBooks with BookReader_ID and Book_ID as primary key. You can also specify your own pretty names for table and keys:

.WithMany().Map(mc => mc.MapLeftKey("ReaderId").MapRightKey("BookId"));
like image 196
Sergey Berezovskiy Avatar answered Oct 07 '22 04:10

Sergey Berezovskiy