1

我有一个通过 Onion 架构和 DDD 实现的解决方案,例如eShopOnContainers

但是我有一个问题要做,所以我决定与你分享。我试图通过一个例子来解释它。你想我有一个像IOrderRepositoryinterface这样的名字IOrderRepository

public interface IOrderRepository : IRepository<Order>
    {
        Order Add(Order order);               // first issue
        Task<OrderDTO> GetAsync(int orderId); // second issue
    }

首要问题

我实现了 OrderRepository 之Add类的方法,但我需要在方法中使用额外的参数,例如以下代码:Add

public Order Add(Order order, int par1, int par2)
    {
        // I need a DTO to persist order  
        OrderDTO orderDTO = new OrderDTO({Order = order, Par1 = par1, Par2 = par2 });

        // Call a method with orderDTO parameter as a service to insert order             
    }

如您所见,IOrderRepository由于我需要额外的参数,因此实施是错误的。

第一个问题的错误解决方案

我有两个错误的解决方案来解决这个问题。

1- 调整IOrderRepository

通过添加如下参数来更改输入IOrderRepository参数:

public interface IOrderRepository : IRepository<Order>
    {
        Order Add(Order order, int par1, int par2);           
    }

据我所知,没有任何业务规则par1 and par2来实现 DDD,首先我应该指定IRepository,但是通过使用这个解决方案,我将基础设施层问题放在了错误架构的领域层中。

2-IOrderRepository进入基础设施层

我可以放入IOrderRepository基础设施层,但这是另一个错误的架构,因为据我所知,这种接口应该位于Domain layer.

我的第一个问题

1-如何在基础设施层的存储库的方法中使用额外的参数来实现参数与域层之间没有任何连接的域层的IRepository?

第二期

正如您在 中看到的IOrderRepository,我应该实现GetAsync返回OrderDTO包含Order和额外参数的方法。据我所知,我不能在域层中使用 DTO(数据传输对象)。我想不出办法来处理它。

我的第二个问题

2-我如何返回OrderRepository基础设施层中的 DTO 方法,但我不能IOrderRepository在域层中应用它。

在此先感谢您的时间。

4

3 回答 3

4

由于我们没有关于您为什么需要这两个参数的上下文,您还可以使用另外两个可能不那么侵入性的选项:-

首先,您可以拥有一个继承自Order并包含这些额外参数的新类:

public class MyOrder : Order
{ 
    int Par1 { get; set; }
    int Par2 { get; set; }
}

然后,在您的存储库中,您可以将其投射或安全投射到MyOrder该类。

另一种选择是使用扩展方法IOrderRepository

public static class SomeExtension
{
    public static void MySave(this IOrderRepository repository, int par1, int par2)
    {
        // do things
    }
}

也许这些在您的场景中不起作用,所以 YMMV。无论哪种情况,您都可能需要重新审视您的设计。

于 2019-06-19T13:45:55.440 回答
1

这看起来像一个 XY 问题,您的代码存在几个问题,您没有很好地解释问题,您只是解释了您想要的答案。

如果您查看链接到的代码,这是他们对 IRepository 的实现(我省略了不相关的方法来回答问题)

public interface IOrderRepository : IRepository<Order>
{
    Order Add(Order order); 
    Task<Order> GetAsync(int orderId);
}

在这里您可以看到他们清除的只是在订单上操作而不是 DTO 但是在您提供的实现中,您返回 DTO,如果没有链接单独的参数,这是不可能返回的

public interface IOrderRepository : IRepository<Order>
{
    Order Add(Order order);               
    Task<OrderDTO> GetAsync(int orderId); 
}  

你可能想要一个更复杂的架构,但没有足够的空间来布局完整的代码,所以我只会给你一个 Gyst Take 参数 Order 和 OrderDTO,并添加用于处理适应的基础设施

public interface IOrderRepository : IRepository<OrderDTO>
{
    OrderDTO Add(OrderDTO order); 
    Task<OrderDTO> GetAsync(int orderId);
}


public interface IAdaptable<TEntity, TDTO>
{
    TDTO ToDTO(TEntity entity);
    TEntity ToEntity(TDTO entityDTO, TEntity entity);
}

然后你需要一个基类来处理操作

public class BaseRepository<TEntity, TDTO> : IRepository<TEntity, TDTO>
    where TEntity : class, new()
{
     protected DbContext _context;
     protected IAdaptable<TEntity, TDTO> _adapter;
     public BaseRepository(DbContext context, IAdaptable<TEntity, TDTO> adapter)
     {
         this._context = context;
         this._adapter = adapter;
     }

     public TDTO Add(TDTO dto)
     {
        var entity = this._adapter.ToEntity(dto, new TEntity());
        this._context.Set<TEntity>().Add(entity);
        this._context.SaveChanges();

         return this._adapter.ToDTO(entity);
     }
}

现在您的基础存储库处理了您的大部分基础逻辑,您所要做的就是实现适配器,例如 Automapper 是一个不错的方法。

public class OrderAdapter : IAdaptable<Order, OrderDTO>
{
    IOtherDependentService _service;
    public OrderAdapter(IOtherDependentService service)
    {
        this._service = service;
    }

    OrderDTO ToDTO(Order order)
    {
       var orderPars = this._service.GetParsFromOrder(order.Id);
       var dto = new OrderDTO{
           Order = order, 
           Pars1 = orderPars.Pars1, 
           Pars2 = orderPars.Pars2
       };

       return dto;

    }

    //.... Implement the rest of the interface you get the picture
}

你应该可以从中得到 Gyst

于 2019-06-25T05:41:21.987 回答
0

参数中有什么?

如果它是订单的一部分,您的模型应该反映这一点。不得不接受所谓不相关的信息通常是一个非常明显的迹象,表明您的对象模型没有反映现实。这是 DDD 的重点。

如果它们是在存储库的整个生命周期中保持一致的其他事物,请将它们作为参数提供给存储库的构造(依赖注入)。然后它可以在内部使用这些来存储项目。

这是后者的一个例子——假设我有一家电子商务公司,我们有一个旧订单系统需要通知旧订单,但在新订单中不再需要它。我可以将这种行为封装在我的工厂中,例如(C# 示例):

public class OrderRepository : IOrderRepository
{
     private LegacyOrderService _legacyService;
     public OrderRepository(LegacyOrderService legacyService){
          _legacyService = legacyService;
     }

     public Order Add(Order order){
         if(!order.isNewOrder){
              _legacyService.notify(order.id);
         }

         # do the rest
     }
}
于 2019-06-21T21:32:19.647 回答