【问题标题】:Complex domain model based on companies and not users基于公司而非用户的复杂领域模型
【发布时间】:2011-07-20 20:22:24
【问题描述】:

我有一些不同类型的公司可以访问我的网络应用程序,例如

不同类型的公司:

客户 供应商 代理

每个人在数据库中都有自己的表,链接到存储所有常见数据的主表 Company,例如地址、电话、电子邮件、TypeOfCompany 以及相关表(客户等)的 FK...

在整个应用程序中处理此 OO 的最佳方式是什么?

我目前正在做类似的事情:

public class CompanyDTO
{
  public int Id {get;set;}
  public string Name {get;set;}
  public Address Address {get;set;}
  public string Type {get;set;} //type of company
  //etc...
}

然后从该类继承并添加其他属性,例如

public class ClientDTO : CompanyDTO
{
 public string Key {get;set;}
 public Address Billing {get;set;}
}

但是我有时会发现它有问题,例如

  1. 供应商用户想要访问:AllCompanies,- 显示所有公司的列表
  2. 然后供应商公司的用户想要查看特定公司的详细信息,现在如果是客户,我需要显示 ClientDTO 还是 SupplierDTO?在这种情况下,我想展示特定公司的详细信息

处理这个问题的最佳方法是什么?

例如GetCompanyByID(int companyid);GetClientByID(int clientid); 在这两种情况下我应该返回什么类型的对象,假设我在这两种情况下都需要客户详细信息...

【问题讨论】:

    标签: c# design-patterns domain-driven-design domain-model


    【解决方案1】:

    有趣的是,数据库不理解派生、聚合和封装等 OO 实践。这是一个不幸的失败,但仍然只是整体称为“database impedance mismatch”的一部分。

    您尝试做的事情很常见,有几种解决方案......

    首先是存储数据模型的选择。基本上有三种可能。

    1. 按照您的操作拆分表。
    2. 为同一个表中的所有派生类型声明所有字段。
    3. 使用 blob 字段 (json/xml/whatever) 来容纳不常见的字段。

    其次是您提出的问题,即从数据库中请求数据。主要是围绕“常见”基本类型列表的请求以及如何访问它们不共享的不常见字段。同样有几种可能性。

    1. 列出基本类型时,仅返回那些公共字段。然后一次性发出后续查询以延迟加载其他字段。
    2. 在列出基本类型时,所有其他所需的表也都外部连接到主表,以确保所有字段都可用于完全实例化对象模型。
    3. 列出基本类型时,会返回多个结果集,每个结果集可能需要一个“子类型”表。然后,客户端将记录拼凑在一起构建对象模型,直到完成。

    不是一个详尽的列表,而是一个开始。出于这个原因,我个人更喜欢避免像您描述的那样的数据模型。本质上,我的偏好是让数据模型定义所有字段的联合(模型#2),然后使用业务层来确定公开、验证、需要哪些属性等。我还使用了上面的模型#3,使用多个值的 blob 字段,它也可以根据需要运行良好。模型 #3 优于 #2 的唯一缺点是您将无法对这些字段进行查询或排序。最终,这两种方法仍然需要涉及的业务逻辑层知道要公开哪些数据。

    记住数据库是愚蠢的,这样对待它们,你会相处得很好。 (注意:此建议不适用于人,仅适用于数据库)

    【讨论】:

    • 一个很好的答案,虽然我个人永远不会建议#3 - 它违反了规范化原则并且不允许像你说的那样进行查询或排序,这是一个预先让步的重大决定。我支持你的选项 #2。
    • 这些字段对我个人来说必须是可查询的,因此为什么它们在表内有自己的字段...
    • 违反规范化原则是我每天的任务。我已经变得如此熟练,以至于现在我什至无法考虑我的一个表有多少违规行为,而我的整个架构要少得多。然而,当其他人抱怨 150 行 SQL 语句和 25 个表连接时,我的应用程序继续快速运行并很好地扩展。恕我直言,规范化是世界上教一个初出茅庐的程序员最糟糕的事情。顺便说一句,自 97 年以来我一直在编写数据库应用程序,我花了 8 或 9 年的时间才弄清楚规范化的原因。
    • 规范化是世界上教一个初出茅庐的程序员最糟糕的事情 - 不,还有更糟糕的事情。我宁愿让它们在正确的轨道上开始——因为规范化总的来说是一件好事——然后说明非规范化模式在你遇到它们时更合适的情况。
    【解决方案2】:

    我想访问:AllCompanies,- 显示所有公司的列表

    当您想要一份公司列表时,您不是要求提供CompanyDTO 实例描述的一般细节吗?也许您的数据访问(服务、存储库等)可能如下所示:

    public class CompanyRepository : ICompanyRepository
    {
        public IEnumerable<CompanyDTO> GetCompanies()
        {
            // get companies and map them to CompanyDTO objects as necessary
        }
    }
    

    那你问了(嗯,有问号)

    然后我想查看特定公司的详细信息,现在如果是客户我需要显示 ClientDTO 或 SupplierDTO?

    我假设这将是一个单独的视图,或者至少分解为一个单独的部分视图。但是,您可以使用Display Templates 来描述您的子公司类型,因为您已经在上面描述了继承。

    我会假装你向我们展示了你的控制器,它看起来像这样:

    public class CompanyController : Controller
    {
        public ActionResult Details(int id)
        {
            CompanyRepository repo = new CompanyRepository();
            return View(repo.GetCompanyById(id));
        }
    }
    

    然后,添加一个名为 Details 的强类型视图,该视图继承了 CompanyDTO 对象,并添加对 Html.DisplayForModel() 的调用:

    <%--some scaffolded code ommitted for brevity--%>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    
        <%= Html.DisplayForModel() %>
    
    </asp:Content>
    

    然后,这就是显示模板的用武之地。添加文件夹

    ~/Views/Company/DisplayTemplates
    

    然后将 3 个强类型部分 视图添加到该文件夹​​ - 每个子类型一个。 Visual Studio 将帮助您:

    1. 右击DisplayTemplates文件夹 --> 添加视图...
    2. 将其命名为“ClientDTO”(这很重要)
    3. 勾选“创建局部视图”
    4. 勾选“创建强类型视图”
    5. 选择ClientDTO
    6. 选择Details 查看内容(这将为您提供一些自动生成的标记)
    7. 点击添加

    对其他子类型重复此过程,将根据传递给您的详细信息视图的模型的 类型呈现正确的模板。

    【讨论】:

    • David - 你为什么回答关于 MVC 的问题?这不是批评,我只是对问题的哪个元素给了你这个建议感兴趣..
    • @MalcomTucker 嗯...我发誓这个问题上有一个 asp.net-mvc-2 标签。
    • 啊,好吧,我以为我错过了什么!删除它可能是正确的决定,它并不需要 UI 解决方案 (IMO)
    • @Haroon 很高兴听到这个消息——如果我能以任何方式详细说明或审查,请告诉我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多