关于如何从域(ORM)对象映射到数据传输对象(DTO)的建议

时间:2008-09-03 13:17:59

标签: c# orm castle-activerecord dto-mapping

我正在使用的当前系统利用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 功能的存储库。

5 个答案:

答案 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,您可以将任何内容映射到任何内容,例如

  • object&lt; - &gt;对象
  • object&lt; - &gt;形式/ web窗体
  • DataReader - &gt;对象

它具有很酷的功能,如:扁平化和不平整

下载包含大量样本

答案 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)。“

  1. 域对象知道并关心数据库?域对象的重点不仅仅是包含业务逻辑而且完全不知道DB和ORM吗?....你必须拥有这些对象吗?你需要修改它们,如果它们包含所有这些东西......这就是为什么我有点困惑DTO如何进入画面

  2. 您是否可以提供有关延迟加载时遇到的问题的详细信息?