首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >领域驱动的设计模型:客户服务案例,更多的非规范化,扁平化?

领域驱动的设计模型:客户服务案例,更多的非规范化,扁平化?
EN

Stack Overflow用户
提问于 2019-08-12 23:13:09
回答 1查看 203关注 0票数 1

在软件领域的商业模型中,领域模型是否通常更非规范化?我对这个特别的例子有疑问,

这是数据库中的客户服务案例。

在领域模型中,

是将所有字段放到一个类中,将CustomerService、CustomerServiceStatus、Type等组合成一个域类(一个平坦的宽表),还是保持原始数据模型结构的规范化?我相信CustomerService大小写是指向查找表、类型和状态等的聚合根吗?

数据库中的支架模型:

CustomerService Case

代码语言:javascript
复制
public class CustomerServiceCase
{
    public int CustomerServiceCaseId { get; set; }
    public int? CustomerServiceCaseStatusId { get; set; }
    public int? CustomerServiceCaseTypeId { get; set; }
    public int? LastModifiedByUserId { get; set; }
    public string CustomerServiceCaseNumber { get; set; }
    public DateTime? CustomerServiceCaseReceiveDate { get; set; }
    public DateTime? CustomerServiceCaseCreateDate { get; set; }

    public virtual CustomerServiceCaseStatus CustomerServiceCaseStatus { get; set; }
    public virtual CustomerServiceCaseType CustomerServiceCaseType { get; set; }

}

客户案例服务状态:

代码语言:javascript
复制
public class CustomerServiceCaseStatus
{
    public int CustomerServiceCaseStatusId { get; set; }
    public int? LastModifiedByUserId { get; set; }
    public string CustomerServiceCaseStatusCode { get; set; }
    public string CustomerServiceCaseStatusDescription { get; set; }
    public bool? Status { get; set; }
    public DateTime? CreateDate { get; set; }
    public DateTime? EffectiveStartDate { get; set; }
    public DateTime? EffectiveEndDate { get; set; }

    public virtual ICollection<CustomerServiceCase> CustomerServiceCase { get; set; }
}

客户服务案例类型:

代码语言:javascript
复制
public class CustomerServiceCaseType
{
    public int CustomerServiceCaseTypeId { get; set; }
    public string CustomerServiceCaseTypeCode { get; set; }
    public string CustomerServiceCaseTypeDescription { get; set; }
    public int? LastModifiedByUserId { get; set; }
    public bool? Status { get; set; }
    public DateTime? CreateDate { get; set; }
    public DateTime? EffectiveStartDate { get; set; }
    public DateTime? EffectiveEndDate { get; set; }

    public virtual ICollection<CustomerServiceCase> CustomerServiceCase { get; set; }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-13 00:14:12

我不确定我是否完全理解您的用例(比如需要单独存储CustomerServiceCaseType --我认为用例类型是有限的、定义得很好)。您可能在谈论用于存储CustomerServiceCaseType的主表,这是您在CustomerServiceCase类中所引用的。

尽管如此,让我从领域驱动的设计角度来概括地回答这个问题.

DDD本身并不关心数据如何存储在底层的持久化存储中,您的域模型应该与数据库无关,而不关心使用哪种基础结构。

所有与持久性相关的方面都应该由存储库处理。他们负责加载和持久化聚合,他们可以自由地以任何他们认为合适的方式来处理这个问题。应用程序服务通常使用这些存储库加载和持久化数据。

如果您使用像MongoDB这样的文档存储,您的聚合可能会存储为一个大文档,包括它自己的字段以及它所包含的实体和value对象的字段。因此,存储库只需对数据库进行一次查询。

如果使用RDBMS,可能最终会有一个非规范化结构。然后,您的存储库将执行多个调用或使用联接来加载数据。但无论何时加载聚合,它都会这样做。在加载聚合时,不应该懒洋洋地评估链接,因为聚合应该满足其封闭域对象的所有不变量。

下面是一个粗略的伪代码示例,它显示了域对象和数据存储之间的断开。

代码语言:javascript
复制
##############
Domain Classes
##############

class Order
{
    String order_number;
    List<OrderLine> order_lines;
    Timestamp ordered_on;
    String status;

    public Order build(params)
    {
        ...
    }
}

class OrderLine
{
    Integer product_id;
    Float price;
    Float quantity;
    Float tax;
    Float total;
    Integer sequence;
    String shipped_status;

    public OrderLine build(params)
    {
        ...
    }
}

###################
Application Service
###################

class OrderService
{
    Boolean place_order(params)
    {
        IRepository OrderRepository;  // Repository object is injected here

        new_order = Order.build(params);

        OrderRepository.create_new_order(new_order);
    }
}

##############
Infrastructure
##############

class OrderRepository extends IRepository
{
    public create_new_order(order)
    {
        // This is for illustration purposes only. You would probably use ORM tool to accomplish this.
        order_sql = "INSERT INTO order VALUES".format(order.order_number, order.ordered_on, ...)

        List<String> order_line_sqls;
        for each order_line in order.order_lines
        {
            order_line_sqls.append("INSERT into order_line VALUES(?, ?, ...)".format(order_line.product_id, order_line.price, ...))
        }

        // You would use a Unit of Work here
        result = db.exec(order_sql)
        if result = true:
            for each order_line_sql in order_line_sqls
            {
                result = db.exec(order_line_sql)
                if result != true:
                    raise Error("Transaction Failed")  // and rollback
            }
    }
}

下面是相反情况的一个例子,其中有一个域元素,但是存储在两个单独的表中(可能是出于性能、报告、数据导出等原因,尽管我在过去的项目中从未亲自做过):

代码语言:javascript
复制
class User
{
    String email;
    String username;
    String password;
    String address1;
    String address2;
    String address3;
    String city;
    String province;
    String zipcode;

    public User build(params)
    {
        ...
    }
}

class UserRepository extends IRepository
{
    public static persist_user(user)
    {
        // This is for illustration purposes only. You would probably use ORM tool to accomplish this.
        user_sql = "INSERT INTO user VALUES(?, ?, ?, ...)".format(user.email, user.username, user.password)
        address_sql = "INSERT INTO user_address VALUES(?, ?, ?, ...)".format(user.address1, user.city, ...)

        // You would use a Unit of Work here
        result = db.exec(user_sql)
        if result = true
        {
            result = db.exec(address_sql)
            if result != true
            {
                raise Error("Transaction Failed")  // and rollback
            }
        }       
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57469316

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档