【问题标题】:Entity Framework Complex LINQ Support实体框架复杂 LINQ 支持
【发布时间】:2011-05-29 01:32:21
【问题描述】:

我知道 Entity Framework 存在一些 LINQ 支持问题(至少与其前身 LINQ to SQL 相比)......而且通常我能够找到一种创造性的方式来重组我的 LINQ 查询,以便它得到 EF 的支持并且不会抛出

"Unable to create a constant value of type ..."

但这一次我遇到了麻烦。像往常一样,这个问题与复杂的连接有关。这次需要对我正在处理的一些遗留数据进行建模。

我有一个办公室查询(一个简单的 POCO)

public IQueryable<Office> Offices
{
    get
    {
        IQueryable<Office> query = 
            from pn in _context.Locations
            where pn.Type == "Y"
            select new Office
            {
                Id = pn.Id  + 1000,
                Name = pn.Name,
            };

        query = query.Union(
            from r in _context.Resources
            where r.ResourceType == "L"
            select new Office
            {
                Id = r.ResourceId,
                Name = r.ResourceName,
            });

        return query;
    }
}

然后我有其他东西,上面有 Office 属性。

public IQueryable<ScheduleEntry> ScheduleEntries
{
    get
    {
        return 
            from pc in _context.CalendarEntries
            join o in this.Offices on pc.LocationId 
                equals o.Id into offices
            from office in offices.DefaultIfEmpty()
            let mainOffice = this.Offices.First()
            select new ScheduleEntry
            {
                Id = pc.CalendarId,
                StartDateTime = pc.StartDateTime ?? DateTime.MinValue,
                EndDateTime = pc.EndDateTime ?? DateTime.MinValue,
                Office = pc.LocationId == 0 ? mainOffice : office,
            };
    }
}

请注意,告诉我将其设为可枚举会破坏目的......所以请不要这样做。

所以....做CalendarEntries.ToArray() 抛出"Unable to create a constant value of type Office"...

具体的问题是let mainOffice = Offices.First()。如果我删除该逻辑,则查询工作正常。知道如何使用 Entity Framework 进行这项工作吗?

谢谢。

【问题讨论】:

  • 哇。 “糟糕的 LINQ 支持?”我认为你应该编辑掉这个问题的情绪或风险,因为这个问题是主观的和有争议的。坚持到底。​​span>
  • EF 没有较差的 linq 支持。它不依赖于存储。 Linq to sql 基本上是 SQL Server 代码生成,而 EF 是真正的 ORM。这意味着计算的属性只有在任何数据存储(不仅仅是 SQL Server)中都可以使用的情况下才有效。这不是糟糕的支持,只是通用数据存储支持。
  • 这听起来更像是威胁而不是建议。不过很公平,我在寻求帮助,而不是威胁。
  • @Gats:我不认为使用产品功能是对其失败的充分防御。前进一步后退两步并不是成功的定义。
  • @Gats:我完全了解 IQueryProvider 的工作方式。说这是因为数据存储的工作方式不准确/不正确。完全有可能以多种方式执行上述类型的查询,所有数据存储独立。 FRAMEWORK 是无法做到的。如果这是一个权衡,那么权衡是 EF 团队决定他们无法弄清楚如何或没有足够的时间来做到这一点。考虑到 EF 的前身可以做到这一点没有问题,我认为这是一个失败。

标签: .net linq entity-framework entity-framework-4


【解决方案1】:

是的,看起来双重查询正在绊倒它。唯一的选择是离开加入办公室或执行以下操作:

       Office mainOffice = Offices.First();
       return from pc in _context.CalendarEntries
               join o in Offices on pc.LocationId equals o.Id into offices
               from office in offices.DefaultIfEmpty()
               select new ScheduleEntry
                          {
                              Id = pc.CalendarId,
                              StartDateTime = pc.StartDateTime ?? DateTime.MinValue,
                              EndDateTime = pc.EndDateTime ?? DateTime.MinValue,
                              Office = pc.LocationId == 0 ? mainOffice : office,
                          };

我假设您不想这样做是因为抱怨将其设置为 IEnumerable,因此您需要加入可查询的办公室,了解如何告诉 EF 如何将查询串在一起。让 x = y 或 value = value 寻找一个我认为有意义的常数。

【讨论】:

  • 我得到相同的“无法创建类型的常量值...”异常。
  • 深入研究并编辑建议。抱歉草率,但试图回答我自己的问题并陷入了这个问题:D
  • 谢谢。这样做我得到了同样的错误......但是如果我预先获得主要办公室 ID:var mainOfficeId = Offices.First().Id,然后在查询的第二次连接中使用该 ID,它就可以工作......不理想,但它有效。
  • 谢谢。不过,就在您之前的观点...无法完全按照您在上面的示例中所做的操作: pc.LocationId == 0 ? mainOffice:office,其中 office 是查询的一部分,而 mainOffice 是一个局部变量,与数据存储或 SQL 服务器或任何东西无关,除了 EF 实现其 IQueryProvider 的投影组件的方式。没有理由您的示例不应该能够工作......但它没有。
  • 同意。可以理解,他们无法构造整个对象以传递给选择结果,但我确实认为他们可以做一些事情来填充指针或其他东西。除了 Linq 到 sql 的比较之外,我也分享您对运行时错误的挫败感。
【解决方案2】:

First 在构造表达式树时执行查询,因此它会尝试将 Office 作为参数传递给您的查询,但这是无法完成的。

替换First 的一种方法是调用this.Offices.Take(1)

【讨论】:

  • 这也会产生相同的“无法创建类型的常量值”错误。另外 - 如果表达式树是较大表达式树的一部分,则在构造表达式树时,First 不会执行查询。也就是说,在我提供的原始示例中,它是作为 Method First 的 MethodCallExpression 创建的……它不是在构造时直接执行的。
  • @Jeff:我刚刚在另一个查询中测试了First,一旦我在子查询中使用它,我得到一个异常:方法“First”只能用作最终查询操作。考虑在这种情况下使用“FirstOrDefault”方法。所以我仍然认为First不能在查询中使用,但FirstOrDefault可以。
  • 好点!...但这仍然是 EF 提供程序的功能,而不是创建表达式树的方式。我只是尝试用 FirstOrDefault() 替换示例中的 First() ,但我仍然得到相同的“无法创建常量值...”异常...
  • 我仍然对Take(1) 不起作用感到惊讶——我之前成功地使用过它而不是First。看起来 EF 提供程序不喜欢在查询中组合不同结果集的方式,因为通常您的子查询应该必须为带有 pc.LocationId == 0 的每条记录执行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 2017-07-07
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多