Linq:连接还是不连接(使用连接或关系,哪种更好)

4

我已经编写了相当多的代码,使用了在我的数据库中有外键关系提供给我的Linq2Sql表关系。但是,这对于我的单元测试来说证明是有些费力的,因为我必须在我的测试环境中手动设置任何关系。

因此,我想知道是否编写Linq连接而不是依赖关系会给我更容易测试和可能更高效的代码。

        var query =
            from orderItem in data.OrderItems
            select new
            {
                orderItem.Order.Reference,
                orderItem.SKU,
                orderItem.Quantity,
            };

        Console.WriteLine("Relationship Method");
        query.ToList().ForEach(x => Console.WriteLine(string.Format("Reference = {0}, {1} x {2}", x.Reference, x.Quantity, x.SKU)));

        var query2 =
            from orderItem in data.OrderItems
            join order in data.Orders
                on orderItem.OrderID equals order.OrderID
            select new
            {
                order.Reference,
                orderItem.SKU,
                orderItem.Quantity,
            };

        Console.WriteLine();
        Console.WriteLine("Join Method");
        query2.ToList().ForEach(x => Console.WriteLine(string.Format("Reference = {0}, {1} x {2}", x.Reference, x.Quantity, x.SKU)));

以上两个查询都给出了相同的结果,但从性能和可测试性方面来看,哪一个更好呢?


.ToList().ForEach() <-- 这段代码是个毒瘤。只需使用 foreach 循环即可。 - Amy B
3个回答

2
你正在测试什么?是Linq to SQL读取数据的能力吗?通常认为,由于Linq to SQL只是一个数据库的薄层封装,因此Linq to SQL代码本身被认为是“纯净的”,所以不需要进行测试。
我非常不赞成以这种方式使您的代码变得复杂,只是为了模拟Linq to SQL DBML。如果您想测试业务逻辑,最好将测试数据库连接到DBML(有一个构造函数重载允许您这样做),并使用数据库事务来测试数据交互。这样,您可以回滚事务以撤消对数据库的更改,使测试数据库保持原始状态。

有趣,这是我最近一直在考虑的事情。 - Antony Scott
1
从单元测试的角度来看,与数据库隔离是一件好事。然而,我理解你的观点,在实际操作中,直接在数据库上运行要容易得多。但作为一个纯粹主义者,我更倾向于将其称为集成测试。 - Damian Powell
同意,这确实是一个集成测试,并且创建数据库的速度要慢得多。我有一个模拟的Linq2Sql存储库,它使用通用列表,我正在其中“注入”对象,而不是数据库中将存在的记录。我正在努力解决的问题是如何轻松地重新创建POCO对象(如果您可以称之为Linq2Sql生成的类!),以及您通过FK获得的所有暗示关系。 - Antony Scott
我最近开始使用EF,它更容易编写集成测试。我在提问时编写的代码很好,但是事情已经发生了变化。我已经形成了你在答案中表达的相同观点,我的所有EF测试都是集成测试。我有一个数据层,其中只包含数据访问代码和一些Linq查询,这些查询仅使用实际数据库进行集成测试。 - Antony Scott

1
就性能而言,这两个查询都会评估为相同的 SQL(Scott Guthrie在博客文章中介绍了如何查看由 LINQ 查询生成的 SQL)。我认为没有任何一个选项本质上比另一个更易于“可测试性”。然而,我更喜欢使用外键和关系,因为在使用 SQL Metal 时,它可以让您快速知道数据库是否具有适当的键。

我也喜欢使用FK,但我所说的是模拟Linq2Sql存储库,以便我可以对任何复杂查询进行单元测试,同时对任何周围逻辑进行单元测试。也许我在使我的代码可测试方面遗漏了一些技巧,我只是在使用在创建dbml时在Visual Studio中生成的代码。SQLMetal是否能够更轻松地制作可模拟(因此可测试)的类? - Antony Scott
SQLMetal会为您提供真正的POCO类,而不像DBML那样将所有内容隐藏在设计师下面。然而,我认为它不会节省太多时间,因为您担心的是特定实例之间的关系,而不仅仅是结构,在测试中。 - sgriffinusa

1

我认为这两种方法在性能和可测试性方面都没有优势。虽然第一种形式更易于阅读,但我个人会选择它。不过这是一个主观问题。

在我看来,你的问题在于如何以简单的方式设置数据,并使外键值和实体引用保持一致。我认为这不是一个容易解决的问题。你可以编写某种框架,创建对象代理并使用实体元数据拦截FK和相关实体属性设置器,以便将它们同步,但在你意识到之前,你已经实现了一个内存数据库!


这正是我面临的问题,你说得对,构建某种框架来“连接”所有关系是一项艰巨的任务。 - Antony Scott
我已经开始使用moq框架,并卡在查询语法和显式连接上。目前这对我非常有效,使我能够测试所有业务逻辑(包括linq查询)。 - Antony Scott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接