【问题标题】:Cannot be translated into a LINQ to Entities store expression无法转换为 LINQ to Entities 存储表达式
【发布时间】:2013-11-25 00:12:13
【问题描述】:

我对 LINQ-to-Entities 比较陌生,但经常使用 LINQ-to-SQL。

我正在使用带有实体框架 6 和 MVC 5 的 Visual Studio 2013。

两者之间的最大区别在于,Linq2SQL 能够在 SELECT 查询本身内部执行转换,而 LINQ2Entities 则不那么宽容,必须在执行 LINQ 查询之前进行正确的转换。因此,我收到错误:

“BillYeagerDB.EdmxExtensionMethods”类型上的指定方法“System.Decimal ConvertToDecimal(Byte)”无法转换为 LINQ to Entities 存储表达式。

经过大量研究,尤其是在 Stack Overflow 上的这个问题,我发现了一个链接 (LINQ to Entities does not recognize the method 'Double Parse(System.String)' method, and this method cannot be translated into a store expression),但他正在使用 ObjectContext,而我正在使用 DbContext

我也确信它对我有用,但我认为我只是错误地设计了扩展方法(这给了我上述错误)。请注意,此特定问题与 LINQ 查询中的 AvgRating 变量有关。一旦我可以让它工作,我可以对任何其他转换进行相同类型的修复。注意AvgRating 定义为Decimal 类型,a.Rating.RatingValue 定义为Byte 类型。

如果有人能帮我解决这个问题,我将不胜感激。

这是我的代码。我正在尝试使用以下查询,但由于转换问题,我知道它不会起作用(如前所述)。

原始 LINQ 查询:

namespace BillYeagerDB
{
    public class BillYeagerDB
    {
        public async Task<List<RestaurantList>> GetRestaurantListAsync()
        {
            try
            {
                using (BillYeagerEntities DbContext = new BillYeagerEntities())
                {
                    DbContext.Database.Connection.Open();

                    var restaurants = await DbContext.Restaurants.GroupBy(g => g).Select(s =>
                        new RestaurantList()
                        {
                            Name = s.Key.Name,
                            City = s.Key.City,
                            Phone = s.Key.Phone,
                            AvgRating = s.Average(a => Convert.ToDecimal(a.Rating.RatingValue)),
                            NbrOfPeopleRating = s.Distinct().Count(c => Convert.ToBoolean(c.RatingId)),
                            Id = s.Key.Id
                        }).ToListAsync();

                    return restaurants;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

我需要更新我的 EDMX 文件

<edmx:ConceptualModels>
      <Schema Namespace="BillYeagerModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
        <Function Name="ParseDecimal" ReturnType="Edm.Decimal"> 
            <Parameter Name="bytevalue" Type="Edm.Byte" /> 
            <DefiningExpression> 
                cast(bytevalue as Edm.Decimal)
            </DefiningExpression> 
        </Function>

C# 扩展方法,它是我项目根目录中的一个类 - 不在我的 EDMX 中

namespace BillYeagerDB
{
    public partial class EdmxExtensionMethods : DbContext
    {
        [DbFunctionAttribute("BillYeagerDB", "ParseDecimal")]
        public static Decimal ParseDecimal(byte bytevalue)
        {
            return Convert.ToDecimal(bytevalue);
        }
    }
}

更新了 Linq 查询 - 注意没有设计时编译错误并且项目编译成功

namespace BillYeagerDB
{
    public class BillYeagerDB
    {
        public async Task<List<RestaurantList>> GetRestaurantListAsync()
        {
            try
            {
                using (BillYeagerEntities DbContext = new BillYeagerEntities())
                {
                    DbContext.Database.Connection.Open();

                    var restaurants = await DbContext.Restaurants.GroupBy(g => g).Select(s =>
                        new RestaurantList()
                        {
                            Name = s.Key.Name,
                            City = s.Key.City,
                            Phone = s.Key.Phone,
                            AvgRating = s.Average(a => EdmxExtensionMethods.ConvertToDecimal(a.Rating.RatingValue)),
                            NbrOfPeopleRating = s.Distinct().Count(c => Convert.ToBoolean(c.RatingId)),
                            Id = s.Key.Id
                        }).ToListAsync();

                    return restaurants;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

【问题讨论】:

  • 您应该能够直接在查询中将字节转换为不同的类型,而无需使用自定义方法。也许不是直接加倍(我不确定),但如果不是,中间转换应该可以工作,也许是 byte -> int -> double。
  • 您自己的解决方案也适用于我;您应该将其作为答案发布并接受,以便我们投票!

标签: c# .net asp.net-mvc entity-framework linq-to-entities


【解决方案1】:

我知道我参加聚会有点晚了,但对于任何使用 Google 搜索的人来说:

我遇到了这个问题,事实证明 DbFunctionAttribute 所在的类必须与 edmx 架构具有相同的命名空间。

所以在这种情况下,要么将 edmx 模式命名空间更改为 BillYeagerDB,
或将 EdmxExtensionMethods 命名空间更改为 BillYeagerModel

【讨论】:

    【解决方案2】:

    尝试将您的选择方法重写为:

    var restaurants = await DbContext.Restaurants.GroupBy(g => g).ToListAsync();
    return restaurants.Select(s =>
      new RestaurantList()
      {
        Name = s.Key.Name,
        City = s.Key.City,
        Phone = s.Key.Phone,
        AvgRating = s.Average(a => Convert.ToDecimal(a.Rating.RatingValue)),
        NbrOfPeopleRating = s.Distinct().Count(c => Convert.ToBoolean(c.RatingId)),
        Id = s.Key.Id
      });
    

    【讨论】:

    • -1 因为这会强制检索不感兴趣的数据,并且如果禁用延迟加载会抛出异常。
    • 在这种情况下会从数据库中获取什么样的无趣数据?还有什么其他方法可以避免 EF 对调用“未翻译的”.NET 方法的限制? Linq2Sql?
    • 所有未投影的餐厅数据仍将被检索。将使用单独的查询来检索每个餐厅的a.Rating(如果任何餐厅没有评级,或者如果延迟加载被禁用,则为例外)。至于另一种方式,请参阅我对该问题的评论。
    • Dmytro,这是我最初的查询导致了整个问题。 Linq2Entities 无法进行像 Linq2SQL 这样的内联转换,这会导致“无法转换为 LINQ to Entities 存储表达式”错误。我已经阅读了很多关于此的 pof 帖子,但我认为我在“我需要对我的 EDMX 文件执行的更新”或我写的“C# 扩展方法”中遗漏了一些东西。有什么想法可以解决这个问题吗?
    • hvd,将不会检索餐厅数据,因为原始形式的查询会导致“无法转换为 LINQ to Entities 存储表达式”。
    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 2015-04-02
    • 1970-01-01
    相关资源
    最近更新 更多