0

使用

  • 视觉工作室 2010
  • .Net 框架 4
  • C#
  • Linq 到实体

问题

我希望能够将 DRY 和 SOLID 等面向对象的原则应用于一些 Linq 投影。到目前为止,通过编译的查询或传递的参数,我可以成功地将这些应用到 Linq 的其余部分,而不是在预测中。

如果这不可能,请告诉我,我必须选择我的替代解决方案之一(如下所述),如果可能,那么如何,或者如果我遗漏了某些东西,并且还有另一种替代实现可以满足目标。

细节

在高层次上,我希望能够使用标准的 Linq 查询或 CompiledQuery 动态控制 Linq 投影中使用的类型。我在我的示例和实际代码中使用 Linq to Entities,但是该问题应该适用于核心 Linq。

以下是非动态且无法解决问题的简单示例。它们被固定为始终对每种类型使用 FooUser。我想要做的是动态控制在投影中创建的用户类型,所有这些都将基于一个通用的 IUser 接口。这将或可能类似于我如何控制查询过滤器的类型。

替代解决方案

我试图遵守 DRY、SOLID,并且还试图避免使用枚举来处理这是典型的代码异味。然而,在我所有的尝试和研究中,我似乎不得不落入以下解决方案之一。

  1. 为每种类型实现一个查询,除了它们过滤的类型和投影中使用的类型之外,它们都是相同的。虽然这违反了 DRY 和 OCP,但我可以将其封装在一个类中,并将它们作为编译查询保持在一起。如果我添加新类型或查询数据的方式发生更改,这将需要更改类。

  2. 实现一个具有类型的枚举,并使用一个更通用的用户类,该类将其类型作为属性。但是,这将导致我不得不在多个位置使用枚举并引入长 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
                       });-
4

1 回答 1

0

我找到了一种使用标准方法调用的方法。我还没有弄清楚如何使用已编译的查询来做到这一点,它看起来不太可能。

我不知道泛型的 where 语句中的构造函数约束 I。这可以满足我的需要。我很想用编译的查询来做到这一点,但可以对这个解决方案感到满意。

public IQueryable<IUser> FooMethod<T>(int type) where T : IUser, new()
{
    using (MyEntities context = new MyEntities())
    {
        var results = from u in context.users
                      where u.usertype == type
                      select new T
                      {
                          id = u.UserId,
                          name = u.UserName,
                          location = u.Userlocation
                      };
        return results; 
    }
}

我选择发布答案而不是删除问题有两个原因,一个是如果其他人正在寻找类似的东西,它可能会有所帮助。然后当然我可能会偏离基础,让人们在事物上打洞并看看我们能想出什么更好的东西总是很有趣。

于 2010-10-01T01:50:38.850 回答