Entity Framework Core - член IN эквивалент

Интересно, как преобразовать этот SQL-запрос в запрос структуры сущностей.

SELECT * 
FROM Post
WHERE PostId IN (
SELECT PostId FROM BlogPost
WHERE BlogId = &blogId);

Я пытаюсь получить список сообщений с указанным идентификатором категории.

База данных упрощена:

Блог (категория для поста):

BlogId
Title
..

Сообщение:

PostId
Title
.. 

BlogPost для объединения двух таблиц и позволяет вам иметь несколько категорий на пост:

PostId
BlogId

Это то, что у меня уже есть, но, конечно, запрос не работает:

public async Task<IActionResult> Category(int? id)
{
     int blogId = id;

     if (blogId == null)
     {
         return NotFound();
     }
     ICollection<Post> posts = await _context.Post.Where(pid => pid.PostId.Contains(_context.BlogPost.Where(i => i.PostId == blogId).ToListAsync())).ToListAsync();

     if (posts == null)
     {
         return NotFound();
     }

     return View(posts );
}

Заранее спасибо.

Ответ 1

Вот как я бы сделал это в одном запросе на основе предоставленной вами информации.

var posts = await _context.Post
    .Where(post =>
        _context.BlogPost.Any(bp => bp.BlogId == blogId && bp.PostId == post.PostId)
    )
    .ToListAsync();

Вот как я бы сделал это в двух запросах, чтобы использовать Contains на основе предоставленной вами информации.

var postIds = await _context.BlogPost
    .Where(bp => bp.BlogId = blogId)
    .Select(bp => bp.PostId)
    .ToArrayAsync();
var posts = await _context.Post
    .Where(p => postIds.Contains(p.PostId))
    .ToListAsync();

Вот как я мог бы сделать это в одном запросе, если бы использовал ценные функции EntityFramework, и у меня было свойство ссылки с именем Post на BlogPost.

var posts = await _context.BlogPost
    .Where(bp => bp.BlogId == blogId)
    .Select(bp => bp.Post)
    .ToListAsync();

Вот как я мог бы сделать это в одном запросе, если бы я использовал ценные функции EntityFramework, и у меня было свойство коллекции, названное Posts from Blog, и таблица многие-многие BlogPost была скрыта EntityFramework таким образом, что вы фактически никогда не взаимодействовали с это из С#.

var posts = await _context.Blog
    .Where(b => b.BlogId == blogId)
    .SelectMany(b => b.Posts)
    .ToListAsync();

С другой стороны, если EntityFramework предоставляет таблицу много-много блогов BlogPost, вы все равно можете начать с блога и использовать правильно настроенные свойства коллекции и ссылки, чтобы получить такие сообщения.

var posts = await _context.Blog
    .Where(b => b.BlogId == blogId)
    .SelectMany(b => b.BlogPosts)
    .Select(bp => bp.Post)
    .ToListAsync();

Или же

var posts = await _context.Blog
    .Where(b => b.BlogId == blogId)
    .SelectMany(b => b.BlogPosts.Select(bp => bp.Post))
    .ToListAsync();

Выносите, EntityFramework - это не SQL. То, что вы делаете в SQL, может или не может отображаться напрямую, или даже применяться к тому, как вы это сделаете в EntityFramework. Не только это, но и когда вы используете EntityFramework, вы используете функции языка EntityFramework и С#, которые сами по себе не являются EntityFramework, например LINQ. Разбиение проблемы на составные части может помочь вам решить проблемы и упростить изучение до возможности выполнять более сложные операции. Изучение и практика LINQ в отдельности поможет вам стать лучше с EntityFramework.

Ответ 2

Запрос LINQ

from p in _context.Post
where _context.BlogCategory.Any
                ( bc => bc.PostId == p.PostId 
                  && bc.BlogId == &id
                )
select p;

SQL

SELECT * 
FROM Post
WHERE PostId IN (
SELECT PostId FROM BlogCategory
WHERE BlogId = &id);

ИЛИ

SELECT * 
FROM Post p
WHERE EXISTS
    (
      SELECT 1 FROM BlogCategory
      WHERE PostId = p.PostID AND BlogId = &id
    );

Ответ 3

Вы можете использовать соединение для отношений post to blog, а затем предложение where в качестве фильтра блога.

var query = from post in _context.Post
  join blogCat in _context.BlogPost on post.PostId equals blogCat.PostId
  where blogCat.BlogId == blogId
  select post;

var result = await query.ToListAsync();

Это основано на вашем Sql в верхней части вашего кода

SELECT * 
FROM Post
WHERE PostId IN (
  SELECT PostId FROM BlogPost WHERE BlogId = &id);

Ответ 4

EDITED

Вы можете использовать .Select()

 var blog = await _context.Blogs.FirstOrDefaultAsync(b => b.Id == blogId);
 var posts = blog ?? blog.BlogCategory.Select(bp => bp.Post);

Я предполагаю, что у вас есть свойство навигации в Blog BlogCategory Вы можете найти эту полезную ссылку