在 LINQ 表达式中使用方法的解决方法

发布于 2025-01-08 10:16:58 字数 775 浏览 0 评论 0原文

在我的 ASP.NET MVC3 应用程序中,我有以下使用 EF 实体 的方法:

public IQueryable<Products> GetCreatedProducts(int year)
{
        return GetAllProducts().Where(m => Equals(DateUtilities.ExtractYear(m.ProductCreationDate), year));
}

ProductCreationDate 是作为字符串存储在数据库中的字段 >“YYYYMMddhhmm”

int DateUtilities.ExtractYear(string date) 是我为了从字符串中获取年份而创建的方法。同样,我使用 ExtractMonthExtractDay

但是,当我执行应用程序时,它会启动 NotSupported 异常

“LINQ to Entities 无法识别“Int32 ExtractYear(System.String)”方法,并且此方法无法转换为存储表达式。”

通过谷歌搜索这个问题,我发现这是 LINQ to Entities 中的一个错误 有人知道解决方法吗?

In my ASP.NET MVC3 application I have the following method that use EF entities:

public IQueryable<Products> GetCreatedProducts(int year)
{
        return GetAllProducts().Where(m => Equals(DateUtilities.ExtractYear(m.ProductCreationDate), year));
}

ProductCreationDate is a field stored in the database as string "YYYYMMddhhmm".

int DateUtilities.ExtractYear(string date) is a method that I created in order to get the year from the string. Similarly I use ExtractMonth and ExtractDay.

However when I execute my application it launches an NotSupported exception:

"LINQ to Entities does not recognize the method 'Int32 ExtractYear(System.String)' method, and this method cannot be translated into a store expression."

By googling the problem I found out that it is a bug in LINQ to Entities Anybody knows a workaround?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

呢古 2025-01-15 10:16:58

我的第一个问题是为什么要将日期作为字符串存储在数据库中?将其存储为日期并通过 Linq 对其进行数据比较。

您遇到的问题是 Linq 在尝试将 Linq 语句编译为原始 SQL 时不理解方法 ExtractYear 是什么

编辑
另一种替代方法是在数据库中创建一个视图,并使用将字符串值表示为日期时间的计算列对该视图进行查询。

My first question would be why are you storing a date in the database as a string? Store it as a date and use data comparison against it through Linq.

The issue that you're coming up against is Linq doesn't understand what the method ExtractYear is when it tries to compile your Linq statement to raw SQL

EDIT
Another alternative would be to create a view in the database and query against the view with a computed column that represents the string value as a datetime.

戒ㄋ 2025-01-15 10:16:58

在这种情况下,您可以采用另一种方式:

GetAllProducts().Where(m => m.ProductCreationDate.StartsWith(year.ToString()));

不是从字符串中提取年份,而是查找以您要查找的年份开头的所有字符串。

我不确定这些是否适用于月份和日期搜索:

var monthString = String.Format("{0:00}", month);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(4,2) == monthString);  

var dayString = String.Format("{0:00}", day);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(6,2) == dayString);

In this case you could go the other way:

GetAllProducts().Where(m => m.ProductCreationDate.StartsWith(year.ToString()));

Rather than extract the year from the string, find all strings beginning with the year you're after.

I'm not sure if these will work for the Month and Day searches:

var monthString = String.Format("{0:00}", month);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(4,2) == monthString);  

var dayString = String.Format("{0:00}", day);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(6,2) == dayString);
孤独患者 2025-01-15 10:16:58

我不认为这实际上是一个错误,而是一个限制——没有 SQL 版本的 ExtractYear,因此不可能执行此查询。

您必须重写查询以仅使用 SQL 兼容的命令(如其他一些答案所示)或从数据库中提取大量数据并使用 LINQ-to-Objects 进行过滤(这可能非常昂贵) ,具体取决于您要查询的内容以及匹配的记录数量)。

I don't think this is really a bug so much as a limitation -- there's no SQL version of ExtractYear, so it's not possible to execute this query.

You'll have to rewrite the query to either use only SQL-compatible commands (like some other answers have shown) or pull lots of data out of the database and do the filtering with LINQ-to-Objects (this could potentially be very expensive, depending on what you're querying and how many of the records match).

清泪尽 2025-01-15 10:16:58

您会收到异常,因为您使用 IQueryable。实体框架将尝试将 where 子句中的谓词转换为 SQL,但 EF 不知道如何转换您的方法。

如果您不想(或不能)更改数据库,您仍然有几个选择:

  1. 将所有行拉到客户端并在客户端上进行过滤。您可以通过从 IQueryable 更改为 IEnumerable 来实现此目的:

    返回 GetAllProducts()
      .AsEnumerable()
      .Where(m => 等于(DateUtilities.ExtractYear(m.ProductCreationDate), 年))
      .AsQueryable();
    
  2. 为了提高效率,您可以使用自己的 SQL(这需要 EF 4.1,并且只能避免将所有产品拉到客户端,而不是服务器上的扫描):

    返回上下文
      。产品
      .SqlQuery("从产品中选择*,其中子字符串(ProductCreationDate, 1, 4) = '2012'")
      .AsQueryable();
    

    请注意,我很懒,对 SQL 进行了硬编码。您可能应该对其进行参数化,并确保避免任何 SQL 注入攻击。

You get the exception because you work with IQueryable. Entity Framework will try to translate the predicate in the where clause into SQL but EF doesn't know how to translate your method.

If you don't want to (or can't) change the database you still have a few options:

  1. Pull all rows to the client side and do the filtering on the client. You do this by changing from IQueryable to IEnumerable:

    return GetAllProducts()
      .AsEnumerable()
      .Where(m => Equals(DateUtilities.ExtractYear(m.ProductCreationDate), year))
      .AsQueryable();
    
  2. To be more efficient you can use your own SQL (this requires EF 4.1 and only avoid pulling all products to the client, not the scan on the server):

    return context
      .Products
      .SqlQuery("select * from Products where substring(ProductCreationDate, 1, 4) = '2012'")
      .AsQueryable();
    

    Note that I was lazy and hardcoded the SQL. You should probably parametrize it and make sure you avoid any SQL injection attacks.

鲜肉鲜肉永远不皱 2025-01-15 10:16:58

您可以进行内联提取,如下所示:

public IQueryable<Products> GetCreatedProducts(int year)
{
        string sYear = year.ToString();
        return GetAllProducts().Where(m => m.ProductCreationDate.Substring(0,4) == sYear);
}

You could do the extraction inline, something like this:

public IQueryable<Products> GetCreatedProducts(int year)
{
        string sYear = year.ToString();
        return GetAllProducts().Where(m => m.ProductCreationDate.Substring(0,4) == sYear);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文