简体   繁体   English

实体框架代码优先,FullTextIndex和继承

[英]Entity Framework Code First, FullTextIndex & Inheritance

I'm currently working, with my team, on a project where we have a large SQL Server 2014 database with a lot of data. 我目前正在与我的团队一起在一个项目中工作,在该项目中,我们有一个包含大量数据的大型SQL Server 2014数据库。 To increase performances, we chose to use FullTextIndex with EntityFramework by following this tutorial . 为了提高性能,我们选择遵循本教程 ,将FullTextIndex与EntityFramework一起使用。 We now have a problem for the table Customer because of inheritance (we think so, it may be something else). 现在,由于继承,表Customer出现了问题(我们认为是这样,可能还有其他问题)。 Here is the model (simplified) : 这是模型(简化):

public abstract class Person // In db : dbo.People
{
    public int Id { get; set }
    public string LastName { get; set; }
    // Other properties
}

public class Customer : Person // In db : dbo.People_Customer
{
    // Inherited properties from Person
}

public class Mission // In db : dbo.Missions
{
    public int CustomerIdPerson { get; set; }
    public virtual Customer Customer { get; set; }
}

When I try to search missions through customer via the following query : 当我尝试通过以下查询通过客户搜索任务时:

context.Missions.Where(m => m.Customer.LastName.Contains("foo")).ToList();

I have this error (raised by SQL Server) : Cannot use a CONTAINS or FREETEXT predicate on column 'LastName' because it is not full-text indexed. 我有此错误(由SQL Server引发): Cannot use a CONTAINS or FREETEXT predicate on column 'LastName' because it is not full-text indexed.

Here is the SQL generated by EF (I just replaced the variable by the actual value of the SQL parameter). 这是EF生成的SQL(我只是用SQL参数的实际值替换了变量)。

SELECT 
[Limit3].[IdJourney] AS [IdJourney]
FROM ( SELECT TOP (2000) 
    [Project4].[IdJourney] AS [IdJourney]
    FROM    (SELECT 
        [Project2].[IdJourney] AS [IdJourney], 
        [Project2].[SuppressionDate] AS [SuppressionDate], 
        [Project2].[State] AS [State], 
        [Project2].[TripIdTrip] AS [TripIdTrip], 
        [Project2].[IdTrip] AS [IdTrip], 
        [Project2].[SuppressionDate1] AS [SuppressionDate1], 
        [Project2].[TripSetIdTripSet] AS [TripSetIdTripSet], 
        [Project2].[C1] AS [C1], 
        (SELECT TOP (1) 
            [Extent6].[PlannedDate] AS [PlannedDate]
            FROM  [dbo].[PlannedElements_PlannedBusinessFleetElement] AS [Extent5]
            INNER JOIN [dbo].[PlannedElements] AS [Extent6] ON [Extent5].[IdPlannedElement] = [Extent6].[IdPlannedElement]
            WHERE (0 = [Extent5].[TypeOfBusinessFleetElement]) AND ([Project2].[IdJourney] = [Extent5].[JourneyIdJourney])) AS [C2]
        FROM ( SELECT 
            [Extent1].[IdJourney] AS [IdJourney], 
            [Extent1].[SuppressionDate] AS [SuppressionDate], 
            [Extent1].[State] AS [State], 
            [Extent1].[TripIdTrip] AS [TripIdTrip], 
            [Extent2].[IdTrip] AS [IdTrip], 
            [Extent2].[SuppressionDate] AS [SuppressionDate1], 
            [Extent2].[TripSetIdTripSet] AS [TripSetIdTripSet], 
            (SELECT TOP (1) 
                [Extent4].[PlannedDate] AS [PlannedDate]
                FROM  [dbo].[PlannedElements_PlannedBusinessFleetElement] AS [Extent3]
                INNER JOIN [dbo].[PlannedElements] AS [Extent4] ON [Extent3].[IdPlannedElement] = [Extent4].[IdPlannedElement]
                WHERE (0 = [Extent3].[TypeOfBusinessFleetElement]) AND ([Extent1].[IdJourney] = [Extent3].[JourneyIdJourney])) AS [C1]
            FROM  [dbo].[Journeys] AS [Extent1]
            INNER JOIN [dbo].[Trips] AS [Extent2] ON [Extent1].[TripIdTrip] = [Extent2].[IdTrip]
        )  AS [Project2] ) AS [Project4]
    LEFT OUTER JOIN [dbo].[TripSets] AS [Extent7] ON [Project4].[TripSetIdTripSet] = [Extent7].[IdTripSet]
    LEFT OUTER JOIN  (SELECT [Extent8].[IdPerson] AS [IdPerson1], [Extent8].[LastName] AS [LastName]
        FROM  [dbo].[Persons] AS [Extent8]
        INNER JOIN [dbo].[Persons_Customer] AS [Extent9] ON [Extent8].[IdPerson] = [Extent9].[IdPerson] ) AS [Join5] ON [Extent7].[CustomerIdPerson] = [Join5].[IdPerson1]
    WHERE (CONTAINS([Join5].[LastName], '"foo*"'))
)  AS [Limit3]

I'm sure the column is full-text indexed. 我确定该列是全文索引的。 I've rebuild multiple times the calalog and the index. 我已经多次重建了calalog和索引。 For other tables that are not inherited, the FullTextSearch works fine... 对于其他未继承的表,FullTextSearch可以正常工作...

I'm out of ideas... Thanks for your help. 我没有主意...谢谢您的帮助。 :) :)

Probably the problem is related to the fact that CONTAINS access to a Join and not to a table so SQL Server does not like it. 问题可能与以下事实有关:CONTAINS访问联接而不是表,因此SQL Server不喜欢它。 I usually avoid to inherit on classes written on the DB (scared about EF behaviour :) ). 我通常避免继承数据库上编写的类(担心EF行为:))。

Anyway you could avoid to add the [myAlias] in the piece of 无论如何,您都可以避免将[myAlias]添加到
CONTAINS([myAlias].[LastName], '"foo*"') CONTAINS([myAlias]。[LastName],'“ foo *”')
query. 查询。 Probably sometimes you need to insert [myAlias] so you could change the code in the FtsInterceptor class. 可能有时您需要插入[myAlias],以便可以更改FtsInterceptor类中的代码。 You could add 1 more "tag" 您可以再添加1个“标签”
private const string FullTextPrefixWithoutAlias = "-FTSPREFIXNOALIAS-"; 私有常量字符串FullTextPrefixWithoutAlias =“ -FTSPREFIXNOALIAS-”;
and then call a different RewriteFullTextQuery if you specify the FTSPREFIXNOALIAS (or better add a parameter to RewriteFullTextQuery to specify the behaviour). 如果指定了FTSPREFIXNOALIAS,则调用另一个RewriteFullTextQuery(或者最好在RewriteFullTextQuery中添加一个参数来指定行为)。 The only difference in RewriteFullTextQuery is that in the case you don't want the alias you need to use RewriteFullTextQuery的唯一区别是,在您不想使用别名的情况下
string.Format(@"contains([$2], @{0})",parameter.ParameterName)); string.Format(@“ contains([$ 2],@ {0})”,parameter.ParameterName));
instead of 代替
string.Format(@"contains([$1].[$2], @{0})",parameter.ParameterName)); string.Format(@“ contains([$ 1]。[$ 2],@ {0})”,parameter.ParameterName));

In the same way you can also add more control to the FtsInterceptor adding more "tags"... 同样,您也可以向FtsInterceptor添加更多控件,添加更多“标签” ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM