我有一个关系划分问题,我试图在实体框架中解决。
我有2张桌子;东西和东西。 每个东西都可以有很多东西。
我必须使用的唯一DbSet是包含ThingId和相关StuffId的Stuff和Thing的标准化视图。
我在一组条件下查询Things视图,然后需要选择结果集中存在相关Stuff的所有东西的东西。即如果在应用Where条件后任何东西缺少东西,则删除与该东西相关的所有东西。
我生成的查询似乎有效,但运行方式太慢,通常会遇到SQL超时。我需要它快速运行。
以下是我的例子:
public IQueryable<Thing> GetCompleteThingsWhere
(Expression<Func<BetSelection, bool>> conditions)
{
var filteredThings = this._dbContext.GetQuery<Thing>().Where(conditions);
var allThings = this._dbContext.GetQuery<Thing>();
var allThingsForFilteredThings =
allThings.Where(x => filteredThings.Any(y => y.StuffId == x.StuffId));
var missingThingsFromFilteredThings =
allThingsForFilteredThings.Where(x => filteredThings
.All(y => y.ThingId != x.ThingId));
var completeStuffThings =
filteredThings.Where(x => !missingThingsFromFilteredThings
.Any(y => x.StuffId == y.StuffId));
return completeStuffThings;
}
查询大约需要6分钟才能运行,SQL看起来非常低效,在WHERE子句的子查询中执行原始的WHERE条件。
进一步说明:
Stuff and Things的样本数据
STUFF THING
__________ ____________________
| StuffId | | ThingId | StuffId |
|1 | |1 |1 |
|2 | |2 |1 |
| | |3 |1 |
| | |4 |2 |
| | |5 |2 |
| | |6 |2 |
让我们说条件参数过滤一组事物,以便我们得到结果集:
Results
____________________
| ThingId | StuffId |
|1 |1 |
|4 |2 |
|5 |2 |
|6 |2 |
结果集中没有与StuffId 1相关的2个内容,所以现在我想从结果集中删除StuffId 1的所有内容,只留下完整的Stuff
Results
____________________
| ThingId | StuffId |
|4 |2 |
|5 |2 |
|6 |2 |
答案 0 :(得分:0)
我设法通过将查询分解为较小的查询,将查询执行时间从6分钟缩短到不到一秒,以便条件查询首先执行一次,只提供一组ID,以便在执行时执行关系划分而不是让EF生成子查询。
public IQueryable<Thing> GetCompleteThingsWhere
(Expression<Func<BetSelection, bool>> conditions)
{
var filteredThings = base.Filter(conjunction)
.Select(thing => new { thing.StuffId, thing.ThingId})
.ToArray();
var filteredThingsStuffIds = filteredThings
.Select(arg => arg.StuffId)
.Distinct()
.ToArray();
var filteredThingsThingIds = filteredThings
.Select(arg => arg.ThingId)
.Distinct()
.ToArray();
var allThings = this.GetAll();
var allThingsForFilteredBets =
allThings.Where(x => filteredThingsStuffIds.Contains(x.StuffId));
var missingThingsFromFilteredThingsStuffIds =
allThingsForFilteredBets.Where(x => !filteredThingsThingIds.Contains(x.ThingId))
.Select(thing => thing.StuffId)
.ToArray();
var completeBets =
allThingsForFilteredBets
.Where(x => !missingThingsFromFilteredThingsStuffIds.Contains(x.StuffId));
return completeBets;
}
答案 1 :(得分:0)
所以,如果我理解你,你想要所有东西属于东西所有东西都符合某些条件?
public IQueryable<Thing> GetCompleteThingsWhere
(Expression<Func<BetSelection, bool>> conditions)
{
return this._dbContext.GetQuery<Stuff>().Where(e => e.Things.All(conditions))
.Select(e => e.Things);
}
使用标准化的StuffThing(参见注释):
public IQueryable<Thing> GetCompleteThingsWhere
(Expression<Func<BetSelection, bool>> conditions)
{
return this._dbContext.GetQuery<StuffThing>()
.GroupBy(e => e.StuffId) // Denormalize
.Where(g => g.All(conditions))
.SelectMany(g => g);
}