【问题标题】:bottleneck using entity framework inheritance使用实体框架继承的瓶颈
【发布时间】:2011-08-26 21:29:14
【问题描述】:

首先是我的实体

我想要一个包含所有故事标题及其类型的页面的问题

共有三个故事LongStoryCoOpStoryGenericStory

通用故事与通用故事类型的StoryType 相关联

我有两个问题

首先,当我想检查故事是LongStory 还是CoOpStory 时,我必须获取所有实体并检查实体类型是否为LongStory 然后做一些事情,我不知道如何检索一些数据[只有标题]并检查类型

我的第二个问题就像我说的那样,我想要一个包含所有故事标题及其类型的页面,如果不进行大量查询,我不知道该怎么做,我无法加入 @987654329 @table 因为它必须是 GenericStory 才能与之关联,所以我首先要获取所有故事,然后对每个 GenericStory 进行额外查询以获取类型

【问题讨论】:

    标签: entity-framework entity-framework-4


    【解决方案1】:

    您正在寻找 OfTypeConcat 扩展方法。

    要仅获取 LongStory 实例,您只需调用:

    var longStories = context.Stories.OfType<LongStory>().ToList();
    

    要获得更大的查询,它会稍微复杂一些。您可以尝试:

    var allStories = context.Stories
                            .OfType<GenericStory>()
                            .Include("StoryType") // I'm not sure how this works with concat
                            .Concat(
                                 context.Stories.OfType<LongStory>.Concat(         
                                      context.Stories.OfType<CoOpStory>()));
    

    或者你可以做一个投影:

    var allStories = context.Stories
                            .OfType<GenericStory>()
                            .Select(s => new { s.Title, s.StoryType.Name })
                            .Concat(
                                 context.Stories
                                        .OfType<LongStory>
                                        .Select(s => new { s.Title, "LongStory" })
                                        .Concat(         
                                            context.Stories
                                                   .OfType<CoOpStory>()
                                                   .Select(s => new { s.Title, Type })));
    

    【讨论】:

    • 大声笑,我刚刚停止写作 :) allStories 查询实际上是到数据库的三个往返吗?我也想到了Concat,但参数是IEnumerable,而不是IQueryable。我不确定我们是否会获得三个往返。 context.Stories.OfType&lt;LongStory&gt;.Concat(context.Stories.OfType&lt;CoOpStory&gt;()) 可以压缩成context.Stories.Where(s =&gt; !(s is GenericStory))
    • Concat 被转换为UNION ALLUnion 简单地转换为UNION。如果没有,则无法在 linq-to-entities 中进行联合。这种压缩很酷 :) 我想过如何避免两个连接,但我没有想到。
    • 很高兴知道Concat 是如何翻译的!最后,对于问题的第一部分,我发现了一些丑陋(但有效)的东西。我想知道这是否真的不可能以更简单的方式实现。
    • 在第一个示例中使用Concat 时不能这样做,因为您将GenericStoryLongStoryCoOpStory 连接不同的类型
    • 所以如果你想cancat你必须先做一个投影?
    【解决方案2】:

    Ladislav 的回答是针对您的第二个问题。这是您第一个问题的可能解决方案。

    据我所知,您无法直接查询投影中的类型(例如,使用 GetType() 在 LINQ to Entities 中不起作用)。但是,如果您只想查询故事的标题和类型,则以下方法将起作用:

    var stories = context.Stories
        .Select(s => new
        {
            Title = s.Title,
            Type = (s is LongStory) ? "LongStory" :
                   (s is CoOpStory) ? "CoOpStory" :
                   (s is GenericStory) ? "GenericStory" :
                   (s is Story) ? "Story" : // forget this if Story is abstract
                   "Unknown"
        }).ToList();
    

    您将获得一个匿名对象列表,其中 Type 属性将类型表示为您在此查询中的自定义字符串。

    不是很好,因为每次向层次结构中添加新类时都必须更改此查询。顺序也很重要(大多数派生类必须在 Type 属性的表达式中排在第一位)。但我不知道其他方法。

    【讨论】:

    • 抱歉,不能同时将两者都标记为答案,但信息真的很棒,谢谢
    【解决方案3】:

    你尝试过这样的事情吗?

    context.Stories.OfType<LongStory>.Where(...).Cast<Story>()
     .Union(context.Stories.OfType<GenericStory>.‌​Where(...).Include(s => s.StoryType).Cast<Story>())
     .Union(context.Stories.OfType<CoOpStory>.Where(...).Cast<Story>());
    

    【讨论】:

    • 这看起来非常好,解决了连接不同类型集合的问题。不幸的是,EF 抱怨Include 路径无效并且StoryType 不是Story 类型的声明属性,我只是对其进行了测试。似乎Include 在实际应用OfType&lt;GenericStory&gt;() 之前应用到DbSet&lt;Story&gt;
    猜你喜欢
    • 1970-01-01
    • 2011-05-19
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多