LINQ to Entities 无法识别方法 'Double Parse(System.String)' 方法,并且此方法无法转换为存储表达式

Posted

技术标签:

【中文标题】LINQ to Entities 无法识别方法 \'Double Parse(System.String)\' 方法,并且此方法无法转换为存储表达式【英文标题】:LINQ to Entities does not recognize the method 'Double Parse(System.String)' method, and this method cannot be translated into a store expressionLINQ to Entities 无法识别方法 'Double Parse(System.String)' 方法,并且此方法无法转换为存储表达式 【发布时间】:2011-08-23 17:06:05 【问题描述】:

当我尝试运行报告时出现错误。问题出在这里:model.Referring = Math.Round(_newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question1) ? 0 : Double.Parse(m.Question1)).Average());

public class SummaryDetails

    public int ChannelId  get; set; 
    public int ChannelGroupId  get; set; 
    public string Question1  get; set; 
    public string Question2  get; set; 
    public string Question3  get; set; 
    public string Question4  get; set; 
    public int OrganizationId  get; set; 


public ActionResult AreaManager(AreaManagerModel model)

    model.ShowCustomerReport = false;
    model.ShowSurveyReport = true;
    LoadModelVariablesonPostBack(model, 8);
    var _newSurveyResult = (
        from ls in SessionHandler.CurrentContext.LennoxSurveyResponses
        join ml in SessionHandler.CurrentContext.MailingListEntries on ls.SurveyCode equals ml.SurveyCode
        join m in SessionHandler.CurrentContext.MailingLists on ml.MailingListId equals m.MailingListId
        join ch in SessionHandler.CurrentContext.Channels on m.ChannelId equals ch.ChannelId
        join cg in SessionHandler.CurrentContext.ChannelGroups on ch.ChannelGroupId equals cg.ChannelGroupId
        join dcg in SessionHandler.CurrentContext.ChannelGroups on cg.ParentChannelGroupId equals dcg.ChannelGroupId
        join ncg in SessionHandler.CurrentContext.ChannelGroups on dcg.ParentChannelGroupId equals ncg.ChannelGroupId
        join pcg in SessionHandler.CurrentContext.ChannelGroups on ncg.ParentChannelGroupId equals pcg.ChannelGroupId
        select new SummaryDetails  
            OrganizationId = ch.OrganizationId,
            Question1 = ls.Question1Answer,
            Question2 = ls.Question2Answer,
            Question3 = ls.Question3Answer,
            Question4 = ls.Question4Answer,
            ChannelId = ch.ChannelId,
            ChannelGroupId = model.TMId != 0 ? cg.ChannelGroupId : model.DistrictId != 0 ? dcg.ChannelGroupId : model.AreaId != 0 ? ncg.ChannelGroupId : model.NationId != 0 ? pcg.ChannelGroupId : model.AreaId == 0 ? ncg.ChannelGroupId : model.DistrictId == 0 ? dcg.ChannelGroupId : cg.ChannelGroupId 
        
    );
    var _newSentSurveys = (
        from ml in SessionHandler.CurrentContext.MailingListEntries
        join m in SessionHandler.CurrentContext.MailingLists on ml.MailingListId equals m.MailingListId
        join ch in SessionHandler.CurrentContext.Channels on m.ChannelId equals ch.ChannelId
        join cg in SessionHandler.CurrentContext.ChannelGroups on ch.ChannelGroupId equals cg.ChannelGroupId
        join dcg in SessionHandler.CurrentContext.ChannelGroups on cg.ParentChannelGroupId equals dcg.ChannelGroupId
        join ncg in SessionHandler.CurrentContext.ChannelGroups on dcg.ParentChannelGroupId equals ncg.ChannelGroupId
        join pcg in SessionHandler.CurrentContext.ChannelGroups on ncg.ParentChannelGroupId equals pcg.ChannelGroupId
        where (ml.EmailDate != null || ml.LetterDate != null || ml.EmailBounce == null)
        select new SummaryDetails 
         
            OrganizationId = ch.OrganizationId,
            ChannelId = ch.ChannelId,
            ChannelGroupId = model.TMId != 0 ? cg.ChannelGroupId : model.DistrictId != 0 ? dcg.ChannelGroupId : model.AreaId != 0 ? ncg.ChannelGroupId : model.NationId != 0 ? pcg.ChannelGroupId : model.AreaId == 0 ? ncg.ChannelGroupId : model.DistrictId == 0 ? dcg.ChannelGroupId : cg.ChannelGroupId 
        
    );
    if (model.ChannelId != 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelId == model.ChannelId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelId == model.ChannelId);
    
    else if (model.TMId != 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.TMId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.TMId);
    
    else if (model.DistrictId != 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.DistrictId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.DistrictId);
    
    else if (model.AreaId != 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.AreaId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.AreaId);
    
    else if (model.NationId != 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.NationId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.NationId);
    
    else if (model.NationId == 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.OrganizationId == 8);
        _newSentSurveys = _newSentSurveys.Where(p => p.OrganizationId == 8);
    
    else if (model.AreaId == 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
    
    else if (model.DistrictId == 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
    
    else if (model.TMId == 0)
    
        _newSurveyResult = _newSurveyResult.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
        _newSentSurveys = _newSentSurveys.Where(p => p.ChannelGroupId == model.LoggedChannelGroupId);
    
    model.SentSurveys = _newSentSurveys.Count() > 0 ? _newSentSurveys.Count() : 0;
    model.CompletedSurveys = _newSurveyResult.Count() > 0 ? _newSurveyResult.Count() : 0;
    model.PercentageComplete = model.SentSurveys != 0 ? (Convert.ToDouble(model.CompletedSurveys) / Convert.ToDouble(model.SentSurveys)) : 0;
    if (_newSurveyResult.Count() > 0)
    
        model.Referring = Math.Round(_newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question1) ? 0 : Double.Parse(m.Question1)).Average());
        model.ServicePerformance = Math.Round(_newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question2) ? 0 : Double.Parse(m.Question2)).Average());
        model.InstallPerformance = Math.Round(_newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question3) ? 0 : Double.Parse(m.Question3)).Average());
        model.ReferringLennox = Math.Round(_newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question4) ? 0 : Double.Parse(m.Question4)).Average());
        double overAllScore = CalculateOverallScore(
                _newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question1) ? 0 : Double.Parse(m.Question1)).Sum(),
                _newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question2) ? 0 : Double.Parse(m.Question2)).Sum(),
                _newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question3) ? 0 : Double.Parse(m.Question3)).Sum(),
                _newSurveyResult.Select(m => string.IsNullOrEmpty(m.Question4) ? 0 : Double.Parse(m.Question4)).Sum(),
                _newSurveyResult.Count());
        model.OverallScore = Math.Round(overAllScore);
    

