簡體   English   中英

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 expression

當我嘗試運行報告時出現錯誤。 問題在這里: 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);
    }
}

這里的問題是您的查詢正在被轉換為 SQL 並在數據庫上運行,而實體框架不知道如何將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任何實例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>標記中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM