在Linq2Sql实体之上应用域模型

时间:2010-04-29 02:49:16

标签: linq-to-sql domain-driven-design

我正在努力练习模型第一种方法,我正在整理一个领域模型。我的要求很简单:UserSession可以有多个ShoppingCartItems。

我应该首先说我要将域模型接口应用于Linq2Sql生成的实体(使用部分类)。我的需求转换为三个数据库表(UserSession,Product,ShoppingCartItem,其中ProductId和UserSessionId是ShoppingCartItem表中的外键)。 Linq2Sql为我生成这些实体。我知道此时我甚至不应该处理数据库,但我认为重要的是要提及。

聚合根是UserSession,因为如果没有UserSession,ShoppingCartItem就不能存在,但我不清楚其余部分。那产品怎么样?它绝对是一个实体,但它应该与ShoppingCartItem相关联吗?

以下是一些建议(它们可能都是不正确的实现):

public interface IUserSession {
    public Guid Id { get; set; }
    public IList<IShoppingCartItem> ShoppingCartItems{ get; set; }
}

public interface IShoppingCartItem {
    public Guid UserSessionId { get; set; }
    public int ProductId { get; set; }        
}

另一个是:

public interface IUserSession {
    public Guid Id { get; set; }
    public IList<IShoppingCartItem> ShoppingCartItems{ get; set; }
}

public interface IShoppingCartItem {
    public Guid UserSessionId { get; set; }
    public IProduct Product { get; set; }         
}

第三个是:

public interface IUserSession {
    public Guid Id { get; set; }
    public IList<IShoppingCartItemColletion> ShoppingCartItems{ get; set; }
}

public interface IShoppingCartItemColletion {
    public IUserSession UserSession { get; set; }
    public IProduct Product { get; set; }      
}

public interface IProduct {
    public int ProductId { get; set; }      
}

我有一种感觉,我的思想与数据库模型和表格紧密耦合,这使得这很难掌握。有人想解耦吗?

2 个答案:

答案 0 :(得分:2)

看起来你走在正确的轨道上。整个“做DDD权利”的一半是拥有正确的基类。看看应用于C#资源的这个伟大的DDD:

http://dddpds.codeplex.com/

源代码可用且非常易读。

因此,关于在模型中使用ID。 ID是一种数据库事物,通常的方法是将所有持久性保留在模型之外,并将模型限制为业务逻辑。但是,通常会对标识符进行例外处理并将其隐藏在Model基类中,如下所示:

public class ModelBase {
  protected readonly object m_Key;
  public ModelBase(object key) {
    m_Key = key;
  }
}

持久层使用此密钥与数据库通信并且不透明。将密钥向下转换为所需类型被认为是可以的,因为你知道它是什么。

此外,域对象几乎位于架构堆栈的底部(就在Infrastructure层之上)。这意味着你可以使它们成为具体的类。您将不会有多个域模型的实现,因此接口是不必要的,这就是Domain Driven Design的用途 - 域优先。

public Class UserSession : ModelBase {
  public UserSession(Guid Id):base(Id) {}

  public Guid Id { get{ return m_Key as Guid;} }
  public IList<ShoppingCartItem> ShoppingCartItems{ get; set; }
}

public class ShoppingCartItem : ModelBase {
  public ShoppingCartItem ():base(null) {}

  public UserSession UserSession { get; set; }
  public Product Product { get; set; }         
}

答案 1 :(得分:1)

典型的购物车或客户订单示例更喜欢将UserSession(或Order)作为聚合的根。个别项目应该是本次会议/订单的子项。这取决于购物车中的单个商品是否应具有有意义的ID。我不喜欢,因为购物车中的5个小部件与另外5个小部件无法区分。因此,我会将购物车项目建模为价值对象的集合。

购物车商品的常见问题是他们是否应该包含价格。如果您包含价格,您的购物车将独立于产品价格的变化。如果您出于历史原因想要存放购物车,这是非常理想的,因为知道购物车中的物品在购买时的价格是多少是有价值的,而不是根据当前价格。

产品本身应该最终成为一种聚合体。周期。

现在,我不知道在LINQ to SQL中是否可以轻松实现所有这些,但您可以尝试。