我有一个数据库查询。我可以使用原始SQL快速完成,但我真的想在LINQ中做类似的事情
declare @ruleInstanceCount int
select @ruleInstanceCount
= (select count(distinct(gri.RuleInstance_Id))
from [Group] g
left join GroupRuleInstance gri on g.id = gri.Group_Id
where g.name= @groupName)
SELECT cache.EntityKey
from RuleInstanceCurrentMembershipCacheItem cache
left join RuleInstance ri on ri.id = cache.RuleInstanceId
left join GroupRuleInstance gri on ri.id = gri.RuleInstance_Id
left join [Group] g on g.id = gri.Group_Id
where cache.IsMember = 1 and g.Name = @groupName
group by cache.EntityKey
HAVING count(cache.RuleInstanceId) = @ruleInstanceCount
order by cache.EntityKey
Yay SQL真的很快,因为我可以声明一个变量并在以后使用它
到目前为止,这是我对LINQ的最好尝试,但它的速度要慢50倍from g in ctx.Groups
where g.Name == groupName
let ruleCount = g.Rules.Select(r => r.Id).Distinct().Count()
from ri in g.Rules
from mem in ri
.CurrentMembership
.Where(m => m.IsMember)
.Select(m => new { m.EntityKey, m.RuleInstanceId, ruleCount })
group mem by mem.EntityKeyinto ekGroup
let ruleCount = ekGroup.Any() ? ekGroup.FirstOrDefault().ruleCount : 0
where ekGroup.Count() == ruleCount
orderby ekGroup.Key
select ekGroup.Key
生成的SQL有点乱(如果需要我可以发布)但是这和我手工编写的SQL有两个重要的区别。
我认为它因为1而变慢但我不知道做声明或类似的任何方式,所以它只执行一次计数。
修改
这里要求的是生成的SQL
SELECT
[Project13].[EntityKey] AS [EntityKey]
FROM ( SELECT
[Project12].[EntityKey] AS [EntityKey]
FROM ( SELECT
[Project11].[EntityKey] AS [EntityKey],
[Project11].[C1] AS [C1],
[Project11].[C2] AS [C2],
[Project11].[C3] AS [C3],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Group] AS [Extent17]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent18] ON [Extent17].[Id] = [Extent18].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent19] ON ([Extent18].[RuleInstance_Id] = [Extent19].[RuleInstanceId]) AND ([Extent19].[IsMember] = 1)
WHERE ((([Extent17].[Name] = @p__linq__0) AND ( NOT ([Extent17].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent17].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project11].[EntityKey] = [Extent19].[EntityKey])) AS [C4]
FROM ( SELECT
[Project10].[EntityKey] AS [EntityKey],
[Project10].[C1] AS [C1],
[Project10].[C2] AS [C2],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Group] AS [Extent14]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent15] ON [Extent14].[Id] = [Extent15].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent16] ON ([Extent15].[RuleInstance_Id] = [Extent16].[RuleInstanceId]) AND ([Extent16].[IsMember] = 1)
WHERE ((([Extent14].[Name] = @p__linq__0) AND ( NOT ([Extent14].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent14].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project10].[EntityKey] = [Extent16].[EntityKey])) AS [C3]
FROM ( SELECT
[Project9].[EntityKey] AS [EntityKey],
[Project9].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Group] AS [Extent11]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent12] ON [Extent11].[Id] = [Extent12].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent13] ON ([Extent12].[RuleInstance_Id] = [Extent13].[RuleInstanceId]) AND ([Extent13].[IsMember] = 1)
WHERE ((([Extent11].[Name] = @p__linq__0) AND ( NOT ([Extent11].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent11].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project9].[EntityKey] = [Extent13].[EntityKey])) AS [C2]
FROM ( SELECT
[Project7].[EntityKey] AS [EntityKey],
CASE WHEN ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Group] AS [Extent8]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent9] ON [Extent8].[Id] = [Extent9].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent10] ON ([Extent9].[RuleInstance_Id] = [Extent10].[RuleInstanceId]) AND ([Extent10].[IsMember] = 1)
WHERE ((([Extent8].[Name] = @p__linq__0) AND ( NOT ([Extent8].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent8].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project7].[EntityKey] = [Extent10].[EntityKey])
)) THEN [Project7].[C1] ELSE 0 END AS [C1]
FROM ( SELECT
[Project6].[EntityKey] AS [EntityKey],
[Project6].[C1] AS [C1]
FROM ( SELECT
[Project2].[EntityKey] AS [EntityKey],
(SELECT TOP (1)
[Project4].[C1] AS [C1]
FROM (SELECT
[Extent4].[Id] AS [Id],
(SELECT
COUNT(1) AS [A1]
FROM ( SELECT DISTINCT
[Extent5].[RuleInstance_Id] AS [RuleInstance_Id]
FROM [dbo].[GroupRuleInstance] AS [Extent5]
WHERE [Extent4].[Id] = [Extent5].[Group_Id]
) AS [Distinct2]) AS [C1]
FROM [dbo].[Group] AS [Extent4]
WHERE (([Extent4].[Name] = @p__linq__0) AND ( NOT ([Extent4].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent4].[Name] IS NULL) AND (@p__linq__0 IS NULL)) ) AS [Project4]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent6] ON [Project4].[Id] = [Extent6].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent7] ON ([Extent6].[RuleInstance_Id] = [Extent7].[RuleInstanceId]) AND ([Extent7].[IsMember] = 1)
WHERE [Project2].[EntityKey] = [Extent7].[EntityKey]) AS [C1]
FROM ( SELECT
[Distinct1].[EntityKey] AS [EntityKey]
FROM ( SELECT DISTINCT
[Extent3].[EntityKey] AS [EntityKey]
FROM [dbo].[Group] AS [Extent1]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent3] ON ([Extent2].[RuleInstance_Id] = [Extent3].[RuleInstanceId]) AND ([Extent3].[IsMember] = 1)
WHERE (([Extent1].[Name] = @p__linq__0) AND ( NOT ([Extent1].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[Name] IS NULL) AND (@p__linq__0 IS NULL))
) AS [Distinct1]
) AS [Project2]
) AS [Project6]
) AS [Project7]
) AS [Project9]
) AS [Project10]
) AS [Project11]
) AS [Project12]
WHERE (([Project12].[C2] = [Project12].[C1]) AND ( NOT ([Project12].[C3] IS NULL OR [Project12].[C1] IS NULL))) OR (([Project12].[C4] IS NULL) AND ([Project12].[C1] IS NULL))
) AS [Project13]
ORDER BY [Project13].[EntityKey] ASC
模特:
public class Group
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RuleInstance> Rules { get; set; }
}
public class RuleInstance
{
public Guid Id { get; set; }
public ICollection<Group> Groups { get; set; }
public ICollection<RuleInstanceCurrentMembershipCacheItem> CurrentMembership { get; set; }
}
public class RuleInstanceCurrentMembershipCacheItem
{
public Guid RuleInstanceId { get; set; }
public int EntityKey { get; set; }
public RuleInstance RuleInstance { get; set; }
public bool IsMember { get; set; }
}
编辑:
基于@ MarcinJuraszek的回答,我解决了以下问题:
var ruleInstances = from g in ctx.Groups
from ri in g.Rules
where g.Name == groupName
select ri.Id;
var cache = ( from g in ctx.Groups
where g.Name == groupName
from ri in g.Rules
from mem in ri.CurrentMembership
where mem.IsMember
group mem by mem.AnimalKey into akGroup
where akGroup.Count() == ruleInstances.Distinct().Count()
orderby akGroup.Key
select akGroup.Key).ToArray();
它产生以下查询
SELECT
[Project4].[EntityKey] AS [EntityKey]
FROM ( SELECT
[GroupBy1].[K1] AS [EntityKey]
FROM (SELECT
[Extent3].[EntityKey] AS [K1],
COUNT(1) AS [A1],
COUNT(1) AS [A2],
COUNT(1) AS [A3]
FROM [dbo].[Group] AS [Extent1]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Group_Id]
INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent3] ON ([Extent2].[RuleInstance_Id] = [Extent3].[RuleInstanceId]) AND ([Extent3].[IsMember] = 1)
WHERE (([Extent1].[Name] = @p__linq__0) AND ( NOT ([Extent1].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[Name] IS NULL) AND (@p__linq__0 IS NULL))
GROUP BY [Extent3].[EntityKey] ) AS [GroupBy1]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM ( SELECT DISTINCT
[Extent5].[RuleInstance_Id] AS [RuleInstance_Id]
FROM [dbo].[Group] AS [Extent4]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent5] ON [Extent4].[Id] = [Extent5].[Group_Id]
WHERE (([Extent4].[Name] = @p__linq__1) AND ( NOT ([Extent4].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent4].[Name] IS NULL) AND (@p__linq__1 IS NULL))
) AS [Distinct1] ) AS [GroupBy2]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM ( SELECT DISTINCT
[Extent7].[RuleInstance_Id] AS [RuleInstance_Id]
FROM [dbo].[Group] AS [Extent6]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent7] ON [Extent6].[Id] = [Extent7].[Group_Id]
WHERE (([Extent6].[Name] = @p__linq__1) AND ( NOT ([Extent6].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent6].[Name] IS NULL) AND (@p__linq__1 IS NULL))
) AS [Distinct2] ) AS [GroupBy3]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM ( SELECT DISTINCT
[Extent9].[RuleInstance_Id] AS [RuleInstance_Id]
FROM [dbo].[Group] AS [Extent8]
INNER JOIN [dbo].[GroupRuleInstance] AS [Extent9] ON [Extent8].[Id] = [Extent9].[Group_Id]
WHERE (([Extent8].[Name] = @p__linq__1) AND ( NOT ([Extent8].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent8].[Name] IS NULL) AND (@p__linq__1 IS NULL))
) AS [Distinct3] ) AS [GroupBy4]
WHERE (([GroupBy1].[A1] = [GroupBy2].[A1]) AND ( NOT ([GroupBy1].[A2] IS NULL OR [GroupBy3].[A1] IS NULL))) OR (([GroupBy1].[A3] IS NULL) AND ([GroupBy4].[A1] IS NULL))
) AS [Project4]
ORDER BY [Project4].[EntityKey] ASC
答案 0 :(得分:2)
您的LINQ与SQL的不同之处。首先,在您的SQL中,您有两个查询,但在LINQ中,您尝试将它们合并为一个。为什么?我试图将您的SQL转换为LINQ,我认为,生成的SQL将与原始SQL类似:
var ruleInstanceCount = (
from g in Group
join gri in GroupRuleInstance on g.id equals gri.Group_Id into gris
from gri in gris.DefaultIfEmpty()
where g.name == groupName
group gri by gri.RuleInstance_Id into grp
select new
{
Id = grp.Key
}
).Count();
var items = (
from cache in RuleInstanceCurrentMembershipCacheItem
join ri from RuleInstance on cache.RuleInstanceId equals ri.id into ris
from ri in ris.DefaultIfEmpty()
join gri from GroupRuleInstance on ri.id equals gri.RuleInstance_Id into gris
from gri in gris.DefaultIfEmpty()
join g from Group on gri.Group_Id equals g.id into gs
from g in gs.DefaultIfEmpty()
where cache.IsMember == 1 && g.Name = groupName
group cache by cache.EntityKey into grp
select new
{
Count = grp.Count(x => x.RuleInstanceId),
EntityKey = grp.Key
})
.Where(x => x.Count == ruleInstanceCount)
.OrderBy(x => x.EntityKey);
答案 1 :(得分:1)
我会尝试以下内容:
var ctx = new Context();
var groupName = "something";
var ruleInstances = from g in ctx.Groups
from gri in g.Rules.DefaultIfEmpty()
where g.Name == groupName
select gri.Id;
var keys = from c in ctx.CurrentMembership
let ri = c.RuleInstance
from g in ri.Groups.DefaultIfEmpty()
where c.IsMember && g.Name == groupName
group c by c.EntityKey into g
where g.Select(x => x.RuleInstanceId).Count() == ruleInstances.Distinct().Count()
orderby g.Key
select g.Key;
它应该给你非常接近的SQL:
SELECT cache.EntityKey
from RuleInstanceCurrentMembershipCacheItem cache
left join RuleInstance ri on ri.id = cache.RuleInstanceId
left join GroupRuleInstance gri on ri.id = gri.RuleInstance_Id
left join [Group] g on g.id = gri.Group_Id
where cache.IsMember = 1 and g.Name = @groupName
group by cache.EntityKey
HAVING count(cache.RuleInstanceId) =
(select count(distinct(gri.RuleInstance_Id))
from [Group] g
left join GroupRuleInstance gri on g.id = gri.Group_Id
where g.name= @groupName)
order by cache.EntityKey
我认为你的背景看起来接近那个:
public class Context
{
public IQueryable<Group> Groups { get; set; }
public IQueryable<RuleInstance> Rules { get; set; }
public IQueryable<RuleInstanceCurrentMembershipCacheItem> CurrentMembership { get; set; }
}