C# 约束域类中的字符串长度
我有一个不知道持久性的域模型,它使用抽象存储库来加载域对象。 my repositories的具体实现(数据访问层(DAL))使用实体框架从sql server数据库获取数据。 数据库的许多varchar列都有长度限制。 现在假设我有以下域类:C# 约束域类中的字符串长度,c#,string,domain-model,C#,String,Domain Model,我有一个不知道持久性的域模型,它使用抽象存储库来加载域对象。 my repositories的具体实现(数据访问层(DAL))使用实体框架从sql server数据库获取数据。 数据库的许多varchar列都有长度限制。 现在假设我有以下域类: public class Case { public Case(int id, string text) { this.Id = id; this.Text = text; } pub
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);
}
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;
}
}
}
sqlserver中表的[text]
列定义为nvarchar(100)
现在我知道我提到我的域类(Case
)是不知道持久性的,但是我觉得它允许持久性是错误的
对于text
参数的值,由于实体框架
将text
属性指定给实体框架生成的类时,如果该类的长度超过100个字符,将引发异常。
因此,我决定在域模型中检查这个约束,因为这允许我在尝试创建之前检查数据的有效性
将其传递给DAL,从而使错误报告更加以域对象为中心。我想你会说我可以检查一下
约束在构造函数和属性设置器中,但由于我有数百个类都具有类似的约束,所以我需要一个
更通用的解决问题的方法
现在,我想到了一个名为ConstrainedString
的类,定义如下:
public abstract class CaseRepository
{
public abstract void CreateCase(Case item);
public abstract Case GetCaseById(int id);
}
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
的ConstrainedString
实现:
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; }
}
现在,我的问题是;我是否忽略了一些内置类或其他我可以使用的方法?或者这是一个合理的方法
欢迎提出任何意见和建议
提前谢谢我认为这取决于许多因素(以及一些个人偏好)。有时,约束应构成域对象的一部分-例如,社会安全号码/护照号码…-它们通常具有固定的长度,并且不能作为域规则(而不是数据持久性规则)而变化(尽管您也可以约束数据库) 有些人不希望在他们的域模型中有这样的检查,而是希望在属性上有类似于验证属性的东西,这些属性可以由单独的验证器从域对象外部检查和执行 您的方法可能存在的问题(虽然不难找到)是让任何ORM/Mapper(如果您使用的是ORM/Mapper)知道如何将字符串映射到db或从db映射到ConstrainedString
ConstrainedString可能无法解决域对象具有关于约束的额外信息的问题,因为它可能需要构造ConstrainedString。我认为验证应该驻留在域模型中。字段上的约束直接表示一些业务逻辑。最终,您必须在坚持之前进行验证。如果您更改案例的约束条件,那么您必须创建一个新的约束条件是有意义的——您已经更改了合同,旧代码将不再知道它是否满足要求
不要担心您的存储库将允许或不允许什么,而是定义您将在类中允许什么,并确保找到一种方法来处理将来更改为的任何存储库。您拥有自己的API—您的依赖项没有。+1个好问题—我经常想知道为什么BCL中不存在这样的类型。然而,我认为它有一种泄漏的抽象的味道,即你让关系数据库像那样影响域模型,或者这些约束有一个令人信服的域原因吗?@markseemann我同意你的看法,它有一种气味,而且大多数情况下,约束没有令人信服的域原因。基本上,它是一个遗留数据库模式,可能会从一些重构中受益,但这超出了我们当前的范围。但无论如何,我不认为我可以忽略模型中的这些约束,因为我想让数据验证成为模型的一部分,而不是存储库实现的一部分(我认为这是一个公平的目标)啊,遗留应用程序的奇妙世界。。。请考虑为实现这些约束的域模型创建一个装饰层,以保持您的域模型干净。请参阅此处了解更多详细信息:2D00-Bug\U 2D00\U 2D00\U Bug-Compatibility.aspx