Entity Framework 代码优先、FullTextIndex 和继承
Entity Framework Code First, FullTextIndex & Inheritance
我目前正在和我的团队一起处理一个项目,我们有一个包含大量数据的大型 SQL Server 2014 数据库。为了提高性能,我们选择按照 tutorial 将 FullTextIndex 与 EntityFramework 一起使用。由于继承,我们现在遇到 table Customer
的问题(我们认为是这样,可能是其他原因)。这是模型(简化):
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; }
}
当我尝试通过以下查询通过客户搜索任务时:
context.Missions.Where(m => m.Customer.LastName.Contains("foo")).ToList();
我有这个错误(由 SQL 服务器引发):Cannot use a CONTAINS or FREETEXT predicate on column 'LastName' because it is not full-text indexed.
这里是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]
我确定该列已建立全文索引。我已经多次重建目录和索引。对于其他未继承的 table,FullTextSearch 工作正常...
我没有主意了...感谢您的帮助。 :)
问题可能与以下事实有关:CONTAINS 可以访问 Join 而不是 table,因此 SQL 服务器不喜欢它。我通常避免继承写在数据库上的 classes(害怕 EF 行为 :))。
无论如何你可以避免在
的片段中添加 [myAlias]
CONTAINS([myAlias].[LastName], '"foo*"')
询问。可能有时您需要插入 [myAlias] 以便您可以更改 FtsInterceptor class 中的代码。您可以再添加 1 个 "tag"
private const string FullTextPrefixWithoutAlias = "-FTSPREFIXNOALIAS-";
然后调用不同的 RewriteFullTextQuery 如果您指定 FTSPREFIXNOALIAS(或者更好地向 RewriteFullTextQuery 添加参数以指定行为)。 RewriteFullTextQuery 的唯一区别是,如果您不想要您需要使用的别名
string.Format(@"contains([], @{0})",parameter.ParameterName));
而不是
string.Format(@"contains([].[], @{0})",parameter.ParameterName));
以同样的方式,您还可以向 FtsInterceptor 添加更多控制,添加更多 "tags"...
我目前正在和我的团队一起处理一个项目,我们有一个包含大量数据的大型 SQL Server 2014 数据库。为了提高性能,我们选择按照 tutorial 将 FullTextIndex 与 EntityFramework 一起使用。由于继承,我们现在遇到 table Customer
的问题(我们认为是这样,可能是其他原因)。这是模型(简化):
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; }
}
当我尝试通过以下查询通过客户搜索任务时:
context.Missions.Where(m => m.Customer.LastName.Contains("foo")).ToList();
我有这个错误(由 SQL 服务器引发):Cannot use a CONTAINS or FREETEXT predicate on column 'LastName' because it is not full-text indexed.
这里是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]
我确定该列已建立全文索引。我已经多次重建目录和索引。对于其他未继承的 table,FullTextSearch 工作正常...
我没有主意了...感谢您的帮助。 :)
问题可能与以下事实有关:CONTAINS 可以访问 Join 而不是 table,因此 SQL 服务器不喜欢它。我通常避免继承写在数据库上的 classes(害怕 EF 行为 :))。
无论如何你可以避免在
的片段中添加 [myAlias]
CONTAINS([myAlias].[LastName], '"foo*"')
询问。可能有时您需要插入 [myAlias] 以便您可以更改 FtsInterceptor class 中的代码。您可以再添加 1 个 "tag"
private const string FullTextPrefixWithoutAlias = "-FTSPREFIXNOALIAS-";
然后调用不同的 RewriteFullTextQuery 如果您指定 FTSPREFIXNOALIAS(或者更好地向 RewriteFullTextQuery 添加参数以指定行为)。 RewriteFullTextQuery 的唯一区别是,如果您不想要您需要使用的别名
string.Format(@"contains([], @{0})",parameter.ParameterName));
而不是
string.Format(@"contains([].[], @{0})",parameter.ParameterName));
以同样的方式,您还可以向 FtsInterceptor 添加更多控制,添加更多 "tags"...