【问题讨论】:

【参考方案1】:

这里的问题是您的查询正在被翻译成 SQL 并在数据库上运行,而 Entity Framework 不知道如何将 Double.Parse 翻译成有效的 SQL 代码。但是,您可以定义一个自定义方法来进行解析,并告诉 Entity Framework 如何将该方法转换为 SQL。事情是这样的:

定义翻译

在文本编辑器中打开您的 *.edmx 文件,然后查找 <edmx:ConceptualModels> 标签。在此之下,您应该会看到一个 <Schema Namespace="YourModel" ...> 标记。在 Schema 标记内,添加以下内容:

    <Function Name="ParseDouble" ReturnType="Edm.Double"> 
        <Parameter Name="stringvalue" Type="Edm.String" /> 
        <DefiningExpression> 
            cast(stringvalue as Edm.Double)
        </DefiningExpression> 
    </Function>

这定义了您的自定义 ParseDouble 函数将被翻译成的 Enity-SQL 代码。

创建要翻译的方法

现在我们需要在代码中定义一个匹配函数,您可以将其放入您的 LINQ 语句中。您的 EDMX 文件用于生成从 ObjectContext 继承的部分类。由于它是一个分部类,您可以在不接触生成的代码的情况下添加自己的方法 - 只需确保类名匹配即可。

using System.Data.Objects.DataClasses;

public partial class YourObjectContext

    /// <summary>
    ///     This method exists for use in LINQ queries,
    ///     as a stub that will be converted to a SQL CAST statement.
    /// </summary>
    [EdmFunction("YourModel", "ParseDouble")]
    public static double ParseDouble(string stringvalue)
    
        return Double.Parse(stringvalue);
    

现在您可以返回到您的 LINQ 语句,并将 Double.Parse 的任何实例替换为 YourObjectContext.ParseDouble。由于这是一个实际调用Double.Parse 的实际方法,因此它将适用于 LINQ to Objects 调用,并且由于它也在 EDMX 文件中定义,因此也可以通过 LINQ to Entities 将其转换为 SQL。

但是等等,你还没有完成!

我注意到您的 LINQ 语句还包括对 Math.Round 的调用。我不知道 Entity Framework 是否包含该方法的翻译,但如果不包含,则在修复 Double.Parse 的方法后,您将收到与该方法相同的错误。幸运的是,这种情况的解决方案几乎完全相同,只是 EDMX 文件中定义的函数看起来像这样:

    <Function Name="Round" ReturnType="Edm.Double"> 
        <Parameter Name="input" Type="Edm.Double" /> 
        <DefiningExpression> 
            Round(input)
        </DefiningExpression> 
    </Function>

您可以使用此EDM Canonical Functions 列表来查看在&lt;DefiningExpression&gt; 标记中放入的有效内容。

【讨论】:

除此之外,SQLFunctions 类中有一堆预定义的。 (不要认为你的在这里)。 msdn.microsoft.com/en-us/library/dd466169.aspx 对于带有 EF 的 Math.Round,您可以使用重载版本 Math.Round(1.2345, 2, MidpointRounding.AwayFromZero) linqPad 误导了我。 Math.Round(1.2345, 2, MidpointRounding.AwayFromZero) 仅适用于 linq2sql,不适用于 EF。 我需要在 Code First EF 6.1 中执行此操作。 DbFunction 不必在对象/数据库上下文中定义。它可以在任何地方定义。我已经用一个静态类对其进行了测试,允许我将它定义为扩展方法。 (我的需要:public static int? ToInt(this string stringValue)。)

以上是关于LINQ to Entities 无法识别方法 'Double Parse(System.String)' 方法,并且此方法无法转换为存储表达式的主要内容,如果未能解决你的问题,请参考以下文章

LINQ to Entities 无法识别方法 IsNullOrWhiteSpace

错误:LINQ to Entities 无法识别方法 DataLength

LINQ To Entities 无法识别方法 Last。真的吗?

LINQ To Entities 无法识别方法 Last。真的吗?

C# LINQ to Entities 无法识别方法“布尔”

我如何修复“LINQ to Entities无法识别方法”错误