Linq to entities 和业务逻辑

4
每当我阅读关于Linq to Entities的文章时,感觉好像需要将业务逻辑嵌入生成的实体类中。
这意味着业务对象(控制器、服务层等)的“用户”必须了解使用Linq所需的数据上下文对象。
这也意味着数据访问逻辑和业务逻辑将混合在一起。
许多微软示例使用某种DTO方法。我不是DTO模式的铁粉。
所以,我应该让业务对象封装Linq实体,并使用属性提供对其的访问,还是应该坚持使用DTO模式?
你有什么建议吗?
谢谢
3个回答

3
实体模型生成“部分类”。在我的一个项目中,我在类库中使用实体模型,并添加了一些 .cs 文件,以向默认实体类添加功能(主要是与错误和消息记录到数据库表相关的函数和导入/导出所有数据到 XML 的方法)。
但是真正的业务逻辑位于第二个引用此实体类库的类库中。让我们来解释一下。首先,我从数据库创建了一个实体模型。它包含公司名称和地址列表。我通过选择“新建项目|类库”,然后将 ADO.NET 实体数据模型添加到该库中来完成这个过程。实体模型将链接到我的 SQL Server 数据库,导入我需要的表并自动为我想要访问的表创建类。然后,我为每个要扩展的表添加第二个 .cs 文件。这将是一些与数据库强关联的原始方法(主要是导入/导出方法和错误记录)。我将其称为 Entity.Model,它将编译为 Entity.Model.dll。
然后,我添加了第二个项目,其中包含业务逻辑。同样,我使用“新建项目|类库”来创建它,并将 Entity.Model.dll 添加到其引用中。然后,我开始编写类,这些类将把特定于数据库的类转换为更逻辑的类。通常,除了保护或隐藏某些字段并添加一些计算字段外,我不必进行太多更改。业务逻辑仅公开我想要从客户端应用程序访问的功能,而不是单个方法。因此,如果我不允许客户端删除公司,则实体模型中的“删除”函数将不会在业务层中公开。也许当公司更改其地址时,我想发送通知,所以我将添加一个事件,当公司的地址字段更改时触发该事件(这将编写一条消息记录或其他内容)。我将其称为 business.logic,并将其编译为 Business.Logic.dll。
最后,我将创建客户端应用程序,并将引用添加到 Business.Logic.dll(但不是实体模型)。现在,我可以开始编写我的应用程序并通过业务层访问数据库。业务层将进行验证、触发几个事件以及除了通过实体模型修改数据库之外的其他操作。而实体模型只是用于保持数据库关系简单,允许我通过数据库中的所有外键链接“浏览”数据。

谢谢你的回答,但是第二个类库如何“使用”实体模型呢(请看我在之前回答中的评论)。 - Gert
实体类库是一个公共类。将其添加到第二个类的引用中,并通过在第二个类中使用实体类的命名空间来使用它。两个类库都编译为.DLL程序集。我会在上面的答案中添加更详细的解释。 - Wim ten Brink

1

我不会编辑生成的文件,因为它们很可能会改变。

你可以做的是将它们包装在一些查询对象中并传递它们。

Ayende提出了一个非常好的观点,关于数据访问层应该真正存在的位置

此外,你应该成为视图模型/数据传输对象的粉丝 ;)


那么您建议我创建一堆“无状态”的管理器类,这些类使用查询对象(就像微软的示例)吗?还是我的业务类应该包含一个查询对象实例,并将其公开给底层层?这样,我可以在业务对象上拥有保存方法、加载方法等。 - Gert
持久性与业务逻辑无关。当你说“linq to entities”时,你是指“linq to sql”而不是“linq to objects”吗?如果是这样,那么我真的不会使用自动生成工具,只需自己编辑xml或使用流畅的linq2sql即可。然后你的实体几乎可以是POCO,并且可以在其中添加业务逻辑以及服务类。请记住,微软已经放弃了linq2sql,因为它很糟糕。 - Andrew Bullock
1
他显然在谈论linq2entities,而不是linq2sql。此外,linq2sql并没有被放弃,因为它“糟糕”。微软选择专注于实体框架,并将这两个分歧的努力合并为一个。 - Chrisb
通过linq to entities,我指的是以前的ADO.net实体框架。它类似于linq to sql,但具有更高级的映射功能(不是1:1与db,更像nHibernate...)。它应该是linq to sql的“继承者”。你可以将其与nHibernate进行比较。但问题仍然存在,我应该将我的业务逻辑嵌入到实体模型的部分类中,还是应该创建一个额外的层?这个额外的层应该是无状态的(静态方法)还是有状态的(像传统的OO一样)?谢谢 - Gert
1
这是我自己尚未回答的问题。就个人而言,我希望能够将数据库模式的利用能力添加到框架中。这样可以很好地用于验证。目前,我正在使用服务层路线。 - Chrisb

1
我喜欢将对实体类的调用封装在业务类中(简称BC)。每个BC都有几个构造函数,其中一个或多个允许传递上下文。这使得一个BC可以调用另一个BC并在同一个上下文中加载相关数据。这也使得处理需要共享上下文的BC集合更加简单。
在不带上下文的构造函数中,我在构造函数本身中创建一个新的上下文。我通过只读属性使上下文可供其他BC访问。
我使用MVVM模式编写代码。这种方法的好处是,到目前为止,我一直能够编写视图模型而无需引用数据上下文,只需引用形成我的模型的BC。因此,如果需要修改数据访问(替换实体框架或升级到测试版之外的版本4),我的视图和视图模型与BC所需的更改隔离开来。
不确定这是否是最佳方法,但到目前为止,我喜欢结果。需要微调以正确设计BC,但最终得到了一组灵活、可扩展和可维护的类。

谢谢您的回复。您是将数据作为BC属性公开,还是仅使用某种方法(例如GetCurrentData())公开查询结果? - Gert
1
我会暴露我需要访问的实体对象的特定属性/字段,而不是全部。如果我不需要在业务组件之外暴露实体对象的某个字段或属性,我就不会为其创建公共甚至受保护的属性或方法。我经常创建私有属性/方法来更好地封装内部逻辑。 - RB Davidson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接