使用
- 视觉工作室 2010
- .Net 框架 4
- C#
- Linq 到实体
问题
我希望能够将 DRY 和 SOLID 等面向对象的原则应用于一些 Linq 投影。到目前为止,通过编译的查询或传递的参数,我可以成功地将这些应用到 Linq 的其余部分,而不是在预测中。
如果这不可能,请告诉我,我必须选择我的替代解决方案之一(如下所述),如果可能,那么如何,或者如果我遗漏了某些东西,并且还有另一种替代实现可以满足目标。
细节
在高层次上,我希望能够使用标准的 Linq 查询或 CompiledQuery 动态控制 Linq 投影中使用的类型。我在我的示例和实际代码中使用 Linq to Entities,但是该问题应该适用于核心 Linq。
以下是非动态且无法解决问题的简单示例。它们被固定为始终对每种类型使用 FooUser。我想要做的是动态控制在投影中创建的用户类型,所有这些都将基于一个通用的 IUser 接口。这将或可能类似于我如何控制查询过滤器的类型。
替代解决方案
我试图遵守 DRY、SOLID,并且还试图避免使用枚举来处理这是典型的代码异味。然而,在我所有的尝试和研究中,我似乎不得不落入以下解决方案之一。
为每种类型实现一个查询,除了它们过滤的类型和投影中使用的类型之外,它们都是相同的。虽然这违反了 DRY 和 OCP,但我可以将其封装在一个类中,并将它们作为编译查询保持在一起。如果我添加新类型或查询数据的方式发生更改,这将需要更改类。
实现一个具有类型的枚举,并使用一个更通用的用户类,该类将其类型作为属性。但是,这将导致我不得不在多个位置使用枚举并引入长 case 语句来处理它们,我想避免这种情况。
我希望不必在不同的邪恶之间做出选择,并且有一个可以符合所有 SOLID 原则和 DRY 的实现。但是,如果必须,我想我最终会得到它的第一个或一个版本。
例子
标准的简单 Linq 查询
using (MyEntities context = new MyEntities())
{
var results = from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
};
}
上述查询的编译版本
private static readonly Func<MyEntities, int, IQueryable<FooUser>> query = CompiledQuery.Compile<MyEntities, int, IQueryable<FooUser>>(
(context, type) => from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
});-