代码之家  ›  专栏  ›  技术社区  ›  Klaus Byskov Pedersen

在域类中约束字符串长度

  •  6
  • Klaus Byskov Pedersen  · 技术社区  · 15 年前

    我有一个持久性无知的域模型,它使用抽象存储库来加载域对象。 我的存储库(数据访问层(DAL))的具体实现使用实体框架从SQL Server数据库中获取数据。 数据库的许多varchar列上都有长度约束。 现在假设我有以下域类:

    public class Case
    {
        public Case(int id, string text)
        {
             this.Id = id;
             this.Text = text;
        }
    
        public int Id { get; private set; }
        public string Text { get; set; }
    }
    

    抽象存储库定义如下:

    public abstract class CaseRepository
    {
        public abstract void CreateCase(Case item);
        public abstract Case GetCaseById(int id);
    }
    

    这个 [text] sqlserver中表的列定义为 nvarchar(100)

    现在我知道我提到了我的领域类( Case )坚持是无知的,然而我觉得它允许是错误的 对于 text 由于实体框架,最终无法由具体的存储库实现保存的参数 将在分配时引发异常 文本 当实体框架生成的类超过100个字符时的属性。 所以我决定在域模型中检查这个约束,因为这允许我在尝试检查数据有效性之前检查数据的有效性。 将其传递给DAL,从而使错误报告更以域对象为中心。我想你可以说我可以检查一下 约束在我的构造函数和属性设置器中,但是由于我有数百个类都有类似的约束,所以我需要一个 更通用的解决问题的方法

    现在,我想到的是一个叫做 ConstrainedString ,定义如下:

    public abstract class ConstrainedString
    {
        private string textValue;
    
        public ConstrainedString(uint maxLength, string textValue)
        {
            if (textValue == null) throw new ArgumentNullException("textValue");
            if (textValue.Length > maxLength) 
                throw new ArgumentException("textValue may not be longer than maxLength", "textValue");
    
            this.textValue = textValue;
            this.MaxLength = maxLength;
        }
    
        public uint MaxLength { get; private set; }
    
        public string Value 
        { 
            get 
            {
                return this.textValue;
            } 
    
            set 
            {
                if (value == null)
                    throw new ArgumentNullException("value");
                if (value.Length > this.MaxLength) throw new ArgumentException("value cannot be longer than MaxLength", "value");
                this.textValue = value;
            } 
        }
    }
    

    此外,我还实现了 约束字符串 打电话 String100 :

    public class String100 : ConstrainedString
    {
        public String100(string textValue) : base(100, textValue) { }
    }
    

    从而导致 案例 就像这样:

    public class Case
    {
        public Case(int id, String100 text)
        {
             this.Id = id;
             this.Text = text;
        }
    
        public int Id { get; private set; }
        public String100 Text { get; set; }
    }
    

    现在,我的问题是:我是否忽略了一些内置类或其他一些我可以使用的方法?或者这是一个合理的方法?

    欢迎提出任何意见和建议。

    提前谢谢你

    3 回复  |  直到 15 年前
        1
  •  1
  •   Brownman98    15 年前

    我相信您的验证应该存在于您的域模型中。字段上的约束直接表示一些业务逻辑。最终,您必须在坚持之前进行验证。

        2
  •  0
  •   saret    15 年前

    我认为这取决于许多因素(以及一些个人偏好)。有时约束应该构成域对象的一部分-例如社会保险号/护照号…-它们通常具有固定的长度,不能作为域规则而改变——而不是数据持久性规则(尽管您也可以约束DB)。

    有些人更喜欢在他们的域模型中不进行这些类型的检查,而是在属性上具有类似于验证属性的内容,该属性可以由单独的验证器在域对象外部进行检查和执行。

    您的方法可能存在的问题(尽管不难解决)是让任何ORM/Mapper(如果您正在使用ORM/Mapper)知道如何将字符串映射到/从DB映射到约束字符串。

    ConstrainedString可能无法解决域对象具有有关约束的额外信息的问题,因为它可能需要构造ConstrainedString。

        3
  •  0
  •   kyoryu    15 年前

    如果你改变了一个案例的约束条件,你就有必要做一个新的——你已经改变了合同,旧的代码将不再知道它是否符合要求。

    不要担心存储库将允许或不允许的内容,而是定义 将允许在类中使用,并确保找到一种方法来使用将来更改为的任何存储库。您拥有自己的API—您的依赖项没有。