2

According to Microsoft Docs https://learn.microsoft.com/en-us/ef/core/modeling/relationships#other-relationship-patterns

Many-to-many relationships without an entity class to represent the join table are not yet supported.

Ok, this leads to a nightmare when you need to migrate apps with several many-to-many relationships that were handled perfectly by EF5.

Now I have Keyword, Tag and KeywordTag entities set up as described in the link.

If I have a keyword entity, which is the correct syntax to retrieve all tags associated with such keyword?

In EF5 it was

var kwd = _context.Keywords.Find(my_kwd_id);
var tagList = kwd.Tags;

Which is the equivalent with EF Core? Intellisense allows me to write

kwd.KeywordTags 

but not

kwd.KeywordTags.Tags

...so I cannot find how to access Tags in any way... Please don't tell me that i have to explicitly search then loop the KeywordTag entity to extract Tags ...

kranz
  • 599
  • 1
  • 6
  • 23
  • 1
    `kwd.KeywordTags.Select(x => x.Tag)`? – Ivan Stoev Apr 29 '17 at 15:37
  • 2
    Thank you so much! Anyway, it is hard to accept that if you want to push further (as in "adopt new technology"), then you have to step back (as in "new technologies are broken until they become old, so they can be replaced by other new technologies that are broken again" and so on...) – kranz Apr 29 '17 at 15:58
  • In case anyone is still looking for how to achieve the same goal, [this](https://stackoverflow.com/a/39672765/4989448) answer guided me as I needed. – rey_coder Oct 12 '17 at 14:09

2 Answers2

2

Since EF Core does not have exact parity with older versions of EF, you need to write bit different code. You would need to do what @Ivan suggested in comments. You also need to eager load your collection because lazy loading is not available. That means you need to do database query explicitly.

Method 1: Instead of using Find you query database directly and bring in related data. (kwd/tagList) would have same data as you are seeing in EF5.

var kwd = db.Keywords.Include(k => k.KeywordTags)
    .ThenInclude(kt => kt.Tag)
    .FirstOrDefault(k => k.Id == my_kwd_id);
var tagList = kwd.KeywordTags.Select(kt => kt.Tag).ToList();

Alternatively, you can use find but load navigations explicitly. This is somewhat similar to lazy loading but since it is not available you ask EF to load navigations. This will have really bad perf as you will send 1 query to fetch all entries from join table & then 1 query for each related tag in tags table. If you are interested in knowing the way to write it, I can post code for that too.

Smit
  • 2,279
  • 1
  • 12
  • 22
  • Many thanks for your explanation. I never saw this kind of syntax, always use a Where clause instead of specifying select conditions as a parameter to FirstOrDefault. Which is the differfence? – kranz May 11 '17 at 05:55
  • 1
    Both are same. Many Linq methods giving single result takes lambda expression as parameter, which is equivalent to write a where clause followed by parameter less operator. In above code you can write where followed by `FirstOrDefault` without arguments. – Smit May 11 '17 at 08:30
0

Tags is an IEnumerable<Tag>. You can iterate over Tags with a foreach loop.

NullEntity
  • 152
  • 11