(一)基本设施层,定义一些基本接口
主要包含以下几个类和接品
1 EntityBase【class】
两个作用:
用于所有实体的基类,这样可以使用LSP;并对ID进行管理
2 IRepository<T>【interface】
仓储是用于持久化支持的组件。
定义四个基本方法:
T FindBy(object key);
IList<T> FindAll();
void Add(T item);
void Remove(T item);
3 IUnitOfWork【interface】
工作单元,用于对三种状态下的实体进行记录管理。定义了四个方法
void RegisterAdded(EntityBase entity, IUnitOfWorkRepository repository);
void RegisterChanged(EntityBase entity, IUnitOfWorkRepository repository);
void RegisterRemoved(EntityBase entity, IUnitOfWorkRepository repository);
void Commit();
注册方法第二个参数用于调用仓储工作单元,用于持久(实体)数据
4 UnitOfWork【类】
实现IUnitOfWork接口
使用字典维持三种状态下的实体,注册的作用,即把未添加到字典中的实体添加到各自的字典中。
Commit方法用于把三种状态下的实体保持与持久数据同步(提交到数据库);需要注意的是同步持久后,清空所有当前提交过的实体
public void Commit() { using (TransactionScope scope = new TransactionScope()) { foreach (EntityBase entity in this.deletedEntities.Keys) { this.deletedEntities[entity].PersistDeletedItem(entity); }
foreach (EntityBase entity in this.addedEntities.Keys) { this.addedEntities[entity].PersistNewItem(entity); }
foreach (EntityBase entity in this.changedEntities.Keys) { this.changedEntities[entity].PersistUpdatedItem(entity); }
scope.Complete(); }
this.deletedEntities.Clear(); this.addedEntities.Clear(); this.changedEntities.Clear(); } |
5 RepositoryBase【class】
仓储基类,实现IRepository<T>, IUnitOfWorkRepository两个接口,此类同时需要用到IUnitOfWork接口,以构造器注入方式注入UnitOfWork
仓储的基本功能由IRepository<T>接口定义,此类实现其中的两个方法:Add和Remove方法,因为Commit方法会调用持久接口的方法,所以Add和Remove方法并不涉及持久的相关操作。
另一方面,此基数为抽象类,对领域模型未确定,即此基类是一个泛型抽象类,所以与持久相关的查询方法:FindBy,FindAll,向下传递,这里不实现。
同理,对IUnitOfWorkRepository接口,实现类似模板方法。方法以保护方法向子类传递:
public virtual void PersistNewItem(EntityBase item) { this.PersistNewItem((T)item); } protected abstract void PersistNewItem(T item); |
为了子类未确定的情况下保持持久,传递的三个受保护的持久方法接受泛型入参。
所以此抽象基类,实现了IUnitOfWorkRepository接口,也实现了IRepository<T>接口的3个方。同时与IUnitOfWork联系起来,注入工作单元。
最终此抽象基类需要子类实现的是:
1 确定领域类型的查询相关操作
2 与持久相关的操作
protected abstract void PersistNewItem(T item); protected abstract void PersistUpdatedItem(T item); protected abstract void PersistDeletedItem(T item); public abstract T FindBy(object key); public abstract IList<T> FindAll(); |
(二)领域层,用于定义模型,模型不能使用贫血模型,需要有数据和业务
不能使用贫血模型(只带数据不带方法的类)。
领域模型包括数据,且有自己的业务逻辑实现
仓储层此时实体类型已经明确,所以用于实现与数据库的交互。
因为数据库类型的不同,定义了一个特定类型数据库仓储基类(做的sql数据库)
SqlRepositoryBase【class】
基础设施层中的RepositoryBase 有6个未实现的方法,仓储层的类型数据库基类从RepositoryBase派生
在此类中,数据库类型已经确定,但为了分层分开,为每个聚合根分别建立仓储实现,意味着在此基类中,实体类型还未确定,所以,此基类还是一个泛型类。
未实现的5个方法如下:
protected abstract void PersistNewItem(T item); protected abstract void PersistUpdatedItem(T item); protected abstract void PersistDeletedItem(T item); public abstract T FindBy(object key); public abstract IList<T> FindAll(); |
可以在此类中实现以上5个方法,数据源架构模式中有3种:
1 表数据入口
2 行数据入口
3 映射器
以表数据入口来看,此类实现了查询的两个方法
public override IList<T> FindAll() { StringBuilder builder = new StringBuilder(50); builder.Append(this.baseQuery); builder.Append(";"); return this.BuildEntitiesFromSql(builder.ToString()); } |
其中的baseQuery在构造器中初始化,此字段由保护的抽象方法提供,此抽象方法由表数据入口中的表实现。
同样的,FindBy方法的sql语句也由子类提供
public override T FindBy(object key) { StringBuilder builder = this.GetBaseQueryBuilder(); builder.Append(this.BuildBaseWhereClause(key)); return this.BuildEntityFromSql(builder.ToString()); } |
现在没实现的是三个持久方法,它们以保护的向子类传递,但不公开。公开的是在UnitOfWork类中实现的。
CompanyRepository【class】
到这个类,数据库类型和实体类型均已经明确,所以不再需要泛型实现
此类从SqlRepositoryBase<Company>, ICompanyRepository派生
对 SqlRepositoryBase<Company>类,需要实现它的3个持久方法和对FindAll,FindBy两个方法提供的sql语句:
protected abstract override void PersistNewItem(T item); protected abstract override void PersistUpdatedItem(T item); protected abstract override void PersistDeletedItem(T item);
protected abstract string GetBaseQuery(); protected abstract string GetBaseWhereClause(); |
三个持久方法
protected override void PersistNewItem(Company item) { StringBuilder builder = new StringBuilder(100); builder.Append(string.Format("INSERT INTO Company ({0},{1},{2},{3},{4},{5},{6}) ", CompanyFactory.FieldNames.CompanyId, CompanyFactory.FieldNames.CompanyName, CompanyFactory.FieldNames.CompanyShortName, CompanyFactory.FieldNames.Phone, CompanyFactory.FieldNames.Fax, CompanyFactory.FieldNames.Url, CompanyFactory.FieldNames.Remarks)); builder.Append(string.Format("VALUES ({0},{1},{2},{3},{4},{5},{6});", DataHelper.GetSqlValue(item.Key), DataHelper.GetSqlValue(item.Name), DataHelper.GetSqlValue(item.Abbreviation), DataHelper.GetSqlValue(item.PhoneNumber), DataHelper.GetSqlValue(item.FaxNumber), DataHelper.GetSqlValue(item.Url), DataHelper.GetSqlValue(item.Remarks)));
this.Database.ExecuteNonQuery( this.Database.GetSqlStringCommand(builder.ToString()));
// Now do the addresses this.InsertAddresses(item); } protected override void PersistUpdatedItem(Company item) { StringBuilder builder = new StringBuilder(100); builder.Append("UPDATE Company SET ");
builder.Append(string.Format("{0} = {1}", CompanyFactory.FieldNames.CompanyName, DataHelper.GetSqlValue(item.Name)));
builder.Append(string.Format(",{0} = {1}", CompanyFactory.FieldNames.CompanyShortName, DataHelper.GetSqlValue(item.Abbreviation)));
builder.Append(string.Format(",{0} = {1}", CompanyFactory.FieldNames.Phone, DataHelper.GetSqlValue(item.PhoneNumber)));
builder.Append(string.Format(",{0} = {1}", CompanyFactory.FieldNames.Fax, DataHelper.GetSqlValue(item.FaxNumber)));
builder.Append(string.Format(",{0} = {1}", CompanyFactory.FieldNames.Url, DataHelper.GetSqlValue(item.Url)));
builder.Append(string.Format(",{0} = {1}", CompanyFactory.FieldNames.Remarks, DataHelper.GetSqlValue(item.Remarks)));
builder.Append(" "); builder.Append(this.BuildBaseWhereClause(item.Key));
this.Database.ExecuteNonQuery( this.Database.GetSqlStringCommand(builder.ToString()));
// Now do the addresses
// First, delete the existing ones this.DeleteAddresses(item);
// Now, add the current ones this.InsertAddresses(item); }
protected override void PersistDeletedItem(Company item) { // Delete the company addresses first this.DeleteAddresses(item);
// Now delete the company string query = string.Format("DELETE FROM Company {0}", this.BuildBaseWhereClause(item.Key)); this.Database.ExecuteNonQuery( this.Database.GetSqlStringCommand(query)); } |
此时,与持久化相关的完成
构建的sql语句的两个方法:
protected override string GetBaseQuery() { return "SELECT * FROM Company"; } |
到此对Company实体的(领域、数据架构)构建完成。
要注意的一个是,CompanyRepository类还实现了一个接口:ICompanyRepository。当前此接口是一个空接口,可能以后会用到。。。
以上介绍,忽略了工厂,服务,测试等内容
以上代码出自:《领域驱动设计C# 2008实现》 随书源码
源码下载