C# 如何将SQL多对多关系转换为Linq语句
在C项目中将T-SQL查询转换为Linq查询有以下挑战。为了简单起见,我尽可能用以下脚本表示:C# 如何将SQL多对多关系转换为Linq语句,c#,sql,sql-server,linq,C#,Sql,Sql Server,Linq,在C项目中将T-SQL查询转换为Linq查询有以下挑战。为了简单起见,我尽可能用以下脚本表示: DECLARE @TableA TABLE (ID INT NOT NULL IDENTITY(1, 1) , Data VARCHAR(10) NOT NULL) DECLARE @TableDetailsA TABLE (ID INT NOT NULL IDENTITY(1, 1) ,
DECLARE @TableA TABLE (ID INT NOT NULL IDENTITY(1, 1)
, Data VARCHAR(10) NOT NULL)
DECLARE @TableDetailsA TABLE (ID INT NOT NULL IDENTITY(1, 1)
, TableAID INT NOT NULL
, TableBID INT NOT NULL)
DECLARE @TableDetailsB TABLE (ID INT NOT NULL IDENTITY(1, 1)
, TableAID INT NOT NULL
, TableBID INT NOT NULL)
DECLARE @TableB TABLE (ID INT NOT NULL IDENTITY(1, 1)
, Data VARCHAR(10) NOT NULL
, TableCID INT NOT NULL)
DECLARE @TableC TABLE (ID INT NOT NULL IDENTITY(1, 1)
, Data VARCHAR(10) NOT NULL)
INSERT INTO @TableA(Data)
VALUES ('Data set A')
INSERT INTO @TableC(Data)
VALUES ('Data set C')
INSERT INTO @TableB(Data, TableCID)
VALUES ('Data set B', 1)
--INSERT INTO @TableDetailsA(TableAID, TableBID)
--VALUES (1, 1)
INSERT INTO @TableDetailsB(TableAID, TableBID)
VALUES (1, 1)
SELECT A.Data AS [Data A]
, B.Data AS [Data B]
, C.Data AS [Data C]
FROM @TableA A
JOIN @TableDetailsA DA
ON A.ID = DA.TableAID
JOIN @TableB B
ON DA.TableBID = B.ID
JOIN @TableC C
ON B.TableCID = C.ID
WHERE B.ID = 1
UNION
SELECT A.Data AS [Data A]
, B.Data AS [Data B]
, C.Data AS [Data C]
FROM @TableA A
JOIN @TableDetailsB BA
ON A.ID = BA.TableAID
JOIN @TableB B
ON BA.TableBID = B.ID
JOIN @TableC C
ON B.TableCID = C.ID
WHERE B.ID = 1
SELECT A.Data AS [Data A]
, B.Data AS [Data B]
, C.Data AS [Data C]
FROM @TableA A
LEFT JOIN @TableDetailsA DA
ON A.ID = DA.TableAID
LEFT JOIN @TableDetailsB DB
ON A.ID = DB.TableAID
JOIN @TableB B
ON B.ID = ISNULL(DA.TableBID, DB.TableBID)
JOIN @TableC C
ON B.TableCID = C.ID
WHERE B.ID = 1
注意,我通过两个不同的细节表TableDetailsA和TableDetailsB在两个表TableA和TableB之间建立了多对多关系。在这种情况下,TableDetailsA没有插入数据
因此,基本上,在我的C项目中,使用linq,我能够复制union语句,如linq中存在任何忽略错误…:
var firstQuery = from ta in repo.TableA
join tda in repo.TableDetailsA
on ta.ID equals tda.TableAID
join tb in repo.TableB
on tb.ID equals tda.TableBID
join tc in repo.TableC
on tb.TableCID = tc.ID
select new
{
ta.Data
, tb.Data
, tc.Data
};
var secondQuery = from ta in repo.TableA
join tdb in repo.TableDetailsB
on ta.ID equals tdb.TableAID
join tb in repo.TableB
on tb.ID equals tdb.TableBID
join tc in repo.TableC
on tb.TableCID = tc.ID
select new
{
ta.Data
, tb.Data
, tc.Data
};
var unionQuery = firstQuery.Union(secondQuery);
var data = unionQuery.ToList();
但是,我不知道如何复制使用ISNULL的第二条SQL语句。。。将TableB连接到TableA,我希望能够这样做,因为这看起来更高效、更优雅,并且需要在代码中声明的变量更少,虽然我知道这可以在一个var中完成,但我希望保持清楚
[编辑]
使用Cetin Basoz在回答中给出的第二个查询,我成功地构建了以下查询,生成了我要查找的结果。然而,我仍然希望找到一种方法,让LINQtoSQL生成ISNULL…,…,正如我在上面的最后一条select语句中看到的那样
var firstQuery = from ta in repo.TableA
from tda in ta.TableDetailsA.DefaultIfEmpty()
from tdb in ta.TableDetailsB.DefaultIfEmpty()
where ta.ID == 1
select new
{
TableAID = ta.ID
, TableBID = tda.TableB != null
? ns.TableB.ID
: nsc.TableB.ID
};
var secondQuery = from fq in firstQuery
join ta in repo.TableA
on fq.TableAID equals ta.ID
join tb in repo.TableB
on fq.TableBID equals tb.ID
join tc in repo.TableC
on tb.TableCID equals tc.ID
select new
{
TableAData = ta.Data
, TableBData = tb.Data
, TableCData = tc.Data
};
所以,我们仍然在等待我们的冠军解开这个死亡的秘密 基于Cetin Basoz的回答,我找到了一个我满意的解决方案。它不会生成我正在寻找的ISNULLDA.TableBID、DB.TableBID,但是它会在join子句中生成以下内容:如果DA.TableBID为NULL,则DA.TableBID ELSE DB.TableBID END
var firstQuery = (from tda in TableDetailsA
where tda.TableB.ID == 1
select new
{
DataA = tda.TableA.Data,
DataB = tda.TableB.Data,
DataC = tda.TableB.TableC.Data
})
.Union(from tdb in TableDetailsB
where tdb.TableB.ID == 1
select new
{
DataA = tdb.TableA.Data,
DataB = tdb.TableB.Data,
DataC = tdb.TableB.TableC.Data
});
var secondQuery = from a in TableA
from tda in a.TableDetailsA.DefaultIfEmpty()
from tdb in a.TableDetailsB.DefaultIfEmpty()
select new {
DataA = a.Data,
DataB = tda.TableB.Data ?? tdb.TableB.Data,
DataC = tda.TableB.TableC.Data ?? tdb.TableB.TableC.Data
};
解开这个问题的关键是我在第二个答案中找到的答案,其中tda.TableB.ID通过int转换为可为null的int类型?符号
构建Linq查询的代码如下所示:
var firstQuery = from ta in repo.TableA
from tda in ta.TableDetailsA.DefaultIfEmpty()
from tdb in ta.TableDetailsB.DefaultIfEmpty()
where ta.ID == 1
select new
{
TableAID = ta.ID
, TableBID = (int?)tda.TableB.ID ?? (int?)tdb.TableB.ID
};
var secondQuery = from fq in firstQuery
join ta in repo.TableA
on fq.TableAID equals ta.ID
join tb in repo.TableB
on fq.TableBID equals tb.ID
join tc in repo.TableC
on tb.TableCID equals tc.ID
select new
{
TableAData = ta.Data
, TableBData = tb.Data
, TableCData = tc.Data
};
这里的答案对你有好处吗?通常,可以使用一个连接表对多对多关系进行建模。例如TableDetailsA或TableDetailsB。为什么两者都定义了关系?删除其中一个表将显著降低linq查询的复杂性。@Ilessa感谢您的链接。可悲的是,在尝试了我从中得到的一个想法后,我仍然没有找到解决办法。还有其他想法吗?@Terence关于db的结构,我非常同意你的看法!然而,这是我目前无法控制的,因为我是这个项目的新手,系统非常陈旧,很难改变。奇怪的是,这类事情似乎在我所研究和遇到的许多旧系统中普遍存在。我只能假设这是90年代末和2000年代初的惯例。在这种情况下,它用于审计目的。不过,我只是在寻找一个Linq到SQL的解决方案,这样我就不必重复代码了。谢谢你的回答。我喜欢你提交的第二个问题,并使用了它,用你的答案扩展了我原来的问题。但是,我仍然在寻找一种在Linq中生成ISNULLDA.TableBID、DB.TableBID的方法。关于第一个查询,我并不像试图避免使用union语句那样热衷于查询。tda.TableB.Data??tdb.TableB.Data正在这样做,不是吗?最初是??没有帮助,因为我遇到了一个错误。然而,我发现将比较值转换为可为null的int值是有效的。我提出了一个答案,它产生了一种我很满意的SQL。感谢您的帮助,因为这将引导我走向正确的方向。我看到您正在模仿Linq中的SQL,这是不需要的。Linq不需要这些连接。