【问题标题】:Only parameterless constructors and initializers are supported in LINQ to Entities messageLINQ to Entities 消息中仅支持无参数构造函数和初始化程序
【发布时间】:2013-06-26 09:36:58
【问题描述】:

我有一个从 EF 模型返回数据的方法。

我收到了上述消息,但我不知道如何规避问题。

    public static IEnumerable<FundedCount> GetFundedCount()
    {
        var today = DateTime.Now;
        var daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);

        var day1 = DateTime.Now.AddDays(-1);
        var day31 = DateTime.Now.AddDays(-31);

        using (var uow = new UnitOfWork(ConnectionString.PaydayLenders))
        {
            var r = new Repository<MatchHistory>(uow.Context);

            return r.Find()
                .Where(x =>
                    x.AppliedOn >= day1 && x.AppliedOn <= day31 &&
                    x.ResultTypeId == (int)MatchResultType.Accepted)
                .GroupBy(x => new { x.BuyerId, x.AppliedOn })
                .Select(x => new FundedCount(
                    x.Key.BuyerId,
                    x.Count() / 30 * daysInMonth))
                .ToList();
        }
    }

FundedCount 不是 EF 实体,MatchHistory 是,所以无法理解它为什么抱怨。

感谢所有建议。

【问题讨论】:

  • 我今天注意到调用 DateTime 构造函数,例如new DateTime(2015, 1, 1) 会抛出这个错误。神秘!

标签: c# linq linq-to-entities


【解决方案1】:

它抱怨的原因是它不知道如何将您的Select() 转换为 SQL 表达式。如果您需要对不是实体的 POCO 进行数据转换,则应先从 EF 获取相关数据,然后再将其转换为 POCO。

在您的情况下,它应该像之前调用 ToList() 一样简单:

return r.Find()
        .Where(x => x.AppliedOn >= day1 && x.AppliedOn <= day31 &&
                    x.ResultTypeId == (int)MatchResultType.Accepted)
        .GroupBy(x => new { x.BuyerId, x.AppliedOn })
        .ToList() // this causes the query to execute
        .Select(x => new FundedCount(x.Key.BuyerId, x.Count() / 30 * daysInMonth));

不过,请注意这一点,并确保尽可能限制ToList() 返回的数据集的大小,以免尝试将整个表加载到内存中。

【讨论】:

  • 这可能会失败,因为您有一个 GroupBy 而没有指定聚合。这将失败或返回 IGroupings 中的所有底层对象
  • 表格将包含 500k 行 - 在分组 20 行之后。
  • 在这种情况下,它应该可以正常运行,因为分组将在高效的服务器上进行,并且在内存中处理 20 行将非常快。
  • 从不使用 EF 的唯一原因
【解决方案2】:

消息很清楚:linq to entity 不支持没有无参数 ctor 的对象。

所以

解决方案1

在之前枚举(或使用中间匿名类型并在该类型上枚举)

.ToList()
.Select(x => new FundedCount(
                    x.Key.BuyerId,
                    x.Count() / 30 * daysInMonth))
                .ToList();

解决方案2

向 FundedCount 类添加一个无参数的 ctor(如果可能的话)

public FundedCount() {}

并使用

.Select(x => new FundedCount{
                        <Property1> = x.Key.BuyerId,
                        <Property2> = x.Count() / 30 * daysInMonth
                         })
                    .ToList();

【讨论】:

  • 这个Solution2是最好的imo,因为没有中间的ToList(),因此也没有中间的SQL执行。谢谢!
【解决方案3】:

它在抱怨,因为它无法将对 FundedCount 的引用转换为 SQL 语句。

所有 LINQ 提供程序都将 LINQ 语句和表达式转换为其目标可以理解的操作。 LINQ to SQL 和 LINQ to EF 将 LINQ 转换为 SQL,PLINQ 将其转换为任务和并行操作,LINQ to Sharepoint 将其转换为 CAML 等。

如果他们无法进行转换,会发生什么情况,取决于提供商。一些提供程序将返回中间结果并将查询的其余部分转换为 LINQ to Objects 查询。其他人只会失败并显示错误消息。

在与数据库通信时,消息失败实际上是一个更好的选择。否则,当实际只需要 1 或 2 列时,服务器必须将所有列返回给客户端。

在您的情况下,您应该修改您的选择以返回带有所需数据的匿名类型,调用 ToList() 然后创建 FundedCount 对象,例如:

.Select( x=> new {Id=x.Key.BuyerId,Count=x.Count()/30 * daysInMonth)
.ToList()
.Select(y => new FundedCount(y.Id,y.Count))
.ToList();

第一个 ToList() 将强制生成 SQL 语句并执行只返回您需要的数据的查询。查询的其余部分实际上是 Linq to Objects 并将获取数据并创建最终对象

【讨论】:

    【解决方案4】:

    我在 GroupBy 中遇到了同样的例外。我发现异常“LINQ to Entities 仅支持无参数构造函数和初始化程序”不是 100% 准确的描述。

    我在“Linq to EntityFramework 查询”中有一个 GroupBy(),它使用结构作为 GroupBy 中的键。那没有用。当我将该结构更改为普通类时,一切正常。

    代码示例

    var affectedRegistrationsGrouped = await db.Registrations
      .Include(r => r.Person)
      .Where(r =>
          //whatever
      )
      .GroupBy(r => new GroupByKey
      {
          EventId = r.EventId, 
          SportId = r.SportId.Value
      })
     .ToListAsync();
    
    ...
    ...
    // this does not work
    private struct GroupByKey() {...}
    
    // this works fine
    private class GroupByKey() {...}
    

    【讨论】:

    • 哈,它卡在 struct 关键字上。迟到的谢谢!
    猜你喜欢
    • 1970-01-01
    • 2014-07-17
    • 2015-07-31
    • 1970-01-01
    相关资源
    最近更新 更多