Many-to-many request in Entity Framework 7

I follow this example that I got from http://ef.readthedocs.org/en/latest/modeling/relationships.html

class MyContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<Tag> Tags { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<PostTag>() .HasKey(t => new { t.PostId, t.TagId }); modelBuilder.Entity<PostTag>() .HasOne(pt => pt.Post) .WithMany(p => p.PostTags) .HasForeignKey(pt => pt.PostId); modelBuilder.Entity<PostTag>() .HasOne(pt => pt.Tag) .WithMany(t => t.PostTags) .HasForeignKey(pt => pt.TagId); } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public List<PostTag> PostTags { get; set; } } public class Tag { public string TagId { get; set; } public List<PostTag> PostTags { get; set; } } public class PostTag { public int PostId { get; set; } public Post Post { get; set; } public string TagId { get; set; } public Tag Tag { get; set; } } 

Now my question is: how do I build my request to receive messages with TagId? Sort of:

 public List<Post> GetPostsByTagId(int tagId) { //linq query here } 

Please keep in mind that this is EF7.

+5
source share
3 answers

My first tip is to change the properties of your collection to ICollection<T> instead of List<T> . You can find a really good explanation in this post .

Now, returning to your real problem, I will make your request:

 public List<Post> GetPostsByTadId(int tagId) { using(var context=new MyContext()) { return context.PostTags.Include(p=>p.Post) .Where(pt=> pt.TagId == tagId) .Select(pt=>pt.Post) .ToList(); } } 

You will need to load the Post navigation property because EF7 does not support lazy loading, and also, as @Igor recommended in your solution, you have to include PostTags as DbSet in your context:

  public DbSet<PostTags> PostTags { get; set; } 

Explanation:

Your query starts in the PostTags table, because it is in this table where you can find all the messages associated with a specific tag. See Include as an internal join to the Post table. If you use the connection between the PostTags and Posts filters using TagId , you will get the columns you need. With a Select call, you say that you only need columns from the Post table.

If you remove the Include call, it should still work. With Include you explicitly indicate that you need to make the connection, but with Select Linq EF provider is smart enough to see that it needs to implicitly use the connection to get the Posts columns as a result.

+9
source
 db.Posts.Where(post => post.PostTags.Any(pt => pt.TagId == tagId)); 
+2
source

This is not very specific to EF7.

You can expand your DbContext by including PostTags

 class MyContext : DbContext { public DbSet<PostTags> PostTags { get; set; } 

Then your request

 db.Posts.Where(post => db.PostTags.Any(pt => pt.PostId == post.PostId && pt.TagId == tagId)) .Select(post => post); 
0
source

Source: https://habr.com/ru/post/1247456/


All Articles