RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 956260
Accepted
Aldmi
Aldmi
Asked:2020-03-14 13:44:12 +0000 UTC2020-03-14 13:44:12 +0000 UTC 2020-03-14 13:44:12 +0000 UTC

C#。为什么 DDD 概念仅在 AgregationRoot 类型中描述使用抽象存储库?

  • 772

您好,我阅读了很多关于 DDD 的内容,遵循此概念的 RIGID 要求之一是仅在“聚合根”类型中使用存储库

 public abstract class Repository<T> where T : AggregateRoot
 {
   public T GetById(long id)
   {

   }      
   public void Save( T aggregateRoot)
   {

   }
 }

估值公司有领域模型(子领域)参考。域内部几乎没有业务逻辑,更需要具有 CRUD 操作的存储系统,但仍然可以区分成熟的域。
每个公司都包含要评估的房屋列表,每个房屋都有一组属性和业务逻辑。

PS 在示例中,我特意指定了一个简单的域模型(公共获取,为属性设置)。

базовые классы:
DomainEntity - содержит Id, объект мутабелен
DomainValueObject - НЕ содержит Id объект имутабелен.

public class Company : AggregateRoot
{    
    public string Name { get; set; } 
    public List<House> Houses { get; set; }    
}

public class House : DomainValueObject<House>
{     
    public string City { get; set; }                // Город
    public string District { get; set; }            // Район
    public string Street { get; set; }              // Улица
    public string Number { get; set; }              // Дом

    public int? Year { get; set; }                  // Год постройки
    public string MetroStation { get; set; }        // Ближайшая станция метро
    public string Geo { get; set; }                 // гео координаты
    public WallMaterial WallMaterial { get; set; }

    //бизнес логика......
}

public class WallMaterial : DomainValueObject<WallMaterial>
{
  public string Name { get; }  

  //бизнес логика......
}

在我的示例中,公司是聚合根

  1. 阅读这家公司的所有房屋。我将不得不拉动整个公司。

     var company= companyRepository.GetById(1);//Тут все зависимости (полный объект Домена)
     var houses= company.Houses;
    

DDD 对此有一个答案,对返回的对象执行 Dto(在特殊情况下)。

var housesDto= companyRepository.GetAllHousesDto(); 

返回的不是House,而是假的,为了符合这个概念——你不能部分地使用聚合,而只能通过聚合的根。houseDto 不是聚合的一部分,它是它的假冒。在这里,遵循这个概念是可以理解的,也不是很痛苦。

  1. 添加一个新家。

那些。添加新房子,我们通过聚合根进行交互:据我了解,存储库的这种使用是假设的

  var company= companyRepository.GetById(1);
  company.Houses.Add(newHouse); 
  companyRepository.Save(company);

那些。为了让我添加房子,我需要从数据库中提取公司,以及所有依赖项,添加房子然后保存。但这不是最优的,不是吗?为什么我需要额外的读取操作?

根据经典(如果您使用 EFcore 作为存储技术),我们这样做。

public async Task<bool> AddHouseInCompanyAsync(long companyId, House house)
{
    var efHouse = Mapper.Map<EfHouse>(house);
    efHouse.EfCompanyId = companyId;
    var res= await _context.Houses.AddAsync(efHouse);
    return res.State == EntityState.Added;
}

但这已经是违反 DDD 了,repository 方法使用了 House 部分。

怎样成为?总是通过公司更改对象(即通过聚合根)?还是 DDD 不适合我的任务,使用 CRUD 包装器更好吗?

c#
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Monk
    2020-03-14T14:16:12Z2020-03-14T14:16:12Z

    您误解了聚合根和其他实体的想法。

    如果一个实体可以没有根而存在,那么它本身就是一个根。

    如果房子可以在没有陪伴的情况下存在,它们也是根。

    您的主题的根示例:

    房屋地板 - 必须属于房屋根。公寓的居民既可以是子实体(例如,如果他们存在的事实很重要),也可以是根,例如,如果您以更复杂的方式使用它们。

    子实体可以与 DTO 类似地完成 - 实际上就是拥有一个子实体并在其中链接到另一个根。那些。company (root) - 有价值的 house (child),其中 child 类型的结构实际上包含对 house 的引用,可能还有一个要存储在数据库中的 id。然后,您可以为这样的孩子添加注释,某种 mb 评级,等等。同时,他们显然不属于这所房子。

    有条件的:

    class Company
    {
      List<CompanyHouse> Houses
    }
    
    class CompanyHouse
    {
      House
      Note
    }
    
    class House
    { ... }
    
    • 3
  2. Best Answer
    Mark Shevchenko
    2020-03-14T14:50:26Z2020-03-14T14:50:26Z

    首先,再看看你的程序的用例。也许您所在领域的房屋不是公司的一部分,而是独立的实体,它们自己的集合体。

    聚合是一个复合对象。例如,在在线商店中,聚合可以是订单实体,其中有单独的商品项目,如果没有订单,这些商品是无用的。商品项目的嵌套通过使用场景及其对应的屏幕形式间接确认。有一个显示所有商品项目的订单编辑表单,但没有用于编辑单独商品项目的表单。

    如果您的程序有用于编辑单个房屋的表格,而与公司没有任何联系,那么房屋是专用的聚合根。

    聚合可以相互引用,但只能通过标识符。他们不能互相支持。

    不需要返回来自存储库的 DTO。通常,DTO 在域之外的某个地方形成,以与应用程序的其他层进行通信。在域本身中,您只有实体和值对象组合成聚合。

    关于添加新房子时的额外读取操作。DDD 不是关于优化,而是关于简化架构、简化代码和简化维护。在 DDD 中,存储库从数据库中读取的不是实体的一部分,也不仅仅是实体,而是所有相关实体组合成一个聚合体。

    速度损失大吗?不。Fowler 描述了一种模式Remote Façade。使用它的原因是从远程计算机下载数据的特殊性,即存在所谓的延迟。在与服务器建立连接的时候,我们花一点时间,连接建立后,就可以高速接收数据了。因此,读取比我们可能需要的多一点的数据是有用的,它比读取我们需要的两倍或三倍的数据要快。

    另外,如果我们想从关系存储切换到文档存储,存储库的接口不会改变,领域层根本不需要改变。所以不要害怕阅读太多。

    EF 使用该方法加载相关数据Include。假设毕竟,房子是公司的一部分。然后,在加载公司时,需要加载关联的房屋:

    public class CompanyRepository
    {
        private readonly DbContextFactory dbContextFactory;
        private readonly DataMapper dataMapper;
    
        . . .
    
        public Company GetById(long id)
        {
            using (var dbContext = dbContextFactory.Create())
            {
                var companyData = dbContext.Companies
                                           .Include(x => x.Houses)
                                           .SingleOrDefault(x => x.Id == id);
    
                var company = dataMapper.FromData(companyData);
    
                return company;
            }
        }
    }
    

    由于该方法Include,不仅可以从数据库加载公司,还可以加载分配给它的房屋。在这段代码中,您可以看到我们正在加载 DTO 并将它们提供给 object DataMapper,该对象从它们构建整个聚合,包括House内部的实体Company。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5