0

在一位同事的帮助下,我们想出了一种将业务规则应用于实体的方法。我们正在向实体注入定义规则的合同。虽然这本身很好用,但 Entity Framework 并不喜欢它。原因是我们在基础实体的构造函数中引入了一个参数。EF 不喜欢参数化构造函数,这是有充分理由的。下面是一些演示合约的代码:

     /// <summary>
    /// Class to define the Base Entity that will be inherited by All Entities with an Id of Guid
    /// </summary>
    public abstract class BaseEntity
    {
        protected BaseEntity(IEntityContract entityContract)
        {
            if(!entityContract.IsValid())
            {
                throw new EntityContractException();
            }
            DateCreated = DateTime.Now;
            DateModified = DateTime.Now;
        }

        /// <summary>
        /// Key Field for all entities
        /// </summary>
        /// 
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public Guid Id { get; set; }

        /// <summary>
        /// Date entity was created
        /// </summary>
        public DateTime DateCreated { get; set; }

        /// <summary>
        /// Last date Modified
        /// </summary>
        public DateTime DateModified { get; set; }
        /// <summary>
        /// keep track of Row Version used for concurrency
        /// </summary>
        [Timestamp]
        public Byte[] RowVersion { get; set; }

    }

    public class Address : BaseEntity
    {
        public Address(IEntityContract entityContract)
            : base(entityContract)
        {
        }

        public string Name { get; set; }
        public string Line1 { get; set; }
        public string Line2 { get; set; }
        public string City { get; set; }
        public string PostalCode { get; set; }

        public Guid RegionId { get; set; }
        public virtual Region Region { get; set; }


    }

    public abstract class BaseEntityContract<TEntity> : Interfaces.IEntityContract where TEntity : BaseEntity
    {
        private readonly List<string> _errors = new List<string>();
        private readonly List<BusinessRule<TEntity>> _businessRules = new List<BusinessRule<TEntity>>();

        public bool IsValid()
        {
            var contractIsvalid = true;

            foreach (var rule in _businessRules.Where(br => !br.Rule((TEntity)(Interfaces.IEntityContract)this)))
            {
                _errors.Add(rule.Description);
                contractIsvalid = false;
            }

            return contractIsvalid;
        }


        /// <summary>
        /// Adds a business rule to be used in validating the {TEntity} contract.
        /// </summary>
        /// <param name="rule">The function used to represent the business rule.</param>
        /// <param name="description">The descriptive message describing the rule.</param>
        protected void RegisterBusinessRule(Func<TEntity, bool> rule, string description)
        {
            _businessRules.Add(new BusinessRule<TEntity>(rule, description));
        }
    }


    public class AddressEntityContract : BaseEntityContract<Address>
    {
        public AddressEntityContract()
        {
            this.RegisterBusinessRule(a => a.Line1.length > 0, "Line 1 cannot be empty.");
        }
    }

我知道您可以通过流畅的 API 将一些验证直接应用于实体的属性,但这似乎与持久性相关而不是与我相关的业务。例如,在数据方面,我们假设描述列可以是 255 个字符,但业务需要只允许 100 个字符。我们可以在创建数据库/模型的过程中定义初始持久性相关的属性。我真的很喜欢合同的想法,但看不到它与实体框架一起使用。我唯一的另一个想法是让合同(或商务舱)位于实体和 EF 之间。我的 DAL 会将实体传递给业务规则类,如果一切正常,则将它们传递给我的服务,反之亦然。我希望有人在适用于实体的业务规则方面有比这更好的方法

4

1 回答 1

0

昨晚我对此有几个想法。

一种选择是处理 DTO 内部的规则,而不是实际的域实体。这假设域实体始终有效,要么来自应用程序(通过 DTO),要么由实体框架构建(来自数据存储)。

另一种选择是将合同视为实体并将它们传递给实体框架,然后将合同注入域中。

于 2011-05-13T11:56:55.863 回答