zoukankan      html  css  js  c++  java
  • abp学习日志三(实体&聚合根)

    实体

    实体是DDD(Domain Driven Design)中核心概念.Eric Evans是这样描述实体的 “一个没有从其属性,而是通过连续性和身份的线索来定义的对象”

    实体通常映射到关系型数据库的表中。1

    Product实体

    按照项目结构,Product应该创建在Domain项目中,所以源码是这样的
    目录结构
    在这里插入图片描述
    代码

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Volo.Abp.Domain.Entities;
    
    namespace LY.Shop.Models
    {
        public class Product :Entity<Guid> // AggregateRoot<Guid>
        {
            public string ProductName { get; set; }
            public string ProductUnit { get; set; }
            public string ProductDescription { get; set; }
            public decimal ProductPrice { get; set; }
            public decimal StoreNumbers { get; set; } 
            public string Note { get; set; }
    
            protected Product()
            {
            }
            public Product(Guid id)
             : base(id)
            {
            }
        }
    }
    
    

    Entity类

    这个类是abp框架提供的,看一下他的源码

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Volo.Abp.MultiTenancy;
    
    namespace Volo.Abp.Domain.Entities
    {
        /// <inheritdoc/>
        [Serializable]
        public abstract class Entity : IEntity
        {
            /// <inheritdoc/>
            public override string ToString()
            {
                return $"[ENTITY: {GetType().Name}] Keys = {GetKeys().JoinAsString(", ")}";
            }
    
            public abstract object[] GetKeys();
        }
    
        /// <inheritdoc cref="IEntity{TKey}" />
        [Serializable]
        public abstract class Entity<TKey> : Entity, IEntity<TKey>
        {
            /// <inheritdoc/>
            public virtual TKey Id { get; protected set; }
    
            protected Entity()
            {
    
            }
    
            protected Entity(TKey id)
            {
                Id = id;
            }
    
            public bool EntityEquals(object obj)
            {
                if (obj == null || !(obj is Entity<TKey>))
                {
                    return false;
                }
    
                //Same instances must be considered as equal
                if (ReferenceEquals(this, obj))
                {
                    return true;
                }
    
                //Transient objects are not considered as equal
                var other = (Entity<TKey>)obj;
                if (EntityHelper.HasDefaultId(this) && EntityHelper.HasDefaultId(other))
                {
                    return false;
                }
    
                //Must have a IS-A relation of types or must be same type
                var typeOfThis = GetType().GetTypeInfo();
                var typeOfOther = other.GetType().GetTypeInfo();
                if (!typeOfThis.IsAssignableFrom(typeOfOther) && !typeOfOther.IsAssignableFrom(typeOfThis))
                {
                    return false;
                }
    
                //Different tenants may have an entity with same Id.
                if (this is IMultiTenant && other is IMultiTenant &&
                    this.As<IMultiTenant>().TenantId != other.As<IMultiTenant>().TenantId)
                {
                    return false;
                }
    
                return Id.Equals(other.Id);
            }
            
            public override object[] GetKeys()
            {
                return new object[] {Id};
            }
    
            /// <inheritdoc/>
            public override string ToString()
            {
                return $"[ENTITY: {GetType().Name}] Id = {Id}";
            }
        }
    }
    
    

    这份源码没有什么好分析的,就是做了一个基类,重写了几个常用的方法。

    聚合根

    “聚合是域驱动设计中的一种模式.DDD的聚合是一组可以作为一个单元处理的域对象.例如,订单及订单系列的商品,这些是独立的对象,但将订单(连同订单系列的商品)视为一个聚合通常是很有用的”2

    源码

    namespace Volo.Abp.Domain.Entities
    {
        /// <summary>
        /// Defines an aggregate root. It's primary key may not be "Id" or it may have a composite primary key.
        /// Use <see cref="IAggregateRoot{TKey}"/> where possible for better integration to repositories and other structures in the framework.
        /// </summary>
        public interface IAggregateRoot : IEntity
        {
    
        }
    
        /// <summary>
        /// Defines an aggregate root with a single primary key with "Id" property.
        /// </summary>
        /// <typeparam name="TKey">Type of the primary key of the entity</typeparam>
        public interface IAggregateRoot<TKey> : IEntity<TKey>, IAggregateRoot
        {
    
        }
    }
    
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using Volo.Abp.Auditing;
    using Volo.Abp.Data;
    
    namespace Volo.Abp.Domain.Entities
    {
        [Serializable]
        public abstract class AggregateRoot : Entity, 
            IAggregateRoot,
            IGeneratesDomainEvents, 
            IHasExtraProperties,
            IHasConcurrencyStamp
        {
            public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
    
            [DisableAuditing]
            public virtual string ConcurrencyStamp { get; set; }
    
            private readonly ICollection<object> _localEvents = new Collection<object>();
            private readonly ICollection<object> _distributedEvents = new Collection<object>();
    
            protected AggregateRoot()
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected virtual void AddLocalEvent(object eventData)
            {
                _localEvents.Add(eventData);
            }
    
            protected virtual void AddDistributedEvent(object eventData)
            {
                _distributedEvents.Add(eventData);
            }
    
            public virtual IEnumerable<object> GetLocalEvents()
            {
                return _localEvents;
            }
    
            public virtual IEnumerable<object> GetDistributedEvents()
            {
                return _distributedEvents;
            }
    
            public virtual void ClearLocalEvents()
            {
                _localEvents.Clear();
            }
    
            public virtual void ClearDistributedEvents()
            {
                _distributedEvents.Clear();
            }
        }
    
        [Serializable]
        public abstract class AggregateRoot<TKey> : Entity<TKey>, 
            IAggregateRoot<TKey>, 
            IGeneratesDomainEvents, 
            IHasExtraProperties,
            IHasConcurrencyStamp
        {
            public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
    
            [DisableAuditing]
            public virtual string ConcurrencyStamp { get; set; }
    
            private readonly ICollection<object> _localEvents = new Collection<object>();
            private readonly ICollection<object> _distributedEvents = new Collection<object>();
    
            protected AggregateRoot()
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected AggregateRoot(TKey id)
                : base(id)
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected virtual void AddLocalEvent(object eventData)
            {
                _localEvents.Add(eventData);
            }
    
            protected virtual void AddDistributedEvent(object eventData)
            {
                _distributedEvents.Add(eventData);
            }
    
            public virtual IEnumerable<object> GetLocalEvents()
            {
                return _localEvents;
            }
    
            public virtual IEnumerable<object> GetDistributedEvents()
            {
                return _distributedEvents;
            }
    
            public virtual void ClearLocalEvents()
            {
                _localEvents.Clear();
            }
    
            public virtual void ClearDistributedEvents()
            {
                _distributedEvents.Clear();
            }
        }
    }
    

    聚合根中除了继承IEntity接口外,还继承了其他几个接口(稍后再说),主要思想还是对IEntity再一次封装。

    官方框架已经给出了几种聚合根,扩展了不同的常用字段

    • CreationAuditedEntity 和 CreationAuditedAggregateRoot 实现了 ICreationAuditedObject 接口.
    • AuditedEntity 和 AuditedAggregateRoot 实现了 IAuditedObject 接口.
    • FullAuditedEntity and FullAuditedAggregateRoot 实现了 IFullAuditedObject 接口.

    额外属性

    关于额外属性使用到的情况非常少,大致就是通过json存在数据库中,映射到实体的ExtraProperties 属性,通过GetProperty 和 SetProperty方法进行取值和写值,可以通过HasProperty 判断是否存在该属性,也可以通过RemoveProperty 方法删除扩展属性中的某一个属性。


    1. 官网原话,值得推敲,Eric Evans的原话咱没看懂,但是 下面语句映射到关系数据库表中就清晰了许多。 ↩︎

    2. 聚合根其实就是对实体的进一步封装。继承自IEntity接口 ↩︎

  • 相关阅读:
    Leetcode Unique Binary Search Trees
    Leetcode Decode Ways
    Leetcode Range Sum Query 2D
    Leetcode Range Sum Query
    Leetcode Swap Nodes in Pairs
    Leetcode Rotate Image
    Leetcode Game of Life
    Leetcode Set Matrix Zeroes
    Leetcode Linked List Cycle II
    CF1321A
  • 原文地址:https://www.cnblogs.com/xiaoch/p/13417916.html
Copyright © 2011-2022 走看看