领域驱动设计之代码优先-领域层设计-8 (翻译)
来源:互联网 发布:c语言点滴pdf微盘 编辑:程序博客网 时间:2024/05/16 08:57
3.9.- 领域实体的”数据注解“
目前为止我们让EF使用默认的协定发现模型,但有时候当我们的类不按照协定,我们需要进行更多的配置。
就像我们提到的,有两个选择;我们先看数据注解然后看”Fluent API“。
假设我们的BankAccount实体的Id属性不是”BankAccountId‟而是叫做“BankAccountNumber‟的属性。我们
试着运行应用但会得到InvalidOperationException,提示实体类型'BankAccount'没有定义键。因为EF不知道
”BankAccountNumber‟应该是主键。
为了解决这个问题,这里我们使用“数据注解”,需要添加一个引用:
项目 -> 添加引用...
选择 .NET 选项卡
选择 “System.ComponentModel.DataAnnotations”
点击 确定
在.cs文件顶添加using声明:
using System.ComponentModel.DataAnnotations;
考虑到这个命名空间不是EF而是.NET框架的一部分,“数据注解“也可以用在其他的技术,不只是EF。
如果EF需要其他的属性,可以在EntityFramework.dll找到,但是之后,这一步对持久化透明不利。
现在我们在”BankAccountNumber‟属性上加上主键的注解:
目前为止我们让EF使用默认的协定发现模型,但有时候当我们的类不按照协定,我们需要进行更多的配置。
就像我们提到的,有两个选择;我们先看数据注解然后看”Fluent API“。
假设我们的BankAccount实体的Id属性不是”BankAccountId‟而是叫做“BankAccountNumber‟的属性。我们
试着运行应用但会得到InvalidOperationException,提示实体类型'BankAccount'没有定义键。因为EF不知道
”BankAccountNumber‟应该是主键。
为了解决这个问题,这里我们使用“数据注解”,需要添加一个引用:
项目 -> 添加引用...
选择 .NET 选项卡
选择 “System.ComponentModel.DataAnnotations”
点击 确定
在.cs文件顶添加using声明:
using System.ComponentModel.DataAnnotations;
考虑到这个命名空间不是EF而是.NET框架的一部分,“数据注解“也可以用在其他的技术,不只是EF。
如果EF需要其他的属性,可以在EntityFramework.dll找到,但是之后,这一步对持久化透明不利。
现在我们在”BankAccountNumber‟属性上加上主键的注解:
//POCO Domain Entity using ‘Data Annotations’ // public class BankAccount : Entity { //Attributes // [Key] public int BankAccountNumber { get; set; } public string BankAccountNumber { get; set; } public decimal Balance { get; set; } public int CustomerId { get; set; } public bool Locked { get; set; } // //Domain Entity Logic // ... ... ... }
现在,我们可以使用BankAccountNumber作为数据库的主键。
注意:“数据注解”不是EF中的新概念。我们也可以使用在ASP.NET Dynamic Data 和“„WCF RIA Services‟中。
实际上,这些技术也使用相同的程序集和命名空间:System.ComponentModel.DataAnnotations
有很多其他的数据注解属性。下面展示了数据注解类的所有属性:
3.10.- 实体验证
从EF 4.1开始,这是EF第一次提供实体的验证。这个主意可能看起来很简单,但其实不是,它的实现对于
大多数从头开始的项目有很大的影响。
区分实体模型的验证和业务概念的验证很重要。一般来说,实体模型验证可以省去很多不必要的返工。
实体可以由几种方法实现,下面是主要的:
- 数据注解(EF)
- Fluent API (EF)
- 实现IValidatableObject
3.10.1.- 使用实体验证的数据注解
与其他任何主题的一样,尽管数据注解非常有吸引力,这也是一种使实体不纯净的方法,所以在领域驱动
设计中我们不推荐使用数据注解。我们推荐使用IValidatableObject或者“Fluent API‟。
下面是一个使用数据注解的一个实体示例:
这段代码的问题是当我们使用在EF程序集中定义的属性时,这样我们的实体就不是持久化透明了。
另一方面,如果我们使用.NET程序集中的属性数据注解时,就没有对EF的直接依赖。
如果我们不想再验证属性中有EF或MVC的依赖,我们会使用派生自ValidationAttribute的属性。
所以我们可以用下面的属性:
表 14.- System.ComponentModel.DataAnnotations 验证注解
验证属性 目的
StringLengthAttribute 字符串的最大曾度
RequiredAttribute 必须的元素
RegularExpressionAttribute 需要匹配指定的正则表达式
RangeAttribute 检查在一定区间的值
DataTypeAttribute 指定关联一个字段的额外类型的名字
CustomValidationAttribute 自定义验证
CustomValidationAttribute提供了自定义验证的代理;因此这会是领域没有外部依赖的一部分。
例如,下面我们定义信用卡号的自定义验证。
从EF 4.1开始,这是EF第一次提供实体的验证。这个主意可能看起来很简单,但其实不是,它的实现对于
大多数从头开始的项目有很大的影响。
区分实体模型的验证和业务概念的验证很重要。一般来说,实体模型验证可以省去很多不必要的返工。
实体可以由几种方法实现,下面是主要的:
- 数据注解(EF)
- Fluent API (EF)
- 实现IValidatableObject
3.10.1.- 使用实体验证的数据注解
与其他任何主题的一样,尽管数据注解非常有吸引力,这也是一种使实体不纯净的方法,所以在领域驱动
设计中我们不推荐使用数据注解。我们推荐使用IValidatableObject或者“Fluent API‟。
下面是一个使用数据注解的一个实体示例:
//Initial Customer Entity // public class Customer : Entity { public int CustomerId { get; set; } [Required()] [MaxLength(20)] public string FirstName { get; set; } [Required()] [StringLength(20)] public string LastName { get; set; } public string City { get; set; } public string Street { get; set; } public string ZipCode { get; set; } }
这段代码的问题是当我们使用在EF程序集中定义的属性时,这样我们的实体就不是持久化透明了。
另一方面,如果我们使用.NET程序集中的属性数据注解时,就没有对EF的直接依赖。
如果我们不想再验证属性中有EF或MVC的依赖,我们会使用派生自ValidationAttribute的属性。
所以我们可以用下面的属性:
表 14.- System.ComponentModel.DataAnnotations 验证注解
验证属性 目的
StringLengthAttribute 字符串的最大曾度
RequiredAttribute 必须的元素
RegularExpressionAttribute 需要匹配指定的正则表达式
RangeAttribute 检查在一定区间的值
DataTypeAttribute 指定关联一个字段的额外类型的名字
CustomValidationAttribute 自定义验证
CustomValidationAttribute提供了自定义验证的代理;因此这会是领域没有外部依赖的一部分。
例如,下面我们定义信用卡号的自定义验证。
public static ValidationResult ValidateCCNumber(string creditCardNumber) { bool result; //TODO: Validate DNI ... CC validation algorithm ... ... if (!result) { return new ValidationResult("Invalid CC number", new string[] { "CC" }); } else return null; }然后,我们会这样修改实体。
[CustomValidation(typeof(OrderValidation),"ValidateCCNumber")] public string CreditCardNumber { get; set; }
总的来说,最解耦的方法是在领域模型层使用IvalidatableObject或在数据访问层实现”Fluent API‟。
3.10.2.- 使用IValidatableObject实体验证
这个方法是非常持久化透明的,在领域模型层的验证代码没有外部依赖。
该方法尤其适用于需要验证多个实体状态的业务验证。通常,这种验证视为“类级别验证”。
为了实现这样的验证,EF产品组给予POCO代码优先实体IValidatableObject的支持,所以我们的实体可以
实现该接口来做更复杂的验证。
对于这样验证重要的一点是只有在没有"注解级别“错误时才会执行。
下面的代码展示了实现IvalidatableObject的验证
public abstract class Product :Entity,IValidatableObject { //... //Ommitted Product Entity properties and methods //... //... public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { var validationResults = new List<ValidationResult>(); if (String.IsNullOrEmpty(Title) || String.IsNullOrWhiteSpace(Title)) validationResults.Add(new ValidationResult(Messages. validation_ProductTitleCannotBeNullOrEmpty, new string[] { "Title" })); if (String.IsNullOrEmpty(Description)|| String. IsNullOrWhiteSpace(Description)) validationResults.Add(new ValidationResult( Messages.validation_ProductDescriptionCannotBeNullOrEmpty, new string[] { "Description" })); if (AmountInStock < 0) validationResults.Add(new ValidationResult(Messages. validation_ProductAmountLessThanZero, new string[] { "AmountInStock" })); if (UnitPrice < 0) validationResults.Add(new ValidationResult(Messages. validation_ProductUnitPriceLessThanZero, new string[] { "UnitPrice" })); return validationResults; } }
- 领域驱动设计之代码优先-领域层设计-8 (翻译)
- 领域驱动设计之代码优先-领域层设计-1 (翻译)
- 领域驱动设计之代码优先-领域层设计-2 (翻译)
- 领域驱动设计之代码优先-领域层设计-3 (翻译)
- 领域驱动设计之代码优先-领域层设计-4 (翻译)
- 领域驱动设计之代码优先-领域层设计-5 (翻译)
- 领域驱动设计之代码优先-领域层设计-6 (翻译)
- 领域驱动设计之代码优先-领域层设计-7 (翻译)
- 领域驱动设计之代码优先-领域层设计-9 (翻译)
- 领域驱动设计之代码优先-领域层设计-10 (翻译)
- 领域驱动设计之代码优先-领域层设计-11 (翻译)
- 领域驱动设计之代码优先-架构描述 (翻译)
- 领域驱动设计之代码优先-架构描述 (通译)
- 领域驱动设计案例之领域层框架搭建
- 领域驱动设计之领域模型
- 领域驱动设计之领域模型
- 领域驱动设计之领域模型
- 领域驱动设计之领域模型
- H.264学习(一)
- Android 利用程序实现GPS的打开或关闭
- 爱是瞬间的美,情是永恒的痛
- WTL创建密码框
- 爱是瞬间的美,情是永恒的痛
- 领域驱动设计之代码优先-领域层设计-8 (翻译)
- 介绍MATLAB 的两种基本绘图功能:二维平面图形和三维立体图形
- 领域驱动设计之代码优先-领域层设计-9 (翻译)
- Newtonsoft.Json 应用
- java单选框
- 如何去掉grouped样式UITableView中cell的边框和背景
- C++入门解惑——浅析cout
- 使用HTML5开发Android本地应用(一)
- 【文章推荐】消息推送解决方案