Использование EF Core FromSql () для полнотекстового поиска по индексу на DbSet <Entity>с ValueObject на той же таблице должно выполняться без LEFT JOIN - PullRequest
1 голос
/ 21 октября 2019

Я использую EF Core 2.2 .FromSql () для запуска полнотекстового поиска запроса с использованием предиката CONTAINS ().

Iвыполнять поиск по всем полнотекстовым индексированным столбцам.

Согласно документации ( ссылка ), для выполнения запроса полнотекстового поиска можно указать:

  • column_name
  • (column_list)
  • "*" (запрос ищет все полнотекстовые индексированные столбцы)

Есть метод ' EF.Functions.Contains () ', но позволяет вводить только одну propertyReference :

Expression<Func<T, bool>> searchPredicate = x =>
     EF.Functions.Contains(EF.Property<string>(x, "FirstName"), searchKeyword);

Я могу построить запрос, используя OR оператор, подобный следующему:

Expression<Func<T, bool>> searchPredicate = x =>
     EF.Functions.Contains(EF.Property<string>(x, "FirstName"), searchKeyword) ||
     EF.Functions.Contains(EF.Property<string>(x, "LastName"), searchKeyword);

Но, глядя в профилировщик, он создает следующий запрос, который нежелателен :

SELECT [x].[Id],
       [x].[FirstName],
       [x].[LastName],
       [x].[Address]
FROM   [Users] AS [x]
WHERE  (CONTAINS([x].[FirstName], 'John' /* @__searchKeyword_1 */))
        OR (CONTAINS([x].[LastName], 'John' /* @__searchKeyword_1 */))

Итак, я должен использовать пользовательскийзапрос в .FromSql () , чтобы выполнить поиск по всем полнотекстовым индексированным столбцам, например:

var customQuery = "SELECT * FROM Users WHERE CONTAINS(*, '\"John\"')";
var users = context.Users.FromSql(customQuery);

Ожидаемый запрос:

SELECT * FROM Users WHERE CONTAINS(*, '\"John\"');

Фактический запрос:

SELECT [p].[Id],
       [p].[FirstName],
       [p].[LastName],
       [p.Address].[Id],
       [p.Address].[Street],
       [p.Address].[StreetNumber]
FROM   (SELECT * FROM Users WHERE CONTAINS(*, '\"John\"')) AS [p]
       LEFT JOIN [Users] AS [p.Address]
         ON [p].[Id] = [p.Address].[Id]

Entity, ValueObject и OnModelCreating () выглядит следующим образом:

public class User : IEntity
{
   public Guid Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public Address Address { get; set; }
}

public class Address: IValueObject
{
   public string Street { get; set; }
   public string StreetNumber { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<User>().ToTable("Users");
    modelBuilder.Entity<User>().OwnsOne(e => e.Address);
}

Я сохраняю Address ValueObject в той же таблице Users с .OwnsOne () .

Использование .FromSql () на другом объекте, в котором нет ValueObject, работает нормально и не включает в запрос LEFT JOIN.

Что следует делатьЯ делаю, чтобы пропустить LEFT JOIN в запросе и правильно выполнить полнотекстовый поиск?

...