【Entity Framework Core】Raw SQL Queries 2

Введение

Когда я писал необработанные SQL-запросы с помощью Entity Framework Core, иногда я получал неожиданные результаты.
В этот раз я попробую, как их избежать.

  • 【Entity Framework Core】Raw SQL Queries

Среды

  • .NET 6.0.101
  • Microsoft.EntityFrameworkCore ver.6.0.1
  • Microsoft.EntityFrameworkCore.Design ver.6.0.1
  • Npgsql.EntityFrameworkCore.PostgreSQL ver.6.0.2
  • NLog.Web.AspNetCore ver.4.14.0

Предотвращение создания таблиц в результате миграции

Когда я помещаю полученные данные в класс, который имеет пользовательские свойства, я добавляю DbSet< T> в класс DbContext.
Но по умолчанию dotnet-ef генерирует новую таблицу при миграции.

SearchedBook.cs

using System.ComponentModel.DataAnnotations;

namespace BookshelfSample.Books.Dto;

public record SearchedBook
{
    [Key]
    public int BookId { get; init; }
    public string BookName { get; init; } = "";
    public string AuthorName { get; init; } = "";
}
Вход в полноэкранный режим Выход из полноэкранного режима

BookshelfContext.cs

using BookshelfSample.Books.Dto;
using BookshelfSample.Models.SeedData;
using Microsoft.EntityFrameworkCore;

namespace BookshelfSample.Models;

public class BookshelfContext: DbContext
{
    public BookshelfContext(DbContextOptions<BookshelfContext> options)
            : base(options) { }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Book>()
            .HasOne(b => b.Author)
            .WithMany(a => a.Books)
            .HasForeignKey(b => b.AuthorId);
        modelBuilder.Entity<Book>()
            .HasOne(b => b.Language)
            .WithMany(L => L.Books)
            .HasForeignKey(b => b.LanguageId);
        modelBuilder.Entity<Language>()
            .HasData(LanguageData.GetAll());
    }
    public DbSet<Author> Authors => Set<Author>();
    public DbSet<Book> Books => Set<Book>();
    public DbSet<Language> Languages => Set<Language>();

    // I don't want to generate "SearchedBook" table.
    public DbSet<SearchedBook> SearchedBooks => Set<SearchedBook>();
}
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы исключить генерацию таблицы, я добавляю «ExcludeFromMigrations» в «OnModelCreating».

BookshelfContext.cs

...
public class BookshelfContext: DbContext
{
...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
...
        modelBuilder.Entity<SearchedBook>().ToTable("searched_book", t => t.ExcludeFromMigrations());
    }
    public DbSet<Author> Authors => Set<Author>();
    public DbSet<Book> Books => Set<Book>();
    public DbSet<Language> Languages => Set<Language>();
    public DbSet<SearchedBook> SearchedBooks => Set<SearchedBook>();
}
Вход в полноэкранный режим Выход из полноэкранного режима
  • Анонс Entity Framework Core (EFCore) 5.0 RC1 — .NET Blog

Добавление нескольких методов where()

Я могу добавить несколько методов where().

SearchBooks.cs

using BookshelfSample.Books.Dto;
using BookshelfSample.Models;
using Microsoft.EntityFrameworkCore;

namespace BookshelfSample.Books;

public class SearchBooks: ISearchBooks
{
    private readonly ILogger<SearchBooks> logger;
    private readonly BookshelfContext context;

    public SearchBooks(ILogger<SearchBooks> logger,
        BookshelfContext context)
    {
        this.logger = logger;
        this.context = context;
    }
    public async Task<List<SearchedBook>> GetAsync(SearchBookCriteria criteria)
    {
        var query = this.context.SearchedBooks
            .FromSqlRaw("SELECT b.id AS "BookId", b.name AS "BookName", a.name AS "AuthorName" FROM book b INNER JOIN author AS a ON b.author_id = a.id");

        if(string.IsNullOrEmpty(criteria.Name) == false)
        {
            query = query.Where(b => b.BookName.Contains(criteria.Name));
        }
        if(string.IsNullOrEmpty(criteria.AuthorName) == false)
        {
            query = query.Where(b => b.AuthorName.Contains(criteria.AuthorName));
        }
        return await query
            .OrderBy(b => b.BookId)
            .ToListAsync();
    }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Согласно журналам, эти методы объединены в одно предложение WHERE.

SELECT b."BookId", b."AuthorName", b."BookName"
FROM (
    SELECT b.id AS "BookId", b.name AS "BookName", a.name AS "AuthorName" FROM book b INNER JOIN author AS a ON b.author_id = a.id
) AS b
WHERE ((@__criteria_Name_1 = '') OR (strpos(b."BookName", @__criteria_Name_1) > 0)) AND ((@__criteria_AuthorName_2 = '') OR (strpos(b."AuthorName", @__criteria_AuthorName_2) > 0))
ORDER BY b."BookId"
Войти в полноэкранный режим Выйти из полноэкранного режима

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *