原帖地址:http://www.cnblogs.com/happyframework/p/3158338.html
背景
见过很多框架(包括我自己的)都会在实体的定义中包含一个IsValid()方法,用来判断实体的合法性,是否应该这样设计呢?本文就这个问题介绍一点想法,希望大家多批评。
实体能否处于“非法”状态?
实体是否应该包含IsValid()方法的深层次问题是:“实体能否处于非法状态?”。我们来定义一些术语,接下来我就引用这些术语:
- A模式:实体允许处于非法状态,但是实体要包含一个IsValid()方法进行校验。
- B模式:实体不允许处于非法状态,业务逻辑必须保证这一点。
关于A模式我不想多说了,A模式本身没有问题的,今天重点说说如何实现B模式。
如何实现B模式?
最好的说明就是写一个例子,下面是我们例子的需求:
这个例子非常简单,也具有代表性,可以进一步抽象为:
- xxx属性不能为空,聚合自身的验证。
- xxx属性必须唯一,跨聚合验证。
让我们一个一个来。
xxx属性不能为空,聚合自身的验证。
聚合本身应该负责自己状态的完整性,反射可能会绕过这些验证,使用类似AutoMapper的工具需要注意(我已经处理了)。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using Happy.Domain;
8 using Happy.Domain.Tree;
9 using Happy.Example.Events.TestGrids;
10
11 using Happy.Infrastructure;
12
13 namespace Happy.Example.Domain.TestGrids
14 {
15 public partial class TestGrid : AggregateRoot<Guid>
16 {
17 public System.Int64? BigIntField { get; set; }
18 public System.Boolean? BitField { get; set; }
19 public System.DateTime? DateField { get; set; }
20 public System.DateTime? DateTimeField { get; set; }
21 public System.Decimal? DecimalField { get; set; }
22 public System.Double? FloatField { get; set; }
23 public System.Int32? IntField { get; set; }
24 public System.Decimal? MoneyField { get; set; }
25 public System.Decimal? NumericField { get; set; }
26 public System.String NVarcharField { get; private set; }
27 public System.Single? RealField { get; set; }
28 public System.TimeSpan? TimeField { get; set; }
29 public System.Byte[] TimestampField { get; set; }
30
31 public void SetNVarcharField(string value)
32 {
33 value.MustNotNullAndNotWhiteSpace(value);
34
35 this.NVarcharField = value;
36 }
37
38 internal void PublishCreatedEvent()
39 {
40 this.PublishEvent(new TestGridCreatedEvent());
41 }
42 }
43 }
xxx属性必须唯一,跨聚合验证。
仓储负责判断唯一性,应用服务负责验证,注意:是先验证,然后修改的实体。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using Happy.Command;
8 using Happy.Application;
9 using Happy.Example.Domain.TestGrids;
10 using Happy.Example.Commands.TestGrids;
11
12 namespace Happy.Example.Application.TestGrids
13 {
14 public class TestGridCommandHandler : ApplicationService,
15 ICommandHandler<CreateTestGridComamnd>,
16 ICommandHandler<UpdateTestGridComamnd>,
17 ICommandHandler<DeleteTestGridComamnd>
18 {
19 public void Handle(CreateTestGridComamnd command)
20 {
21 var testGridService = this.Service<TestGridService>();
22
23 testGridService.CheckNVarcharFieldUnique(command.NVarcharField);
24 var testGrid = command.CreateTestGrid();
25
26 testGridService.Create(testGrid);
27 command.Result = testGrid.Id;
28 }
29
30 public void Handle(UpdateTestGridComamnd command)
31 {
32 var testGridService = this.Service<TestGridService>();
33
34 var testGrid = testGridService.LoadAndDetach(command.Id);
35 if (testGrid.NVarcharField != command.NVarcharField)
36 {
37 testGridService.CheckNVarcharFieldUnique(command.NVarcharField);
38 }
39 command.UpdateTestGrid(testGrid);
40
41 testGridService.Update(testGrid);
42 }
43
44 public void Handle(DeleteTestGridComamnd command)
45 {
46 this.Service<TestGridService>().Delete(command.Id);
47 }
48 }
49 }
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using AutoMapper;
8
9 using Happy.Infrastructure;
10 using Happy.Infrastructure.AutoMapper;
11 using Happy.Command;
12 using Happy.Example.Domain.TestGrids;
13
14 namespace Happy.Example.Commands.TestGrids
15 {
16 public class UpdateTestGridComamnd : ICommand, IHasIdProperty<Guid>
17 {
18 public Guid Id { get; set; }
19 public System.Int64? BigIntField { get; set; }
20 public System.Boolean? BitField { get; set; }
21 public System.DateTime? DateField { get; set; }
22 public System.DateTime? DateTimeField { get; set; }
23 public System.Decimal? DecimalField { get; set; }
24 public System.Double? FloatField { get; set; }
25 public System.Int32? IntField { get; set; }
26 public System.Decimal? MoneyField { get; set; }
27 public System.Decimal? NumericField { get; set; }
28 public System.String NVarcharField { get; set; }
29 public System.Single? RealField { get; set; }
30 public System.TimeSpan? TimeField { get; set; }
31 public System.Byte[] TimestampField { get; set; }
32 public byte[] OptimisticKey { get; set; }
33
34 internal void UpdateTestGrid(TestGrid testGrid)
35 {
36 Mapper.Map(this, testGrid);
37 testGrid.SetNVarcharField(this.NVarcharField);
38 }
39
40 static UpdateTestGridComamnd()
41 {
42 var map = Mapper.CreateMap<UpdateTestGridComamnd, TestGrid>();
43 map.ForMember(x => x.Id, m => m.Ignore());
44 map.IgnoreNotPublicSetter();
45 }
46 }
47 }
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using Happy.Example.Domain.TestGrids;
8
9 namespace Happy.Example.Application.TestGrids
10 {
11 public partial class TestGridService
12 {
13 protected override void AfterCreate(TestGrid aggregate)
14 {
15 base.AfterCreate(aggregate);
16
17 aggregate.PublishCreatedEvent();
18 }
19
20 internal void CheckNVarcharFieldUnique(string value)
21 {
22 if (!this.Repository.IsNVarcharFieldExist(value))
23 {
24 throw new InvalidOperationException("NVarcharField必须唯一");
25 }
26 }
27 }
28 }
备注
一些好的资源:
本文链接:http://www.cnblogs.com/happyframework/p/3158338.html,转载请注明。
分享到:
相关推荐
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.scheme.Scheme; ...
Chapter 1: Introducing the ADO.NET 4.0 Entity Framework..................................1 Chapter 2: The Entity Data Model ........................................................13 Chapter 3: The ...
Packtpub.WCF.4.5.Multi-Layer.Services.Development.with.Entity.Framework.Dec.2012
org.apache.http.entity.mime apache的android jar包
This book is a step-by-step tutorial to guide you through learning WCF, Entity Framework, LINQ, and LINQ to Entities. You will be guided to create six WCF and Entity Framework solutions from scratch, ...
修复错误:tk.mybatis.mapper.MapperException: 无法获取实体类com.xxx 对应的表名!
org.apache.http.legacy.jar和org.apache.http.entity.mime4.1.2.jar两个jar包 欢迎下载
本案例是微软EntityFrameworkCore的一个仓储模式实现,这个仓储库不是我写的,而是使用了一个老外写的EntityFrameworkCore.Data.Repository。 IDE环境:VS2022 开发框架:ASP.NET Core6.0 WebApi ORM框架:Entity...
Apress.Pro.Entity.Framework.4.0.Mar.2010.pdf
想学Entity.Framework.DbContext吗?想学单元测试吗?想知道Entity.Framework如何实现Unit Of Work,Reposit模式吗?这本书应有尽有.
Z.EntityFramework.Extensions 破解 注册机,详细破解方法
------------------EntityBean配置(连接Oracle)------------- 1.One Table 1.1 添加数据源 在: \jboss-4.2.2.GA\docs\examples\jca\oracle-ds.xml,拷贝oracle-ds.xml 到: \jboss-4.2.2.GA\server\all\deploy 配置...
有使用 Entity Framework Core - Code First 的经验。 有使用 ASP.NET Core 和 Rest API 的经验 可选:有使用 Docker 的经验 指示: 设置 MS SQL Server 以运行数据库 使用 Customer.API 项目启动项目 结构: ...
Code-First.Development.with.Entity.FrameworkCode-First.Development.with.Entity.FrameworkCode-First.Development.with.Entity.Framework
5 What Is Quality?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Prevention versus Detection . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....
安卓开发类库和jar包httpmime-4.1.2.jar org.apache.http.entity.mime
server: port: 8888 spring: datasource: ... url: jdbc:mysql://localhost:3306/movie?characterEncoding=utf8&serverTimezone=UTC username: root ... type-aliases-package: com.movie.api.model.entity
Orleans.Providers.EntityFramework Orleans谷物存储的Entity Framework Core实现。 有一些不错的功能缺失。 我不是特别需要它们,但是如果您有建议或想要帮助,将不胜感激。用法Nuget: ://...
EntityFramework 执行过程分析工具,可完美看到执行的语句,支持EFCore
EntityFramework.Profiler v2.0 Build 2233 已破解,可无限使用,无需许可文件。