我对linq表达式很陌生,并且正在尝试得出此tsql的等效linq版本:
SELECT
p.Name,
Count(a.Street) [Number of addresses],
c.ContractType,
COUNT(cv.ContractVersionId) Number,
MAX(cv.ChangedDate) [Last change date]
From Person p
LEFT JOIN Address a ON p.PersonId = a.PersonId AND a.ChangedDate IS NULL
LEFT JOIN Contract c ON p.PersonId = c.PersonId
LEFT JOIN ContractVersion cv ON c.ContractId = cv.ContractId
GROUP BY p.Name, c.ContractType
这将产生输出:
Name Number of addresses ContractType Number Last change date
Bob 1 NULL 0 NULL
Allice 1 Buy 1 2020-10-31 00:00:00.000
Karen 0 Buy 3 2020-09-01 00:00:00.000
Peter 3 Lease 3 2020-07-10 00:00:00.000
Tom 5 Lease 5 2020-09-14 00:00:00.000
Allice 3 Rent 3 2020-05-10 00:00:00.000
要复制的数据:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Person]') AND type in (N'U'))
DROP TABLE [dbo].Person
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Address]') AND type in (N'U'))
DROP TABLE [dbo].Address
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Contract]') AND type in (N'U'))
DROP TABLE [dbo].Contract
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ContractVersion]') AND type in (N'U'))
DROP TABLE [dbo].ContractVersion
GO
CREATE TABLE Person (
PersonId Uniqueidentifier NOT NULL,
Name NVARCHAR(100) NOT NULL
)
CREATE TABLE Address(
AddressId Uniqueidentifier NOT NULL,
PersonId Uniqueidentifier NOT NULL,
Street NVARCHAR(100) NOT NULL,
ChangedDate DATETIME NULL
)
CREATE TABLE Contract (
ContractId Uniqueidentifier NOT NULL,
PersonId Uniqueidentifier NOT NULL,
ContractType NVARCHAR(100) NOT NULL
)
CREATE TABLE ContractVersion (
ContractVersionId Uniqueidentifier NOT NULL,
ContractId Uniqueidentifier NOT NULL,
ContractText NVARCHAR(100) NOT NULL,
ChangedDate DATETIME NULL
)
INSERT INTO Person
VALUES
('{B8A97537-AF09-45FD-A723-1BF43796DADA}','Tom'),
('{124A34C0-1AB3-4449-AEE2-04ED2732B8ED}','Allice'),
('{E501CC32-C587-43C7-B0DD-096F04EE80AA}','Peter'),
('{9D1E37BE-D032-45CC-AA1D-06ECBB9C59EA}','Karen'),
('{049B5985-F4D0-448C-9391-8E08495DF61F}','Bob')
INSERT INTO Address
VALUES
('{AF3BE020-6851-46E1-9D04-9959C665A80D}','{B8A97537-AF09-45FD-A723-1BF43796DADA}','Last address 1',NULL),
('{A0957F82-8922-452C-AA1B-4EA05A1B121B}','{124A34C0-1AB3-4449-AEE2-04ED2732B8ED}','Last address 2',NULL),
('{10D60EDC-75B3-412F-AA0B-962746EB72BD}','{E501CC32-C587-43C7-B0DD-096F04EE80AA}','Last address 3',NULL),
('{93A10053-5059-4127-8EA1-C0DF77760E84}','{049B5985-F4D0-448C-9391-8E08495DF61F}','Last address 4',NULL),
('{F1E838FE-7074-4AB3-8A4D-0895CEB98362}','{B8A97537-AF09-45FD-A723-1BF43796DADA}','D','2020-01-01'),
('{4CB0D80D-7F74-4755-9C1A-08A03EE88B4B}','{124A34C0-1AB3-4449-AEE2-04ED2732B8ED}','D','2020-01-01'),
('{B42DE51A-3EAD-4AAC-B5DC-75493FE214E5}','{E501CC32-C587-43C7-B0DD-096F04EE80AA}','D','2020-01-01')
INSERT INTO Contract
VALUES
('{64989F02-793E-4313-9324-4916D6C5D610}','{B8A97537-AF09-45FD-A723-1BF43796DADA}','Lease'),
('{0101F8CD-E72E-4D9B-A8BD-A94BBDB39740}','{124A34C0-1AB3-4449-AEE2-04ED2732B8ED}','Rent'),
('{D1F94A9C-0718-4E18-B63F-B506C5E2C70E}','{E501CC32-C587-43C7-B0DD-096F04EE80AA}','Lease'),
('{A8397E6D-597A-4024-91DC-98EA0D9FF848}','{9D1E37BE-D032-45CC-AA1D-06ECBB9C59EA}','Buy'),
('{D47E82B3-2D41-4CCB-BD6F-003BD9C49BEA}','{B8A97537-AF09-45FD-A723-1BF43796DADA}','Lease'),
('{5EC4E588-00A5-442B-BD7B-0C9FD27E8076}','{124A34C0-1AB3-4449-AEE2-04ED2732B8ED}','Buy')
INSERT INTO ContractVersion
VALUES
('{E3E26DE5-F00A-4BEB-9A48-72AE9EA29F2E}','{64989F02-793E-4313-9324-4916D6C5D610}','Created','2020-01-01'),
('{C5EFAB2E-EE41-4A10-A708-44CA19E505A9}','{0101F8CD-E72E-4D9B-A8BD-A94BBDB39740}','Created','2020-05-01'),
('{43EDFE20-B1EF-4236-8D4E-478F445EC327}','{D1F94A9C-0718-4E18-B63F-B506C5E2C70E}','Created','2020-06-03'),
('{16870733-0EC3-497B-BA51-770C921A245A}','{A8397E6D-597A-4024-91DC-98EA0D9FF848}','Created','2020-08-15'),
('{93CAEA22-D796-4237-A706-47C3D6AE8700}','{D47E82B3-2D41-4CCB-BD6F-003BD9C49BEA}','Created','2020-09-12'),
('{9D003A79-1376-4512-922F-88A33EC72CCB}','{5EC4E588-00A5-442B-BD7B-0C9FD27E8076}','Created','2020-10-31'),
('{8BD9E556-BB56-4404-A7C2-C6C06D321127}','{64989F02-793E-4313-9324-4916D6C5D610}','Reviewed','2020-01-05'),
('{E46D1C7E-94BF-43BC-883D-7960CE719C07}','{0101F8CD-E72E-4D9B-A8BD-A94BBDB39740}','Reviewed','2020-05-01'),
('{0B5B594C-78BF-49B7-834B-3E9A617A16F9}','{D1F94A9C-0718-4E18-B63F-B506C5E2C70E}','Reviewed','2020-06-08'),
('{931C3910-DFD6-4EB4-9826-9518B3C6BC54}','{A8397E6D-597A-4024-91DC-98EA0D9FF848}','Reviewed','2020-08-16'),
('{6F97D07E-9AAD-488E-87D3-D2A886547B1C}','{D47E82B3-2D41-4CCB-BD6F-003BD9C49BEA}','Reviewed','2020-09-14'),
('{BD3B3413-8853-4199-BC93-B23D49F77A9C}','{64989F02-793E-4313-9324-4916D6C5D610}','Finalized','2020-04-01'),
('{5DA560DE-69D7-4244-A320-AF3FE4135B22}','{0101F8CD-E72E-4D9B-A8BD-A94BBDB39740}','Finalized','2020-05-10'),
('{8392D528-438C-4F82-8BAC-69C1913CF610}','{D1F94A9C-0718-4E18-B63F-B506C5E2C70E}','Finalized','2020-07-10'),
('{0DC060B3-12F0-4927-8526-57E87C0150EA}','{A8397E6D-597A-4024-91DC-98EA0D9FF848}','Finalized','2020-09-01')
SELECT
p.Name,
Count(a.Street) [Number of addresses],
c.ContractType,
COUNT(cv.ContractVersionId) Number,
MAX(cv.ChangedDate) [Last change date]
From Person p
LEFT JOIN Address a ON p.PersonId = a.PersonId AND a.ChangedDate IS NULL
LEFT JOIN Contract c ON p.PersonId = c.PersonId
LEFT JOIN ContractVersion cv ON c.ContractId = cv.ContractId
GROUP BY p.Name, c.ContractType
感谢所有帮助!
更新: 我可以生成此linq表达式,但是字体却使我无法进行分组,因为数据位于不同的表中。
from p in Persons
join a in Addresses on new { p.PersonId} equals new { a.PersonId} into addressGroup from a in addressGroup.DefaultIfEmpty()
join c in Contracts on p.PersonId equals c.PersonId into contractGroups from c in contractGroups.DefaultIfEmpty()
join cv in ContractVersions on c.ContractId equals cv.ContractId
select new {p.Name, a.Street, c.ContractType, cv.ChangedDate}
更新2:
我在下面尝试了@jdweng查询,结果生成的sql像这样:
SELECT [t5].[Name] AS [name], (
SELECT COUNT(*)
FROM (
SELECT NULL AS [EMPTY]
FROM (
SELECT [t7].[Street] AS [value], [t6].[Name], [t8].[ContractType]
FROM [Person] AS [t6]
LEFT OUTER JOIN [Address] AS [t7] ON [t6].[PersonId] = [t7].[PersonId]
LEFT OUTER JOIN [Contract] AS [t8] ON [t6].[PersonId] = [t8].[PersonId]
INNER JOIN [ContractVersion] AS [t9] ON [t8].[ContractId] = [t9].[ContractId]
) AS [t10]
WHERE ([t5].[Name] = [t10].[Name]) AND ((([t5].[value] IS NULL) AND ([t10].[ContractType] IS NULL)) OR (([t5].[value] IS NOT NULL) AND ([t10].[ContractType] IS NOT NULL) AND ((([t5].[value] IS NULL) AND ([t10].[ContractType] IS NULL)) OR (([t5].[value] IS NOT NULL) AND ([t10].[ContractType] IS NOT NULL) AND ([t5].[value] = [t10].[ContractType])))))
GROUP BY [t10].[value]
) AS [t11]
) AS [numberOfAddresses], [t5].[value] AS [contractType], (
SELECT COUNT(*)
FROM (
SELECT NULL AS [EMPTY]
FROM [Person] AS [t12]
LEFT OUTER JOIN [Address] AS [t13] ON [t12].[PersonId] = [t13].[PersonId]
LEFT OUTER JOIN [Contract] AS [t14] ON [t12].[PersonId] = [t14].[PersonId]
INNER JOIN [ContractVersion] AS [t15] ON [t14].[ContractId] = [t15].[ContractId]
WHERE ([t5].[Name] = [t12].[Name]) AND ((([t5].[value] IS NULL) AND ([t14].[ContractType] IS NULL)) OR (([t5].[value] IS NOT NULL) AND ([t14].[ContractType] IS NOT NULL) AND ((([t5].[value] IS NULL) AND ([t14].[ContractType] IS NULL)) OR (([t5].[value] IS NOT NULL) AND ([t14].[ContractType] IS NOT NULL) AND ([t5].[value] = [t14].[ContractType])))))
GROUP BY [t15].[ContractVersionId]
) AS [t16]
) AS [number]
FROM (
SELECT [t4].[Name], [t4].[value]
FROM (
SELECT [t0].[Name], [t2].[ContractType] AS [value]
FROM [Person] AS [t0]
LEFT OUTER JOIN [Address] AS [t1] ON [t0].[PersonId] = [t1].[PersonId]
LEFT OUTER JOIN [Contract] AS [t2] ON [t0].[PersonId] = [t2].[PersonId]
INNER JOIN [ContractVersion] AS [t3] ON [t2].[ContractId] = [t3].[ContractId]
) AS [t4]
GROUP BY [t4].[Name], [t4].[value]
) AS [t5]
几乎可以产生我想要的结果,并且花费的时间是原始tsql的20倍。
答案 0 :(得分:1)
尝试关注
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Context db = new Context();
var results = (from p in db.Person
join a in db.Address on p.PersonId equals a.PersonId
join c in db.Contract on p.PersonId equals c.PersonId
join cv in db.ContractVersion on c.ContractId equals cv.ContractId
select new { p = p, a = a, c = c, cv = cv}
).GroupBy(x => new { name = x.p.Name, contractType = x.c.ContractType })
.Select(x => new {
name = x.Key.name,
numberOfAddresses = x.GroupBy(y => y.a.Street).Count(),
contractType = x.Key.contractType,
number = x.GroupBy(y => y.cv.ContractVersionId).Count(),
lastChangeDate = x.OrderByDescending(y => y.cv.ChangedDate).FirstOrDefault().cv.ChangedDate
})
.ToList();
}
}
public class Context
{
public List<Person> Person { get; set; }
public List<Address> Address { get; set; }
public List<Contract> Contract { get; set; }
public List<ContractVersion> ContractVersion { get; set; }
}
public class Person
{
public string Name { get; set; }
public string PersonId { get; set; }
}
public class Address
{
public string PersonId { get; set; }
public string Street { get; set; }
public DateTime ChangedDate { get; set; }
}
public class Contract
{
public string PersonId { get; set; }
public string ContractType { get; set; }
public string ContractId { get; set; }
}
public class ContractVersion
{
public string ContractId { get; set; }
public DateTime ChangedDate { get; set; }
public string ContractVersionId { get; set; }
}
}
这是第二条查询,运行速度可能更快:
var results = db.Person.Select(p => new {
Person = p,
Address = db.Address.Where(a => p.PersonId == a.PersonId),
Contract = db.Contract.Where(c => p.PersonId == c.PersonId),
ContractVersion = db.ContractVersion.Where(cv => p.PersonId == cv.ContractId)
}).GroupBy(x => new { name = x.Person.Name, contractType = x.Contract.FirstOrDefault().ContractType})
.Select(x => new
{
name = x.Key.name,
numberOfAddresses = x.Select(y => y.Address.SelectMany(z => z.Street)).Count(),
contractType = x.Key.contractType,
number = x.GroupBy(y => y.ContractVersion.SelectMany(z => z.ContractVersionId)).Count(),
lastChangeDate = x.SelectMany(y => y.ContractVersion.Select(z => z.ChangedDate)).OrderByDescending(y => y).FirstOrDefault()
})
.ToList();
答案 1 :(得分:1)
不确定EF Core如何有条件地支持Count
,因此仅使用Sum
进行仿真。
var query =
from p in Persons
join a in Addresses on p.PersonId equals a.PersonId into addressGroup
from a in addressGroup.DefaultIfEmpty()
join c in Contracts on p.PersonId equals c.PersonId into contractGroups
from c in contractGroups.DefaultIfEmpty()
join cv in ContractVersions on c.ContractId equals cv.ContractId in versionsGroup
from cv in versionsGroup.DefaultIfEmpty()
group new { a, cv } by new { p.Name, c.ContractType } into g
select new
{
g.Key.Name,
NumberOfAddresses = g.Sum(x => x.a.Street != null ? 1 : 0),
g.Key.ContractType,
Number = g.Sum(x => x.cv.ContractVersionId != null ? 1 : 0),
LastChangeDate = g.Max(x => x.cv.ChangedDate)
}