小编典典

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

c#

尝试运行报告时收到错误消息。问题在这里: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);
    }
}

阅读 318

收藏
2020-05-19

共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.ParseYourObjectContext.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规范功能列表来查看将哪些有效内容放入<DefiningExpression>标签中。

2020-05-19