如何为测试目的创建EF代码第一类的分离克隆?

时间:2011-04-08 15:26:13

标签: entity-framework integration-testing automapper code-first

我想创建一个集成测试,它从数据库中抓取EF实体,将其克隆到分离的对象,修改它然后将其保存回来并再次将其与原始对象进行比较。

但是,我使用AutoMapper来创建类的克隆,但事实证明它也被跟踪或是原始对象的别名。我需要它与EF完全分离,并且能够在我的存储库类之外执行此操作(即不使用任何EF分离方法)。

这样做的原因是我的EF类包含其他类的嵌套集合,EF不处理持久化整个对象树。因此,我的repository类中的Update()方法处理这个问题,我希望我的NUnit测试来测试这段代码。我希望测试能够在没有EF跟踪的情况下快速创建原始类的副本。

3 个答案:

答案 0 :(得分:6)

  

创建包含当前,原始或数据库的克隆对象   values从CurrentValues返回的DbPropertyValues对象,   可以使用OriginalValues或GetDatabaseValues创建克隆   实体。此克隆将包含来自的属性值   用于创建它的DbPropertyValues对象。例如:

using (var context = new UnicornsContext())
{
    var unicorn = context.Unicorns.Find(1);

    var clonedUnicorn = context.Entry(unicorn).GetDatabaseValues().ToObject();
}
     

请注意,返回的对象不是实体,也不是   跟踪上下文。返回的对象也没有   关系设置为其他对象。

     

克隆的对象可用于解决与之相关的问题   对数据库的并发更新,尤其是UI所在的位置   涉及到正在使用某种类型的对象的数据绑定。 (看到   关于处理乐观并发的更多细节的第9部分。)

*来自http://blogs.msdn.com/b/adonet/archive/2011/01/30/using-dbcontext-in-ef-feature-ctp5-part-5-working-with-property-values.aspx

希望它可以帮助别人

答案 1 :(得分:3)

一旦您使用EF 5+,他们引入了AsNoTracking()方法,所有问题都消失了。 下面的行返回一个未链接的实例,因此所有上下文都不会知道该实例中的任何更改:

context.Clients.AsNoTracking().FirstOrDefault(item => item.Id == id);

如果客户引用地址并且您想要一个未链接的实例,只需使用Include

context.Clients
       .Include("Address").AsNoTracking()
       .FirstOrDefault(item => item.Id == id);

答案 2 :(得分:0)

如果是测试,您可以执行任何操作,并且不必绑定到任何体系结构方法(如存储库)。您的存储库可能会接收上下文作为注入,因此您可以访问它。另一点是我不相信AutoMapper会创建跟踪实体。

制作类副本的一种方法是使用序列化,默认情况下只保存公共字段(Xml序列化或DataContract序列化)。序列化对象并将其反序列化为新实例。序列化将保存整个对象图,并且反序列化的对象图将被分离。请注意,这些序列化不喜欢对象图中的循环引用(从A到B的导航属性以及从循环到B到A的导航属性)。序列化也具有太强烈的侵略性,因此它可以更深入地遍历图形 - 这在多对多关系中尤其危险。

最好的方法是使用ICloneable接口并实现Clone或定义支持方法,这些方法将执行具有所需深度的不同克隆。

Here是克隆基于EntityObject的实体的另一种方法。这是一个很难的代码,特别是Reflection.Emit的一部分。但这对你没有帮助,因为代码优先使用的是POCO。