您可以将 OOP 应用于 Linq 投影吗?

发布于 2024-09-25 19:22:38 字数 1939 浏览 0 评论 0原文

使用

  • Visual Studio 2010
  • .Net Framework 4
  • C#
  • Linq to Entities

问题

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

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

详细信息

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

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

替代解决方案

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

  1. 为每种类型实现一个查询 除了 他们过滤的类型和类型 用于投影。虽然这 违反了 DRY 和 OCP,我可以 将其封装在一个单一的 上课并让他们保持紧密联系 作为已完成的查询。这将 如果我添加,则需要更改课程 一个新类型或者你如何查询 数据发生变化。

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

Using

  • Visual Studio 2010
  • .Net Framework 4
  • C#
  • Linq to Entities

Issue

I would like to be able to apply Object Oriented Principles like DRY and SOLID to some Linq Projections. With compiled queries or passed parameters I can apply these to the rest of Linq successfully so far, just not in the projections.

Please let me know if this isn't possible, and I must choose one of my alternate solutions (described below), if it is possible then how, or if I am missing something and there is another alternative implementation that will satisfy the goal.

Details

At a high level I would like to be able to dynamically control the type used in a Linq Projection, either with a standard Linq Query or a CompiledQuery. I am using Linq to Entities in my examples and actual code, however the issue should be applicable to the core Linq.

Below are simplistic examples that are not dynamic and do not solve the issue. They are fixed to always use the FooUser for each type. What I would like to be able to do is dynamically control the type of user created in the projection all of which would be based on a common IUser interface. This would be or could be similar to how I can control what type the query filters on.

Alternate Solutions

I am trying to conform to DRY, SOLID, and also trying to avoid using an enum to deal which is a typical code smell. However in all my attempts and research I seem to have to fall to one of the following solutions.

  1. Implement a query for each type
    which are all the same except for
    the type they filter on and the type
    used int he projection. While this
    violates DRY and OCP, I can
    encapsulate this within a single
    class and keep them close together
    as complied queries. This will
    require the class to change if I add
    a new type or if how you query for
    the data changes.

  2. Implement a enum that has the types, and use a more generalized User class that has its type as a property. However this will cause me to have to use the enum in several locations and introduce long case statements to handle them, which I would like to avoid.

I would love not to have to choose between different evils, and have an implementation that can conform to all SOLID principles and DRY. However if I must I think I will end up with the first or a version of it.

Examples

Standard Simple Linq Query

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
                  };
}

Compiled Version of the Above Query

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
                       });-

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柠檬心 2024-10-02 19:22:38

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

我不知道泛型的 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; 
    }
}

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

I found a way to do this with a standard method call. I haven't figured out how to do it with a compiled query, it doesn't look likely.

I was not aware of the Constructor Constraint I on the where statement for a generic. This can suit my needs. I would love to do this with a compiled query, but can live happy with this solution.

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; 
    }
}

I chose to post an answer instead of deleting the question for two reasons, one in case others are looking for something similar it could be helpful. Then of course I could be way off base and its is always fun to have people shoot holes in things and see what better stuff we can come up with.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文