【问题标题】:User entity in Clean Architecture清洁架构中的用户实体
【发布时间】:2021-01-05 10:48:51
【问题描述】:

我正在使用Jason Taylor Clean Architecture template 创建一个新的网络应用程序。我的应用程序必须支持帖子和用户实体,并且这些实体是相关的。一个用户可以创建多个帖子。

现在我想实现这个用户实体,以便使用我的应用程序的人可以使用这些用户登录。通常我只会使用 ASP.NET Core Identity,但因为我需要在 Domain 项目中引用该引用,并且该项目应该独立于任何框架,所以我不能这样做。

在这种情况下我该怎么办?

【问题讨论】:

    标签: c# .net asp.net-identity domain-driven-design clean-architecture


    【解决方案1】:

    如果您通过使用唯一标识符(例如 GUID、用户名、电子邮件等)在某个域实体中引用用户实体,那么您为什么会有一个域模型中的框架依赖项?

    只是不要使用框架层中的一些身份类作为类成员(字段),而是使用原始类型(例如字符串),甚至更好,一些自定义的value object 类,而不是代表我提到的用户身份唯一标识符。例如,您可以将其称为 UserId

    这样,您就将身份框架(可以视为基础架构层的一部分)与域层完全解耦。

    例如,如果您有一个 Order 域模型实体需要了解 Customer(或买方),则您不使用 ApplicationUser 来自身份层的类,而是仅使用与框架无关的用户 ID 类型 UserId

    您可以查看 Microsoft eshopOnWeb 了解如何做到这一点的一些示例。

    这个例子显示了Order domain entity

    public class Order : BaseEntity, IAggregateRoot
    {
        private Order()
        {
            // required by EF
        }
    
        public Order(string buyerId, Address shipToAddress, List<OrderItem> items)
        {
            Guard.Against.NullOrEmpty(buyerId, nameof(buyerId));
            Guard.Against.Null(shipToAddress, nameof(shipToAddress));
            Guard.Against.Null(items, nameof(items));
    
            BuyerId = buyerId;
            ShipToAddress = shipToAddress;
            _orderItems = items;
        }
    
        public string BuyerId { get; private set; }
        public DateTimeOffset OrderDate { get; private set; } = DateTimeOffset.Now;
        public Address ShipToAddress { get; private set; }
    
        // DDD Patterns comment
        // Using a private collection field, better for DDD Aggregate's encapsulation
        // so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection,
        // but only through the method Order.AddOrderItem() which includes behavior.
        private readonly List<OrderItem> _orderItems = new List<OrderItem>();
    
        // Using List<>.AsReadOnly() 
        // This will create a read only wrapper around the private list so is protected against "external updates".
        // It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance)
        //https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx 
        public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly();
    
        public decimal Total()
        {
            var total = 0m;
            foreach (var item in _orderItems)
            {
                total += item.UnitPrice * item.Units;
            }
            return total;
        }
    }
    

    在这里你可以看到,对用户的引用只是被一个字符串引用,这里是 BuyerId 属性,它没有将任何身份框架依赖引入到域层。如果在应用程序中的某个点需要用户身份对象,则可以从订单实体中查询此买方 ID,然后可以从域层之外的基础设施请求用户身份对象。

    Order 实体中应用的相同模式也可以应用于您的 Post 实体,例如通过使用类似 AuthorId 属性来引用用户,该属性可以是域层中定义的某个字符串或自定义类(值对象)。

    【讨论】:

      猜你喜欢
      • 2021-02-12
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多