我正在使用的当前系统利用Castle Activerecord在Domain对象和数据库之间提供ORM(对象关系映射)。这一切都很好,在大多数情况下实际上运作良好!
问题出在Castle Activerecords支持异步执行,更具体地说是管理对象所属会话的SessionScope。长话短说,坏事发生了!
因此,我们正在寻找一种方法,可以轻松地从域对象(知道数据库存在和关心)转换(自动思考)到DTO对象(谁对数据库一无所知,不关心会话,映射属性)或者所有的东西(ORM)。
有没有人有这方面的建议。首先,我正在寻找对象的基本一对一映射。域对象人将映射为 PersonDTO 。我不想手动这样做,因为这是浪费。
显然我想到了反思,但我希望在这个网站上有一些更好的IT知识可以建议“cool”。
哦,我正在使用C#,ORM对象在使用Castle ActiveRecord映射之前说过。
通过@ ajmastrean的请求我linked得到了一个我(非常)嘲笑的例子。该示例包含捕获表单,捕获表单控制器,域对象,activerecord 存储库和异步帮手。它有点大(3MB),因为我包含了运行它所需的ActiveRecored dll。您需要在本地计算机上创建一个名为 ActiveRecordAsync 的数据库,或者只需更改.config文件。
示例的基本细节:
捕获表单
捕获表单引用了控制器
private CompanyCaptureController MyController { get; set; }
在表单初始化时调用MyController.Load() private void InitForm() { 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);
}
}
这是“bad stuff”发生的地方,因为我们正在使用设置为Lazy load的公司子列表。
控制器
控制器有一个从表单调用的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 功能的存储库。
答案 0 :(得分:9)
我解决了一个与此非常类似的问题,我将大量旧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 to PersonDTO做这个:
Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();
Person和PersonDTO上的任何属性(同样具有相同的名称和类型)都将被运行时发出的方法复制,并且不必发出任何后续调用,但会重用相同的发出代码对于那个顺序的那些类型(即将PersonDTO复制到Person也会发出命中以发出代码)。
要发布的代码太多,但如果您有兴趣,我会努力将样本上传到SkyDrive并在此处发布链接。
理查德
答案 1 :(得分:4)
使用ValueInjecter,您可以将任何内容映射到任何内容,例如
它具有很酷的功能,如:扁平化和不平整
下载包含大量样本
答案 2 :(得分:2)
你应该在我的博客中找到自动播放器:
http://januszstabik.blogspot.com/2010/04/automatically-map-your-heavyweight-orm.html#links
只要在两个对象上命名属性相同,automapper就会处理它。
答案 3 :(得分:0)
我很抱歉没有在这里详细介绍细节,但基本的OO方法是让DTO成为ActiveRecord类的成员,并让ActiveRecord将访问者和更改者委托给DTO。您可以使用代码生成或重构工具从AcitveRecord类中快速构建DTO类。
答案 4 :(得分:0)
实际上我现在完全被混淆了。 因为您说:“因此,我们正在寻找一种方法,可以轻松地从域对象(知道数据库存在和关心的人)转换(自动思考)到DTO对象(谁对数据库一无所知,也不关心会话) ,映射属性或所有东西ORM)。“
域对象知道并关心数据库?域对象的重点不仅仅是包含业务逻辑而且完全不知道DB和ORM吗?....你必须拥有这些对象吗?你需要修改它们,如果它们包含所有这些东西......这就是为什么我有点困惑DTO如何进入画面
您是否可以提供有关延迟加载时遇到的问题的详细信息?