1

I love EF Code First, but sometimes it seems it would be easier to just define the tables in SQL.

In this case I have two models, something like this:

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<BookRecommendation> BookRecommendations { get; set; }
    // additional properties about the item
}

public class BookRecommendation
{
    public int Id { get; set; }
    // public int BookId { get; set; } // from attempts to use data annotations
    public virtual Book Book { get; set; }
    // public int BookRecommendedId { get; set; } // from attempts to use data annotations
    public virtual Book BookRecommended { get; set; }
    // additional properties about the relationship between the two items
}

Unfortunately, I can't get this to work correctly with either data annotations or the fluent API.

There are questions like Multiple foreign keys pointing to same table in Entity Framework 4.1 code first, Entity Framework 4.1 InverseProperty Attribute and ForeignKey, and others like this, but these tend to involve collections on both end.

My models could just be wrong, since frustration set in early and I thought about how I'd do this in SQL:

Book
    Id
    Name
    // other properties

Recommendation
    Id
    BookId
    RecommendedBookId
    // other properties

There would then be foreign keys between Book.Id : Recommendation.BookId and Book.Id : Recommendation.RecommendedBookId.

What do I need to do via data annotations or fluent API to get this working, or how should I modify my models?

Community
  • 1
  • 1
James Skemp
  • 8,018
  • 9
  • 64
  • 107
  • Possible duplicate of [Entity Framework Code First - two Foreign Keys from same table](http://stackoverflow.com/questions/5559043/entity-framework-code-first-two-foreign-keys-from-same-table) – Michael Freidgeim Aug 02 '16 at 13:45
  • Honestly, given that this question is over 4 years old, I can't say 100% whether it's a possible duplicate of that or not. But based upon the two highest rated answers on that question, and the last answer to this one from March '13, and that I seemingly wasn't getting an exception, but possibly tables that didn't match my database-first assumptions, I'd lean toward these being different. – James Skemp Aug 02 '16 at 15:35
  • "Possible duplicate" is a way to clean-up - to close similar questions and keep one with the best answers. See  http://meta.stackexchange.com/questions/147643/should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer-and-ha – Michael Freidgeim Aug 02 '16 at 21:44

2 Answers2

0
public class Book
{
    public int BookID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<BookRecommendation> BookRecommendations { get; set; }

}

public class BookRecommendation
{
    public int BookRecommendationID { get; set; }
    public int BookID { get; set; } 
    public string remarks { get; set; } //Some recommendation text

    public virtual Book Book { get; set; }

}

I guess this should solve the problem! It will make a Book entity and a collection of Recommendations for it. Which means a book can have many recommendations and a recommendation will belong to only one book. When a book is created and then you try to write recommendation for it, you will see that there's a dropdown box that has the name of the book through its "BookID".

Sorrel Vesper
  • 414
  • 4
  • 18
0

Good question. Sorry it took me a year to find this.

You need to tell EF which of your 2 relationships back to Book is the one that BookRecommendation is pointing to using the InversePropertyAttribute. In code:

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }

    [InverseProperty("BookRecommended")]
    public virtual ICollection<BookRecommendation> BookRecommendations { get; set; }
    // additional properties about the item
}

public class BookRecommendation
{
    public int Id { get; set; }

    [ForeignKey("Book")]
    public int BookId { get; set; }
    public virtual Book Book { get; set; }

    [ForeignKey("BookRecommended")]
    public int BookRecommendedId { get; set; }
    public virtual Book BookRecommended { get; set; }
}

So the InverseProperty on Book names the BookRecommended property on BookRecommendation so EF is clear on which of the 2 FKs this one refers to. For good measure the 2 ForeignKey attributes just make it possible to explicitly name the FK properties on BookRecommendation - you can get rid of the extra properties if you want, but the attribute has to be there if you keep them.

Chris Moschini
  • 36,764
  • 19
  • 160
  • 190