情境:我正在为我的“持久层”使用LinqToSql (可能被认为是无关紧要的),并试图解决一些架构上的问题,比如某些与业务相关的逻辑应该放在哪里。
场景:应用程序的用户创建一个新订单。当他们这样做时,需要将产品密钥集合与该订单相关联。
我的第一个尝试是将所有这些jazz放在一个OrderService类中。然后,我尝试使用partial方法将其与我的DataContext结合:
partial void InsertOrder(Order instance)
{
var productKeys = this.ProductKeys
.Where(x => x.DeleteDate == null && x.Order == null && !x.Issued)
.Take(instance.NumberOfProductKeys);
if (productKeys.Count() != instance.NumberOfProductKeys)
throw new NotSupportedException("There needs to be more product keys in the database.");
instance.ProductKeys.AddRange(productKeys);
this.ExecuteDynamicInsert(instance);
}尽管这并不像预期的那样工作(产品密钥实际上从未与订单相关联),但我觉得这是从我的业务领域剥离逻辑,并将其推入我的“持久层”。我也考虑过将它放在OrderService类中,但我觉得它也只是从领域实体中移除了逻辑,并产生了一个事务脚本。引入Order Factory正好绕过了这个问题:数据和逻辑再次分离。
所以我的问题是:为了避免一个贫乏的领域模型,并且希望order除了作为一个美化的数据结构之外还能做一些事情,有没有一种适当的方法将这个逻辑集成到我的领域模型中?
我想出的最好的解决方案是将逻辑放到Order类中,并验证它是否在验证钩子中完成:
public partial class Order
{
public void AssociateWithProductKeys(WIIIPDataContext context)
{
var productKeys = context.ProductKeys
.Where(x => x.DeleteDate == null && !x.Issued && x.Order == null && x.ProductType == ProductType)
.Take(NumberOfProductKeys);
if (productKeys.Count() != NumberOfProductKeys)
throw new ValidationException("There needs to be more product keys in the database for product type: " + ProductType.Description);
ProductKeys.AddRange(productKeys);
foreach (ProductKey productKey in ProductKeys)
{
productKey.Issued = true;
}
}
partial void OnValidate(ChangeAction action)
{
if (action == ChangeAction.Insert)
{
if (ProductType.Id == 3 && ProductKeys.Count() != 1)
throw new ValidationException("Attempted to associated more than 1 product key with a CD version.");
if (ProductKeys.Count() != NumberOfProductKeys)
throw new ValidationException("Number of product keys doesn't match expected value");
}
}
}使用代码将如下所示:
// The Unit of Work
using (var context = new MyDataContext())
{
...
order.AssociateWithProductKeys(context);
context.Orders.InsertOnSubmit(order);
context.SubmitChanges();
}== 2012年3月29日==更新
在使用LinqToSQL (和Web Forms)时,我采用了命令/查询模式,不再将LinqToSql DataContext创建的实体用作到我的数据存储的映射。我所有的规则和没有进入的东西都进入了命令对象,在某种程度上,使它们成为应用程序的真正核心。
发布于 2012-03-14 09:05:22
客户端将订单传递给业务逻辑层(BLL)。BLL调用DAL方法获取n个产品密钥。DAL不实现任何逻辑,它只是获得n个键。然后,BLL对DAL提供的内容做出反应。如果有足够的键,则BLL将这些键与订单关联并返回。如果没有足够的键,则BLL不会将键与订单关联,并抛出异常。然后,客户端根据逻辑层返回的内容向用户提供正确的UI消息。
我同意您自己的评估,即DAL中不应该存在逻辑。这意味着DAL方法可能会从不同的用例场景中重用,我们不希望DAL决定任何事情,因为业务规则可能会改变,新的用例可能会出现。
这有帮助吗?
发布于 2012-03-14 12:46:54
我正在使用LinqToSql (可以认为是无关紧要的)
我一点也不认为这是无关紧要的。
抛开LINQ- to -SQL是否是“真正的”ORM的讨论不谈,我发现所有ORM(特别是LINQ-to-SQL)在它们希望您使用它们的方式上都是非常规范的。坚持他们喜欢的模式,一切都很简单。按照你的选择构建你的代码,你会冒着走向痛苦世界的风险。
在这种情况下,当LINQ-to-SQL同时包含数据访问和逻辑(紧密耦合)时,它工作得最好。一旦你有一个非常小的项目以外的任何东西,这是一个可怕的实践,并将导致调试噩梦,但如果你试图分离数据访问和逻辑,你会遇到一些常见的问题。
微软的建议是,DataContext应该是用于工作单元的短期对象。这种方法不能很好地工作,因为LINQ-to-SQL使用的是“附加”/“分离”模型。有几十个网站提出了“通过序列化分离”的黑客攻击,在我看来,这是可怕的。
此外,ORM模型本身适用于数据对象,而不是全功能的封装对象。DataContext需要维护对象之间的关系,因此让它们对自己负责通常会导致以后的麻烦。
虽然我喜欢LINQ-to-SQL,并且已经在许多项目中使用过它,但我不推荐一个很好的模式,我会积极推荐在数据级别上反对任何面向对象的模式。忘记你所知道的,试着写一个易于维护的数据层。根据我的经验,根据严格的设计规则将您的逻辑和数据访问分开,这将导致以后使用此工具包时出现重大问题。
https://stackoverflow.com/questions/9693719
复制相似问题