13

我正在开发的当前系统利用 Castle Activerecord 在域对象和数据库之间提供 ORM(对象关系映射)。这一切都很好,而且大多数时候实际上效果很好!

问题来自于 Castle Activerecords 对异步执行的支持,更具体地说,是管理对象所属会话的 SessionScope。长话短说,坏事发生了!

因此,我们正在寻找一种方法来轻松地将域对象(他们知道数据库存在并关心)转换(自动思考)到 DTO 对象(他们对数据库一无所知,不关心会话、映射属性或所有事情)奥姆)。

有没有人有这样做的建议。首先,我正在寻找对象的基本一对一映射。域对象Person将被映射到说PersonDTO。我不想手动执行此操作,因为它是一种浪费。

很明显,我想到了反思,但我希望这个网站周围有一些更好的 IT 知识, 会建议“更酷” 。

哦,我在 C# 中工作,如前所述的 ORM 对象与 Castle ActiveRecord 映射。


示例代码:

根据@ajmastrean 的要求,我已经链接到一个我(严重)一起嘲笑的例子。该示例有一个捕获表单、捕获表单控制器对象、活动记录存储库和一个异步助手。它有点大(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);
    }
}

这就是“坏事”发生的地方,因为我们正在使用设置为延迟加载的 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功能的存储库。

4

5 回答 5

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 到 PersonDTO 示例执行此操作:

Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();

并且 Person 和 PersonDTO 上的任何属性(同样,具有相同的名称和类型)都将由运行时发出的方法复制,并且不必发出任何后续调用,但会为那些类型重用相同的发出代码顺序(即,将 PersonDTO 复制到 Person 也会导致发出代码的命中)。

发布的代码太多,但如果您有兴趣,我会努力将示例上传到 SkyDrive 并在此处发布链接。

理查德

于 2008-10-04T03:58:16.210 回答
4

使用ValueInjecter,你可以将任何东西映射到任何东西,例如

  • 对象 <-> 对象
  • 对象 <-> 表单/WebForm
  • 数据读取器 -> 对象

它具有很酷的功能,例如:扁平化和非扁平化

下载包含大量示例

于 2010-06-15T08:50:09.913 回答
2

你应该自动映射我在这里写过的博客:

http://januszstabik.blogspot.com/2010/04/automatically-map-your-heavyweight-orm.html#links

只要两个对象上的属性名称相同,自动映射器就会处理它。

于 2010-04-22T20:52:12.863 回答
0

其实我现在完全糊涂了。因为您在说:“因此,我们正在寻找一种方法来轻松地将域对象(他们知道数据库存在并关心)转换(自动思考)到 DTO 对象(他们对数据库一无所知并且不关心会话) ,映射属性或所有事物ORM)。”

  1. 领域对象了解并关心数据库?这难道不是域对象的全部意义在于仅包含业务逻辑并且完全不知道 DB 和 ORM 吗?....您必须拥有这些对象?如果它们包含所有这些东西,你只需要修复它们......这就是为什么我有点困惑 DTO 是如何出现的

  2. 您能否提供更多有关延迟加载所面临问题的详细信息?

于 2008-11-21T23:37:02.690 回答
0

我很抱歉没有真正把细节放在这里,但基本的 OO 方法是让 DTO 成为 ActiveRecord 类的成员,并让 ActiveRecord 将访问器和修改器委托给 DTO。您可以使用代码生成或重构工具从 AcitveRecord 类中快速构建 DTO 类。

于 2008-10-04T04:21:50.357 回答