概述
我首先使用实体框架4.3代码,使用流畅的界面来设置我的DbContext。我有一个基本 Item 类,其他类型继承了这个类,例如事件, BlogPost , ForumThread ,< em> WikiPage 等等。
这些继承的类型映射到我认为实体框架称为TPT继承的内容。这在查询单个类型(如“事件”或“博客帖子”)时非常有用,但在尝试查询所有类型时构建非常复杂的查询,因为为了实现EF提供的多态行为而需要连接所有类型
问题背景
我想构建一个全局搜索功能,我只需要访问基础'Item'实体而不是继承实例。我希望能够通过名称,标签等查询基本项目类。执行任何类型的LINQ查询,即使在请求基本项类型时仍会导致多态行为,从而导致性能下降。
代码优先模型
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Body { get; set; }
public DateTime Created { get; set; }
public int? CreatedBy { get; set; }
public int? LastModifiedBy { get; set; }
public DateTime? LastModified { get; set; }
public virtual User Author { get; set; }
public bool IsDeleted { get; set; }
public string ImageUri { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Event : Item
{
// Additional properties
}
public class BlogPost : Item
{
// Additional properties
}
我希望能够做的是将另一个POCO映射到同一个基表,这样当我构建查询时,它就不会涉及继承问题。 EF似乎并不喜欢这样。我目前没有手头的错误,但我对简单映射的尝试失败了。
替代解决方案?
我曾考虑过实现一个'index'表,它看起来类似于'Item'表,每当创建一个新的item类型时都会在其中插入一条记录。但是,每当事件,博客文章数据发生变化等时,这个索引数据也需要更新。这会因标签等外键而变得更加复杂。每当事件上的标签被更改时,我都必须确保这些更改在匹配的索引表上同步。在考虑所有不同的项目类型时,这将成为一个管理的噩梦,坦率地说,似乎不是一个非常优雅的解决方案。
数据库触发器
我首选的解决方案是代码而不是数据库触发/存储过程。
有没有办法构建一个查询来强制EF只返回基类型而不是多态类型,这导致了太多的连接和可怕的性能?或者还有其他一些聪明的方法吗?
更新
通过Nuget(目标.Net 4.0)更新到EntityFramework 5之后,我已经能够通过标签查询项目并将项目投射到新的 SearchItem 中,从而产生相当干净的SQL而无需加入TPT类型。
var x = from item in repository.FindAll<Item>()
where item.Tags.Any(t => t.Name == "test")
select new SearchItem
{
Id = item.Id,
Name = item.Name,
Body = item.Body,
Created = item.Created,
CreatedBy = item.CreatedBy,
IsDeleted = item.IsDeleted,
ImageUri = item.ImageUri,
MembershipEntityId = item.MembershipEntityId,
//Tags = (from t in item.Tags
// select new Tag
// {
// Id = t.Id,
// Name = t.Name,
// MembershipEntityId = t.MembershipEntityId
// })
};
SQL
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Body] AS [Body],
[Extent1].[Created] AS [Created],
[Extent1].[CreatedBy] AS [CreatedBy],
[Extent1].[IsDeleted] AS [IsDeleted],
[Extent1].[ImageUri] AS [ImageUri],
[Extent1].[MembershipEntityId] AS [MembershipEntityId]
FROM [dbo].[Item] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[ItemTag] AS [Extent2]
INNER JOIN [dbo].[Tag] AS [Extent3] ON [Extent3].[Id] = [Extent2].[Tag_Id]
WHERE ([Extent1].[Id] = [Extent2].[Item_Id]) AND (N'test' = [Extent3].[Name])
)
这已解决了我的一半问题,因为我现在可以按标签搜索基本类型。但是我希望能够使用新投影返回标签。包括那些注释掉的代码会导致EF无法翻译的查询。有解决方法吗?
答案 0 :(得分:3)
有没有办法构建一个查询来强制EF只返回 基类型而不是导致太多的多态类型 加入和可怕的表现?
一般没有。您已映射继承,如果要返回Item
的实例,则EF必须始终返回正确的type =&gt;它需要那些连接。 EF也不允许多次映射同一个表,因此您不能在同一映射中将Item
映射为另一个POCO。
理论上,您应该能够查询Items
并投影到您希望从基类获得的非映射 POCO类属性。不幸的是,这在.NET 4.0中不起作用 - EF still performed joins。您可以使用.NET 4.5和EF 5.0来解决此问题should be solved。