【问题标题】:How do I prevent a "Not supported in LINQ to Entities" exception when creating an IPagedList?创建 IPagedList 时如何防止“LINQ to Entities 不支持”异常?
【发布时间】:2016-12-29 23:23:49
【问题描述】:

我正在 ASP.NET MVC 5 中创建一个 Web 应用程序,并且需要使用数据库获取一些数据。获得数据后,我想使用它创建一个IPagedList 对象。但是,我发现此功能会生成一个异常,指出Type CurrentSite is not supported in LINQ to Entities。反之,仅获取数据而不创建 IPagedList 时,则不会发生这种情况。

public ActionResult GetComputers(int? SiteID)
{
    //This works
    IQueryable<Computer> computers = db.Computers.Where(c => c.CurrentSite.ID == SiteID);

    //This doesn't - It throws the LINQ to Entities exception
    IPagedList<Computer> computers = db.Computers.Where(c => c.CurrentSite.ID == SiteID).ToPagedList(1, 25);
}

如何在不向我的数据库表中添加CurrentSite 列的情况下使用获得的数据创建IPagedList 对象?

更新: 这是CurrentSite 属性背后的逻辑。

public ComputerSites CurrentDeployment
{
    get
    {
        if (this.ComputerSites == null)
        {
            return null;
        }
        else
        {
            return this.ComputerSites.Where(cs => DateTime.Now.IsBetween(cs.StartDate, cs.EndDate) && cs.Deleted == false).OrderBy(cs => cs.StartDate).FirstOrDefault();
        }
    }
}

public Site CurrentSite
{
    get
    {
        if (this.CurrentDeployment == null)
        {
            return null;
        }
        else
        {
            return this.CurrentDeployment.Site;
        }
    }
}

【问题讨论】:

  • 你的 IPagedList 来自哪里?
  • db.Computers.Where(c =&gt; c.CurrentSite.ID == SiteID).ToList(); 工作吗?
  • @AdilMammadov 我刚刚尝试过这个并得到了同样的错误,即使在订购查询时也是如此。
  • 您应该更新您的问题并发布您的模型。我觉得你的模型有问题。
  • 我建议你改变逻辑。您的模型看起来不正确。

标签: c# asp.net database entity-framework linq


【解决方案1】:

IQueryable 不会抛出异常,因为您只是在构建一个表达式并且还没有执行它; Linq to Entities 还没有抛出异常,因为它还不知道它会命中它。相反,当您使用 IPagedList 时,您正在评估此表达式,这就是引发异常的原因。

简单地说,Linq 了解原始类型,但不了解您自己创建的复杂类型。虽然有一些解决方法,但如果可以的话,最好将您要在 CurrentSite 中引入的逻辑封装在 where 语句中。核心问题是,当您在属性中包含逻辑时,Linq 无法将其编译为 SQL 就绪代码以在您的数据库中进行交互。

【讨论】:

    【解决方案2】:

    PagedList 在内部使用SkipTake (source)。

    public static IPagedList<T> ToPagedList<T>(this IEnumerable<T> superset, int pageNumber, int pageSize)
    {
        return new PagedList<T>(superset, pageNumber, pageSize);
    }
    
    
    public PagedList(IQueryable<T> superset, int pageNumber, int pageSize)
    {
        ...................
    
        // add items to internal list
        if (superset != null && TotalItemCount > 0)
            Subset.AddRange(pageNumber == 1
                ? superset.Skip(0).Take(pageSize).ToList()
                : superset.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList()
            );
    }
    

    Linq to Entities 中,Skip 仅在有序查询上受支持。所以你必须订购你的查询才能使用IPagedList

    IPagedList<Computer> computers = db.Computers
        .Where(c => c.CurrentSite.ID == SiteID)
        .OrderBy(c => c.CurrentSite.ID) // Or some other property.
        .ToPagedList(1, 25);
    

    现在它应该可以按预期工作了。

    【讨论】:

    • 我尝试像您在此答案中所做的那样订购查询,但我仍然收到相同的异常,指出不支持 CurrentSite
    • 那么你的模型有问题。你也应该提供你的模型。
    【解决方案3】:

    有时最简单的解决方案是最有效的。事实证明,您可以通过在查询中添加AsEnumerable 调用来绕过该问题,就像这样。

    db.Computers.AsEnumerable().Where(c => c.CurrentSite.ID == SiteID).ToPagedList(1, 25);
    

    现在可以正常使用了。

    【讨论】:

    • 我投了反对票,因为您不了解调用 AsEnumerable 的影响,它正在获取整个查询。
    猜你喜欢
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多