领域层
实体是领域驱动设计的
核心概念之一,Eric Evans就是这样描述的。许多对象不是由它们的
属性定义的,而是由一系列
连续事件和标识设计的。
译者注:对象不是其属性的基本定义,但应该由其线性连续性和恒等式来定义,因此,实体是具有唯一标识的ID,并存储在数据库中。实体通常映射到数据库中的表中。
实体类(实体类)
在ABP中,实体从实体类继承,见下面的例子:
公共类人员:实体
{
公共虚拟字符串名称{;get;set;}
公共虚拟时间创作时间{有};集;
公共
任务()
{
创作时间=现在的
日期时间;
}
}
Id类被定义为一个实体,它有两个属性,它的父元素有一个id属性。id是这个实体的主键。因此,从实体类继承所有实体的主键(所有实体的主键
都是id字段)。
可以更改id(主键)数据
类型。
默认值是int类型。如果要定义其他类型的ID,则应声明id的类型如下示例。
公共类人员:实体
{
公共虚拟字符串名称{;get;set;}
公共虚拟时间创作时间{有};集;
公共任务()
{
创作时间=现在的日期时间;
}
}
可以将其
设置为字符串、GUID或其他数据类型。
实体类重写等式(= =)
运算符是用来确定两个对象是否相等(两单位等于ID),大都是瞬时性()
方法来
检测是否还定义一个实体一个ID属性。
界面公约
在许多应用中,许多实体属性(数据库表的
创建时间也有场)表示当实体是created.apb提供了一些有用的接口实现类似的
功能。也就是说,一个普遍的编码方法是为那些实体实现这些接口。
(1)审计(审计)
实体类实现的创作时间
性能的ihascreationtime接口。当实体插入到数据库中,ABP自动设置为当前时间的属性值。
ihascreationtime公共接口
{
在创作时间{得到;集;}
}
人类可以改写为下面的示例实现ihascreationtime接口:
人类:实体,IHasCreationTime
{
公共虚拟字符串名称{;get;set;}
公共虚拟时间创作时间{有};集;
公共任务()
{
创作时间=现在的日期时间;
}
}
icreationaudited从ihascreationtime和接口有一个属性CreatorUserId:
公共接口icreationaudited:ihascreationtime
{
长creatoruserid {有};集;
}
当一个新的实体
保存,ABP自动设置CreatorUserId的值为当前
用户的ID
你可以很容易地实现icreationaudited接口。通过导出实体类creationauditedentity(因为该类实现了icreationaudited界面,我们可以直接继承creationauditedentity类来实现上述功能),它有一个通用的版本,实现不同的ID数据类型(默认为int),它可以给不同的数据类型ID(ID的实体类)。
下面是实现类似
修改功能的接口
imodificationaudited公共接口
{
日期时间lastmodificationtime {得到;集;}
长lastmodifieruserid {有};集;
}
当一个实体更新时,ABP会自动设置这些属性的值。
如果你想实现所有审计的属性,您可以
扩展iaudited接口直接;的例子如下:
公共接口iaudited:icreationaudited,imodificationaudited
{
}
作为一个快速发展的
模式,你可以直接从auditedentity类,不需要实现的iaudited接口(的auditedentity类所实现的功能,该类直接继承可以实现上述功能,auditedentity)的类有一个不同的ID数据类型的泛型版本(默认是int),可以ID(实体类ID)不同的数据类型。
(2)软
删除(软删除)
软的缺失是一种常见的方式,是用来标志一个实体,已被删除,而不是从数据库上删除记录。例如,你可能不想努力从数据库中删除用户记录,因为它与许多其他的表相
关联。实现软删除的目的,我们可以实现接口isoftdelete:
isoftdelete公共接口{
布尔isDeleted {有};集;
}
ABP实现了打开框的软删除模式,当删除软删除的实体被删除时,ABP会感知
操作并防止它被删除。设置isDeleted属性值为true,更新数据库中的实体,也就是说,软删除记录不能从数据库中检索,和ABP自动过滤器为我们软删除记录。(例如:选择
查询,即查询的查询分析器在ABP,没有数据库。)
如果你使用软删除,你也可以实现此功能,这是记录谁删除实体。实现此功能可以实现ideletionaudited接口。请看下面的例子:
公共接口ideletionaudited:isoftdelete
{
长deleteruserid {有};集;
日期时间deletiontime {得到;集;}
}
正如你看到的,ideletionaudited从isoftdelete interface.abp自动设置这些属性的值时,一个实体被删除。
如果你想将所有的审计接口的实体,例如,创造(创作),修改(修改)和删除(删除),你可以直接实现ifullaudited接口,因为接口继承这些接口。
公共接口ifullaudited:iaudited,ideletionaudited
{
}
作为一种
快捷方式,可以直接从fullauditedentity类派生出你的实体类,因为阶级已经实现了ifullaudited接口。
注:审计接口和类都有一个通用的导航属性自定义您的用户实体模板(例如icreationaudited和FullAuditedEntity),在TUser创建,修改和删除用户类型的实体类,在源代码
详细看(abp.domain.entities.auditing
空间fullauditedentity)。TprimaryKey是唯一ID的基类型,默认为int。
(3)
激活状态/空闲状态(主动/被动)
一些实体需要被标记为活动或空闲。然后你可以为实体采取主动/被动状态的行动。基于这个
原因产生的实体,可以延长ipassivable接口来实现这个功能,接口定义的活跃性。
如果你创造了首次实体标记为激活状态,可以设置真实的活跃属性值的构造
函数。
这是
不同于软删除(isDeleted)。如果实体是软删除,无法从数据库中检索(有过滤软删除记录),但激活或闲置的实体,你是完全取决于你如何得到这些标记的实体。
认同接口
事实上,实体实现认同接口(和认同的接口来实现与实体)。如果你不想从实体类,你可以实现这些接口直接。其他单位也可以实现相应的接口,但不
推荐你使用这个,除非你有没有从实体类的一个很好的理由。
仓库(仓库)
仓库定义:域层和数据映射层的中介使用类似的接口集合访问域对象(Martin Fowler)。
事实上,仓库用于在数据库上操作域对象(实体实体和值对象值类型),一般来说,我们为不同的实体(或聚合根聚合根)创建相应的仓库。
IRepository接口
在ABP,库类实现IRepository接口。最好的办法是定义不同的仓库对象不同的接口。
实体实体的仓库接口声明的示例如下所示:
公共ipersonrepository IRepository界面:
{
}
ipersonrepository继承自IRepository,它是用来定义ID就是int类型的实体(Int32)。如果你的实体ID数据类型是int,你可以继承IRepository界面,如下图所示:
公共ipersonrepository IRepository界面:
{
}
仓储类IRepository定义了一系列通用的方法。例如,选择,插入,更新,删除方法(CRUD操作)。大多数时候,这些方法已经满足了一般实体的需求。如果这些党派足够的实体,我们不需要创建存储接口 /类实体的需求。在
执行部分的更多细节。
(1)查询(查询)
IRepository的定义从数据库中检索实体的常用方法。
获取单个实体(获取单个实体):
tentity得到(tprimarykey ID);
任务GetAsync(tprimarykey ID);
TEntity Single(表达式>谓语);
TEntity FirstOrDefault(tprimarykey ID);
任务firstordefaultasync(tprimarykey ID);
TEntity FirstOrDefault(表达式>谓语);
任务firstordefaultasync(表达式>谓语);
TEntity Load(tprimarykey ID);
获取的方法是使用基于主键值获得相应的实体(ID)。当数据库中找不到一个一致的实体根据主键值是一个例外。单方法类似于get方法,但它的
输入参数是一个表达式,而不是一个主键值(ID)。所以,我们可以写lambda表达式得到实体的例子如下:
无功的人= _personrepository.get(42);
无功的人= _personrepository.single(P = O的
名字= =Halil易卜拉欣该);
注意,当给定
条件找不到实体或多个实体时,单个方法抛出异常。
FirstOrDefault是相同的,但在没有实体,符合一个lambda表达式或ID,它将返回null(而不是抛出异常)。当多个实体,符合条件的,它只会返回第一实体。
加载不会从数据库中检索实体,但它会创建延迟执行所需的
代理对象。它只会从数据库中查询实体你访问一些属性的实体,你想查询的时候,当有一个性能要求,这种方法可以用来代替GET方法。加载方法也是NHibernate和ABP的实现。如果ORM提供者(Provider)没有实现这种方法,加载方法
运行相同的获得方法。
ABP的一些方法有异步(异步)的版本,可以应用于异步开发模式(见异步方法的相关部分)。
B,实体列表(获取实体列表):
getalllist(名单);
任务> getalllistasync();
表getalllist(表达式>谓语);
任务> getalllistasync(表达式>谓语);
IQueryable GetAll();
getalllist用于从数据库检索的所有实体。它是重载的,提供过滤实体的功能,如下:
无功的人= _personrespository.getalllist();
VaR的人= _personrepository.getalllist(人= > person.isactive人。年龄> 42);
获得返回类型IQueryable对象。所以我们可以调用此方法后做LINQ操作的例子:
例
VaR查询=从人_personrepository.getall()
在person.isactive
人的名字进行
排序。
选择的人;
无功的人= query.tolist();
例二
表personlist2(,)= _personrepository.getall(P = p.name.contains(H))。OrderBy(P =器)和跳跃(40),(20)(。列出);
如果getAll方法被调用,那么几乎所有的查询可以使用LINQ。它甚至可以用来编写
连接表达式。
说明:关于IQueryable
当你调用外部的库对象的获得方法,你必须打开数据库连接。这是因为IQueryable允许延迟执行,将执行数据库查询,直到您调用ToList方法或使用IQueryable在foreach循环(或访问查询对象的方法)。因此,当你打电话的列出的方法,数据库的连接必须
启用。我们可以使用提供的ABP是UnitOfWork调用的方法实现的功能。注意
应用程序服务的方法假定UnitOfWork。因此,在获得方法的使用不需要的功能除了UnitOfWork作为一种应用服务的方法。
有些方法有异步版本可以应用于异步开发模式(见异步方法的章)。
自定义返回值(自定义返回值)
ABP的延迟加载效果也达到了IQueryable的另一种方法,而不需要在调用方法添加UnitOfWork属性标签。
T查询(函数,T>querymethod);
查询方法接受λ(或方法)得到IQueryable和返回任何对象类型的实例如下:
无功的人= _personrepository.query(Q =在哪里(P = p.name.contains(H)(P.OrderBy)= >(器)。列出));
因为lambda(或方法)是在仓库对象的方法中执行的,所以只有在数据库连接打开之后才执行它。
(2)新(插入)
的IRepository接口定义了一个简单的方法来对数据库提供了一个新的实体:
TEntity Insert(tentity实体);
任务insertasync(tentity实体);
TPrimaryKey InsertAndGetId(tentity实体);
任务insertandgetidasync(tentity实体);
TEntity InsertOrUpdate(tentity实体);
任务insertorupdateasync(tentity实体);
TPrimaryKey InsertOrUpdateAndGetId(tentity实体);
任务insertorupdateandgetidasync(tentity实体);
新方法将实体到数据库并返回相同的新增实体,insertandgetid方法返回的标识符(ID)的新的实体。它很好,当我们使用自动增加标识符值和需要新生成的标识符的entity.insertofupdate值将添加或更新实体,和选择取决于Id是否有价值。最后,insertorupdatedandgetid返回ID值实体后添加或更新。
所有的方法都有异步版本,可以应用到异步开发模型(见异步方法部分)。
(3)更新(更新)
IRepository定义了一个方法来更新已经在数据库中的一个实体,它更新的实体和返回相同的实体对象。
tentity更新(tentity实体);
任务updateasync(tentity实体);
(4)删除(删除)
IRepository已经制定了一些方法来删除现有数据库中的实体。
删除(tentity实体);
任务deleteasync(tentity实体);
删除(tprimarykey ID);
任务deleteasync(tprimarykey ID);
删除(表达式>谓词);
任务deleteasync(表达式>谓语);
第一种方法接受现有实体,第二种方法接受现有实体的ID。
最后一个方法接受一个条件来删除一个符合的实体。请注意,所有符合谓词表达式的实体将首先被检索,然后被删除。因此,使用非常小心,如果有太多的实体满足条件,就可能造成许多问题。
所有的方法都适用于异步开发模式的异步版本(见异步方法的章)。
(5)其他方法(其他)
IRepository也提供了大量的获取数据表中单位数的方法。
Int Count();
任务countasync();
Int Count(表达式>谓词);
任务countasync(表达式>谓语);
Long LongCount();
任务longcountasync();
长longcount(表达式>谓语);
任务longcountasync(表达式>谓语);
所有的方法都用在异步开发模式的异步版本(见异步方法的章)。
(6)对异步方法(关于异步方法)
ABP
支持异步开发模式。因此,仓储的方法有异步版本。下面是一个例子,应用服务的方法,采用异步模型:
公共课personappservice:AbpWpfDemoAppServiceBase,IPersonAppService
{
私人只读IRepository _personrepository;
公共personappservice(IRepository personrepository)
{
_personrepository = personrepository;
}
公共异步任务getAllPeople()
{
无功的人=
等待_personrepository.getalllistasync();
返回新的getpeopleoutput
{
人=地图绘制者(人)
};
}
}
getAllPeople方法是异步的,使用getalllistasync等待保留关键字。
如果不是在每一个ORM框架提供。
这是从EF提供异步能力。如果ORM框架没有提供异步存储方法,它将在一个
同步的方式。同样的,例如,对insertasync手术如EF加一样,因为EF将写新的主体数据库(DbContext。调用SaveChanges)直到单元操作完成(
工作单位)。
存储的实现
公司是在不指定一个特定的ORM框架或其他数据库访问技术设计。任何框架可以用只要IRepository接口的实现。
仓储是容易使用NHibernate或有效实施。
EntityFramework
当你使用NHibernate或者EntityFramework,你不需要如果方法可创建您的实体仓库对象。我们可以把IRepository(或IRepository)直接。下面的例子使用添加实体数据库应用服务仓库对象:
公共课personappservice:ipersonappservice
{
私人只读IRepository _personrepository;
公共personappservice(IRepository personrepository)
{
_personrepository = personrepository;
}
公共无效CreatePerson(CreatePersonInput输入)
{
人=人= {名称输入名称,
地址=输入电子邮件地址};
_personrepository.insert(人);
}
}
对personappservice构造函数注入IRepository和使用插入的方法。当你需要创建一个定制的仓储实体的方法,你应该创建一个存储库类指定的实体。
管理数据库连接
数据库连接被打开和
关闭,在仓库方法中,ABP将自动连接管理。
当调用存储方法时,数据库连接将自动打开并
启动事务。当执行和返回仓库方法时,将存储所有实体更改,将提交事务,并关闭数据库连接。一切都是由总部自动化
控制。如果仓储方法抛出任何类型的异常,事务将自动回滚,数据连接是关闭的,以上所有操作都可以在所有实现IRepository接口库类开放调用的方法。
如果存储方法调用其他库存的方法(即使是在不同的仓储方法),它们共享相同的连接和交易。连接是由仓库的方法是存储方法调用链的上层管理。更多关于数据库管理,看到UnitOfWork
文件。
存储的生命周期
所有仓储的对象是临时性的。也就是说,他们创造了当他们在need.abp大量使用依赖注入,当库类需要注入,新课现实是由注入容器自动创建。基于注入文件查看更多信息。
仓储的最佳做法
对于类型T的一个实体,它可以使用IRepository的。但不在任何
情况下,创建定制的仓库,除非我们真的需要它。预定义的仓储方法足以应对各种情况。
如果你创建一个定制的仓库(IRepository)
存储类应该是无状态的,这意味着你不应该定义仓库水平状态对象,仓库的方法调用不应该
影响其他电话。 U3000 U3000 U3000 U3000
当存储可根据注射使用,很少或没有根据其他服务。 U3000