1

我正在使用实体框架 5 进行这样的查询:

var query = 
    from i in context.Instrument
    from p in i.InstrumentPerformance  // 1 : n
    where p.PortfolioScenarioID == 6013
    select i;

我想在内存中存储这个(过滤的)查询的可查询表示。理想情况下,我将能够断开上下文并仍然请求特定的 InstrumentPerformance 集合,如下所示:

var perf = query.First(i => i.InstrumentID == 407240).InstrumentPerformance;

但是这 - 当然 - 不会产生所需的结果,因为“perf”对象将包含一个 InstrumentPerformance 集合,该集合包含每个 1:n 加入的 InstrumentPerformance 实体(无论其 PortfolioScenarioID 是否为 6013),并且它将通过惰性检索这些实体加载,使用 context.ContextOptions.LazyLoadingEnabled = false (或上下文超出范围)查询将不会产生任何结果。

所以这远不是我想要得到的:从原始查询中轻松查询内存中的表示。我试图具体化成字典和类似的方法,但最终为我想避免的结果编码自定义数据对象。

所以我的问题是:获得这种内存视图的推荐方法是什么?

编辑:我目前正在使用两个字典来缓存数据,例如:

var instruments = (
    from i in context.Instrument
    from p in i.InstrumentPerformance
    where p.PortfolioScenarioID == 6013
    select i)
    .ToDictionary (i => p.InstrumentID, i => i);

var performances = (
    from i in context.Instrument
    from p in i.InstrumentPerformance
    where p.PortfolioScenarioID == 6013
    select p)
    .ToDictionary (p => p.InstrumentID, p => p);

但是,这需要两次往返数据库,其中一次似乎就足够了,更重要的是查询性能数据的语义(现在是 performances[InstrumentID])与 EF 查询方式(应该是 instrument.InstrumentPerformance.First( )等)。

4

2 回答 2

1

可以先一次性检索对象,然后通过以下方式创建字典:

var query = 
    (from i in context.Instrument
    select new { 
                 i,
                 ps = i.InstrumentPerformance
                          .Where(p.PortfolioScenarioID == 6013)
               }).AsEnumerable()
               .Select(x => x.i);

这会具体化并选择Instrument实体,这里的诀窍是它们的部分加载 InstrumentPerformance的集合。即工具只包含InstrumentPerformance满足条件的实体PortfolioScenarioID == 6013。这是因为 EF 运行一个称为关系修复的过程,该过程在从数据库中获取子对象时将其关联到正确的父对象。

所以现在你可以处理上下文,之后的任何时候

var perf = query.First(i => i.InstrumentID == 407240).InstrumentPerformance;

或使用from i in query代替from i in context.Instrument.

重要提示:应禁用延迟加载,否则 EF 仍会在处理完整集合时尝试加载它们。

于 2013-06-09T22:30:47.813 回答
0

查看EntityCollection<T> CreateSourceQueryAttach。我认为你可以这样做(未经测试):

var instrumentQuery = 
    from i in context.Instrument
    from p in i.InstrumentPerformance  // 1 : n
    where p.PortfolioScenarioID == 6013
    select i;
var instruments = instrumentQuery.ToList();
foreach (var instrument in instruments) {
    var performanceQuery =
        instrument.InstrumentPerformance.CreateSourceQuery()
            .Where(p => p.PortfolioScenarioID == 6013);
    instrument.InstrumentPerformance.Attach(performanceQuery);
}

这会立即执行所有内容(没有延迟加载)并且有一些代码重复,但它会导致Instrument每个i.InstrumentPerformance返回过滤集合的位置的列表,这意味着对其进行操作的任何后续代码都可以将其视为任何其他 EF 集合,而无需需要知道查询的详细信息。

于 2013-06-09T20:44:40.713 回答