design-patterns - LINQ to entity - 传递模型的最佳实践

标签 design-patterns linq-to-entities repository-pattern

众所周知,大多数应用程序都有数据访问层,通常使用存储库类。通常,我们希望存储库使用强类型对象进行操作,例如

interface IUserRespository
{
     User GetUserByID(int id);
     void AddUser(User u);
     ... and so on
}

但是,有时我们想对数据库进行更复杂的查询,这涉及到分组和聚合。例如,我们想要获取所有用户的所有订单的总值(结果集将只有两列:UserName 和 TotalAmount)。现在我的问题是:存储库方法会是什么样子? LINQ to entity 网上有几十个例子如何使用 sum 和 group by 进行查询,但所有这些例子都返回匿名类型。那么,我们的存储库如何返回这样的查询结果呢?另一个常见的答案是:将它包装在一个类中。所以该方法可能如下所示:
interface IUserRepository
{
    UserOrderTotal[] GetOrderTotalsForAllUsers();
}

UserOrderTotal 必须是一个小类,具有查询返回的两个属性:UserName 和 TotalAmount。此类将在我们的一个 .cs 文件中的某处定义。这真的是唯一的解决方案吗?它看起来很糟糕,因为它在主要实体模型(edmx)之外的某个地方引入了一个新的“临时”模型。理想情况下,我想用一个名为 TotalAmount 的新字段来丰富我的用户模型,该字段只会在此查询中填充,因此界面可能如下所示:
interface IUserRepository
{
    User[] GetOrderTotalsForAllUsers();
}

并且它将返回所有字段设置为默认值的用户实体,除了名称和总金额。我遇到的问题是我无法使用未映射到数据库列的字段来编译模型。我收到错误错误 3004:从第 2226 行开始映射片段时出现问题:没有为 Set User 中的属性 User.TotalAmount 指定映射。在以下情况下,具有键(PK)的实体将不会往返:实体类型为 [FPSoMeterModel.User ]

我做错了吗?这个问题是微不足道的,还是我问错了问题?为每个涉及聚合的查询(!)创建一个包装类似乎有点荒谬。似乎整个 LINQ 的东西都鼓励人们不要使用多层架构,而是在呈现数据的同一层中构建查询......你们如何处理这个问题,你们使用“存储库”类吗? LINQ,如果是的话 - 你如何返回复杂的查询结果?

最佳答案

我不会考虑定义一个新的 UserOrderTotal相反,类里面的不良做法。有两种方法可以查看这样的对象。

(1) 你可以看到这个UserOrderTotal类为 Data Transfer Object (DTO)。这样,它就不是您域的一部分。 DTO 通常用于通过网络传输实体或以扁平形式向表示层提供域对象。我一直在使用它们。在这种情况下,对象被用作数据的投影:作为 View 。 MVVM 模式使用相同的原理,其中 MVVM 的 ViewModel 部分是用户界面特定的 DTO。

(2) 你可以看到这个UserOrderTotal类作为您的域的一部分。从领域驱动设计的角度来看,对象可以是用户语言的一部分。在这种情况下,将其定义为域对象将是合乎逻辑的结果。但不同之处在于它不会在 de Entity Framework 的 (EF) edmx 文件中定义。我认为在 EF 中可以定义没有映射到数据库表的实体,但我不知道这是否让事情变得更容易。我个人认为在 edmx 所在的同一项目中定义这些域对象之外的 edmx 文件没有问题。

关于返回 User 的数组对象:这似乎是个坏主意。这种方法有几个问题。首先,您的代码没有很好地传达其意图。您使用 User对象,但将所有属性留空。对于尝试使用此代码的任何人来说,这种做法都很难遵循。您实际上是在滥用 User对象不是它不是的东西:即聚合。

除此之外,您注意到 EF 无法处理您添加到模型中的这个额外属性。虽然通常可以向 EF 模型添加属性(通过使用部分类),但您应该对此非常保守。当你在 LINQ 查询中使用这些属性时,虽然事情会编译,但事情会在运行时失败。

Making a wrapper class for each query (!) that involves aggregation seems a bit ridiculous.



我不这么认为。 IMO 这是正确的做法。这是在多层架构中使用 EF 的结果。我必须承认,在单层中使用 EF 要容易得多,但从长远来看,它会变得非常困惑。项目越大,需要维护的时间越长,添加更多抽象层是合理的。

How do you guys deal with this, do you use "repository" classes with LINQ



我设计的应用程序通常有一个服务/业务层将读取与突变分开。对于读取操作/查询,我使用带有返回域对象或 DTO 集合的方法的静态类。通常这样的“服务方法”特定于用户界面的特定部分。突变包含在“服务命令”中。用户界面创建一个服务命​​令并触发它。命令表示单个用例或用户故事,是一个原子逻辑。服务层将确保在执行命令时创建数据库事务(在需要时)。对于用户界面,使用命令通常如下所示:
void UpdateButton_Click(object sender, EventArgs e)
{
    if (!this.Page.IsValid)
    {
        return;
    }

    var command = new UpdateUserSettingsCommand();

    command.UserName = this.UserName.Text;
    command.MailAddress = this.MailAddress.Text;

    command.Execute();
}

我希望这一切都有意义。如果您想了解更多关于我如何使用 DTO 的信息,请阅读 this SO answer of mine .

我希望这有帮助。

关于design-patterns - LINQ to entity - 传递模型的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3228697/

相关文章:

java - 使用抽象子类设置 super 属性

php - 这是策略模式的一个很好的用例吗?

c# - LINQ to Entities,连接两个表,然后分组并从两个表中获取列的总和

c# - 在一个数据库请求中连接 IQueryable 集合

c#-4.0 - EF4 : how to use a generic repository pattern ?

php - Laravel 存储库模型中的 API 调用

asp.net-mvc - 具有依赖注入(inject)的工作单元 + 存储库 + 服务层

python - 哪个示例应用程序展示了 Google App Engine/Python 应用程序中 MVC 结构的最佳实践?

c# - 如何在运行时创建一个表达式以在 GroupBy() 中使用 Entity Framework?

oop - DDD - 实体不能直接访问 Repositories 的规则