实施实体框架关系部门

时间:2016-10-07 13:26:52

标签: c# entity-framework relational-division

我有一个关系划分问题,我试图在实体框架中解决。

我有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        |

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);
}