I have the following challenge to covert a T-SQL query to a Linq query in a C# project. As best as I can and for simplicity's sake, it is represented in the following script:
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
Notices that I have a many to many relationship between two tables, TableA
and TableB
through two different detail tables TableDetailsA
and TableDetailsB
. In this case TableDetailsA
does not have data inserted into it.
So basically, using linq, in my C# project, I am able to replicate the union
statement like so (ignore error in the linq if there are any...):
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();
However, I don't know how to replicate the second SQL statement that uses the ISNULL(...)
to join TableB
to TableA
, which I would like to be able to do as this seems more efficient and elegant and would require less variables to be declared in my code (although I know this can be done in one var but I like to keep it clear).
[EDIT]
Using the second query given in the answer by Cetin Basoz, I've managed to build the following queries that generate the result I'm looking for. However, I still would prefer to find a way to for Linq to SQL to generate the ISNULL(..., ...)
, as seen in my last select statement above.
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
};
So, we are still waiting for our champion to unlock this deathly secret!