将包含多个联接,左联接,分组并必须具有EF核心的SQL查询转到

时间:2020-09-05 09:20:45

标签: sql linq asp.net-core entity-framework-core

我有一个对我来说真的很复杂的SQL查询,我试图将其转换为基于EntityFramework Core的代码,但我至少不能执行多重连接。

SELECT vrCore_Product.iMasterId, vrCore_Product.sName[Particular], 
                            SUM(tCore_Indta_0.fQuantityInBase) - ISNULL(AVG(tCore_ReservedStock_0.fQuantity),0)[Net Quantity],vrPos_Outlet.iMasterId[Product]
                            ,vrCore_Product.sCode[vrCore_Product.sCode0] FROM tCore_Data_0
                            JOIN tCore_Header_0 ON tCore_Header_0.iHeaderId = tCore_Data_0.iHeaderId
                            JOIN tCore_Indta_0 ON tCore_Data_0.iBodyId = tCore_Indta_0.iBodyId
                            JOIN cCore_Vouchers_0 WITH (READUNCOMMITTED) ON tCore_Header_0.iVoucherType = cCore_Vouchers_0.iVoucherType
                            JOIN vrCore_Product ON vrCore_Product.iMasterId = tCore_Indta_0.iProduct AND vrCore_Product.iTreeId = 0
                            JOIN vrPos_Outlet ON vrPos_Outlet.iMasterId = tCore_Data_0.iInvTag
                            LEFT JOIN 
                            (
                                Select iProduct, tCore_Data_0.iInvTag, SUM(case bReserveOrRelease when 0 then  tCore_ReservedStock_0.fQuantity else -tCore_ReservedStock_0.fQuantity end) fQuantity 
                                FROM tCore_ReservedStock_0 
                                JOIN tCore_Data_0 ON tCore_Data_0.iTransactionId = tCore_ReservedStock_0.iTransactionId 
                                JOIN tCore_Indta_0 ON tCore_Indta_0.iBodyId = tCore_Data_0.iBodyId
                                JOIN tCore_Header_0 ON tCore_Header_0.iHeaderId = tCore_Data_0.iHeaderId
                                WHERE tCore_Header_0.bSuspended = 0
                                GROUP BY iProduct,tCore_Data_0.iInvTag
                                HAVING SUM(CASE bReserveOrRelease WHEN 0 THEN tCore_ReservedStock_0.fQuantity ELSE -tCore_ReservedStock_0.fQuantity END)<>0
                            )tCore_ReservedStock_0 ON tCore_ReservedStock_0.iProduct = tCore_Indta_0.iProduct AND tCore_ReservedStock_0.iInvTag = tCore_Data_0.iInvTag WHERE tCore_Header_0.bUpdateStocks = 1 AND tCore_Data_0.bSuspendUpdateStocks <> 1 
                         AND tCore_Header_0.bSuspended = 0 AND tCore_Data_0.iAuthStatus < 2 
                         AND (tCore_Header_0.iDate BETWEEN dbo.DateToInt('2020-01-10') AND dbo.DateToInt('2020-01-22') OR (tCore_Header_0.iDate < dbo.DateToInt('2020-01-22') AND tCore_Header_0.iVoucherClass = 512))  AND vrCore_Product.iProductType <> 'Service' AND vrPos_Outlet.iMasterId IN (26) GROUP BY vrPos_Outlet.iMasterId, vrCore_Product.iMasterId, vrCore_Product.sName ,vrCore_Product.sCode HAVING SUM(tCore_Indta_0.fQuantity) <> 0 ORDER BY vrPos_Outlet.iMasterId

2 个答案:

答案 0 :(得分:1)

使用C#进行编码时,我们会考虑对象。在执行T-SQL时,我们认为是关系型的。这产生了一个称为对象关系阻抗失配的问题。 EF通过允许我们仅在对象中进行思考来帮助解决该问题。您正试图做完全相反的事情,即通过Linq查询将查询转换回对象表示形式。提示:我从不那样做。我的起点是C#对象模型,我在Linq中对查询思维进行建模。我不在乎T-SQL。

这似乎只是语法问题,因为T-SQL和Linq都是查询语言,最后,EF将Linq转换为T-SQL。但是,它们之间的区别不仅在于语法,还在于我们的思维方式。例如,在考虑T-SQL中的联接时,在linq中,我们考虑了导航属性。一方面,我们考虑关系和外键,另一方面,我们考虑对象和图形。

在非常少见的情况下,我最好使用T-SQL查询,我宁愿执行原始查询,也不必经历将其转换回Linq的痛苦:https://docs.microsoft.com/en-us/ef/core/querying/raw-sql

在您的情况下,我将执行以下两项操作之一:

  • 我要么简单地放弃T-SQL查询,然后重新开始,然后在Linq中思考。如果我对业务领域以及使用该查询需要提取的内容有很好的了解,这将很有帮助。这是大多数时候最喜欢的方法。
  • 或者,如果我对查询过于投入(不希望使用双关语),我会简单地使用EF将其作为原始查询执行(始终使用参数,而不是将查询与输入值连接起来,以防止出现任何查询) SQL注入漏洞)。唯一的缺点是,在向其添加原始查询后,代码就不再与数据库引擎无关。

答案 1 :(得分:-1)

如果您有关系,则可以像这样使用Include()

var data = _context.TcoreData0
                   .Include(x => x.TcoreHeader0)
                   .Include(x => x.TcoreIndta0)
                   .Include("tCore_Header_0.cCore_Vouchers_0")
                   .Include...