使用Repository模式和ViewModel,如果您不希望原始数据库对象泄漏到存储库之外,如何针对数据库构建查询?如何在不加载内存中的所有数据库并使用LINQ to Objects的情况下实际创建查询?我无法将IQueryable暴露给应用程序的其余部分。
例如,使用EF我有一堆POCO,它们具有与db字段匹配的几个属性,但也有一些东西可以解决枚举不能直接支持(现在)以及外键ID来防止N + 1和更容易查询等。我不希望它们泄漏到应用程序的其余部分,我希望应用程序只看到一个普通的对象图。
public class DbUser
{
public int Id { get; set; }
public string Name { get set; }
public int GroupId { get; set; }
public DbGroup Group { get; set; }
public ICollection<DbComment> { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get set; }
public Group Group { get; set; }
public ICollection<Comment> { get; set; }
}
这里的问题是我的存储库将在内部使用EF进行查询(以及单元测试时的内存中)。但是我该如何实施IQueryable<User> FindAll()
?我不能只返回dbContext.Users.Select(u => new User(u))
,因为在这种情况下我失去了所有可能的查询能力;它只是将整个用户集合加载到内存中,将所有类型从DbUser转换为User,然后在内存集合中构建LINQ查询 - 这非常低效。
我不能只在存储库中构建查询。在某些页面上,我有查询选择几个字段,但也从其他相关对象计算一些复杂的东西,根据结果过滤它们(例如带有正分数的评论计数),但我还需要在应用程序中。我可以选择用于获取复杂内容的所有对象并将它们返回给应用程序(但不是作为数据库实体),但这意味着选择大量数据。
基本上,我如何阻止数据库实体以其残留和黑客攻击应用程序的其余部分,同时仍然保持在存储库之外构建查询的能力 ?
答案 0 :(得分:1)
CQRS(Command Query Responsibility Segregation)解决了这个问题。你有'真实'模型,域模型,所有业务规则和所有这些,以及一个'query-ony'模型,它基本上是一个简单的poco(可以由Views直接使用),它将由一个专门的查询存储库。
持久性模型(EF实体)仅用于与db“交谈”,repos始终返回或处理域/应用程序对象。基本上,您必须将EF实体映射到域实体(并且在保存时反之亦然)。通过这种方式,您将拥有各自独立的模型。