关于如何从域 (ORM) 对象映射到数据传输对象 (DTO) 的建议
Posted
技术标签:
【中文标题】关于如何从域 (ORM) 对象映射到数据传输对象 (DTO) 的建议【英文标题】:Suggestions on how to map from Domain (ORM) objects to Data Transfer Objects (DTO) 【发布时间】:2008-09-03 13:17:59 【问题描述】:我正在开发的当前系统利用 Castle Activerecord 在域对象和数据库之间提供 ORM(对象关系映射)。这一切都很好,而且大多数时候实际上效果很好!
问题来自于 Castle Activerecords 对异步执行的支持,更具体地说,是管理对象所属会话的 SessionScope。长话短说,坏事发生了!
因此,我们正在寻找一种方法来轻松地将域对象(他们知道数据库存在并关心)转换(自动思考)到 DTO 对象(他们对数据库一无所知并且不关心会话、映射属性)或所有东西ORM)。
有没有人对此提出建议。首先,我正在寻找对象的基本一对一映射。域对象 Person 将被映射为 PersonDTO。我不想手动执行此操作,因为这很浪费。
很明显,我想到了反思,但我希望通过这个网站周围的一些更好的 IT 知识,“cooler”会被建议。
哦,我在 C# 中工作,如前所述,使用 Castle ActiveRecord 映射的 ORM 对象。
示例代码:
应@ajmastrean 的要求,我将linked 提供给我(严重)一起模拟的一个示例。该示例有一个捕获表单、一个捕获表单controller、域对象、activerecord repository和一个async 帮手。它有点大(3MB),因为我包含了运行它所需的 ActiveRecored dll。您需要在本地计算机上创建一个名为 ActiveRecordAsync 的数据库,或者只需更改 .config 文件。
示例的基本细节:
捕获表格
捕获表单有对控制器的引用
private CompanyCaptureController MyController get; set;
在初始化表单时它调用 MyController.Load() 私人无效初始化表格() MyController = new CompanyCaptureController(this); MyController.Load(); 这将返回一个名为 LoadComplete() 的方法
public void LoadCompleted (Company loadCompany)
_context.Post(delegate
CurrentItem = loadCompany;
bindingSource.DataSource = CurrentItem;
bindingSource.ResetCurrentItem();
//TOTO: This line will thow the exception since the session scope used to fetch loadCompany is now gone.
grdEmployees.DataSource = loadCompany.Employees;
, null);
这是 “坏东西” 发生的地方,因为我们正在使用设置为延迟加载的 Company 的子列表。
控制者
控制器有一个从表单调用的 Load 方法,然后它调用 Asyc 助手以异步调用 LoadCompany 方法,然后返回 Capture 表单的 LoadComplete 方法。
public void Load ()
new AsyncListLoad<Company>().BeginLoad(LoadCompany, Form.LoadCompleted);
LoadCompany() 方法只是利用存储库来查找已知公司。
public Company LoadCompany()
return ActiveRecordRepository<Company>.Find(Setup.company.Identifier);
该示例的其余部分相当通用,它有两个继承自基类的域类、一个用于插入一些数据的设置文件和一个用于提供 ActiveRecordMediator 功能的存储库。
【问题讨论】:
【参考方案1】:我解决了一个与此非常相似的问题,我将许多旧 Web 服务合同中的数据复制到 WCF 数据合同中。我创建了许多具有这样签名的方法:
public static T ChangeType<S, T>(this S source) where T : class, new()
此方法(或任何其他重载)第一次为两种类型执行时,它会查看每种类型的属性,并根据名称和类型决定哪些属性存在于这两种类型中。它采用这个“成员交集”并使用 DynamicMethod 类来模拟 IL 以将源类型复制到目标类型,然后将生成的委托缓存在线程安全的静态字典中。
一旦创建了委托,它的速度非常快,而且我提供了其他重载来传递委托,以复制与交集条件不匹配的属性:
public static T ChangeType<S, T>(this S source, Action<S, T> additionalOperations) where T : class, new()
...所以您可以为您的 Person 到 PersonDTO 示例执行此操作:
Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();
并且 Person 和 PersonDTO 上的任何属性(同样,具有相同的名称和类型)将由运行时发出的方法复制,并且不必发出任何后续调用,但会重用相同的发出代码 对于那些按顺序排列的类型(即,将 PersonDTO 复制到 Person 也会导致发出代码的命中)。
发布的代码太多,但如果您有兴趣,我会努力将示例上传到 SkyDrive 并在此处发布链接。
理查德
【讨论】:
【参考方案2】:使用ValueInjecter,通过它你可以将任何东西映射到任何东西,例如
对象 对象 对象 表单/WebForm DataReader -> 对象它具有很酷的功能,例如:扁平化和非扁平化
下载包含大量示例
【讨论】:
【参考方案3】:你应该使用我在博客中提到的自动映射器:
http://januszstabik.blogspot.com/2010/04/automatically-map-your-heavyweight-orm.html#links
只要两个对象上的属性名称相同,自动映射器就会处理它。
【讨论】:
现在是死链接。是的,linkrot。【参考方案4】:我很抱歉没有真正把细节放在这里,但基本的 OO 方法是让 DTO 成为 ActiveRecord 类的成员,并让 ActiveRecord 将访问器和修改器委托给 DTO。您可以使用代码生成或重构工具从 AcitveRecord 类中快速构建 DTO 类。
【讨论】:
【参考方案5】:其实我现在完全糊涂了。 因为您在说:“因此,我们正在寻找一种方法来轻松地将域对象(他们知道数据库存在并关心)转换(自动思考)到 DTO 对象(他们对数据库一无所知并且不关心会话) , 映射属性或所有事物 ORM)。”
域对象知道并关心 DB?这难道不是域对象的全部意义在于仅包含业务逻辑并且完全不知道 DB 和 ORM 吗?....您必须拥有这些对象?如果它们包含所有这些东西,你只需要修复它们......这就是为什么我有点困惑 DTO 是如何出现的
您能否详细说明您在延迟加载时遇到的问题?
【讨论】:
以上是关于关于如何从域 (ORM) 对象映射到数据传输对象 (DTO) 的建议的主要内容,如果未能解决你的问题,请参考以下文章
Node.js关于ORM框架以及sequelize模块的使用