Frage LINQ to Entities erkennt die Methode 'Double Parse (System.String)' nicht und diese Methode kann nicht in einen Speicherausdruck übersetzt werden


Ich erhalte den Fehler, wenn ich versuche, den Bericht auszuführen. Das Problem ist hier: 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);
    }
}

16
2018-05-11 22:58


Ursprung


Antworten:


Das Problem besteht darin, dass Ihre Abfrage in SQL übersetzt und in der Datenbank ausgeführt wird. Entity Framework kann nicht übersetzen Double.Parse in gültigen SQL-Code. Sie können jedoch eine benutzerdefinierte Methode zum Parsen definieren und Entity Framework mitteilen, wie diese Methode in SQL übersetzt werden soll. So geht's:

Definieren Sie die Übersetzung

Öffnen Sie Ihre * .edmx-Datei in einem Texteditor und suchen Sie nach dem <edmx:ConceptualModels> Etikett. Darunter sollten Sie ein sehen <Schema Namespace="YourModel" ...> Etikett. Fügen Sie im Schema-Tag Folgendes hinzu:

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

Dies definiert den Enity-SQL-Code, in den Ihre benutzerdefinierte ParseDouble-Funktion übersetzt wird.

Erstellen Sie eine Methode, die übersetzt werden soll

Jetzt müssen wir eine passende Funktion im Code definieren, die Sie in Ihre LINQ-Anweisung einfügen können. Ihre EDMX-Datei wird zum Generieren einer partiellen Klasse verwendet, die von ObjectContext erbt. Da es sich um eine partielle Klasse handelt, können Sie Ihre eigenen Methoden hinzufügen, ohne den generierten Code zu berühren - stellen Sie einfach sicher, dass die Klassennamen übereinstimmen.

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);
    }
}

Jetzt können Sie zu Ihrer LINQ-Anweisung zurückkehren und alle Instanzen von Double.Parse mit YourObjectContext.ParseDouble. Da dies eine tatsächliche Methode ist, die tatsächlich aufruft Double.ParseEs wird bei LINQ to Objects-Aufrufen funktionieren, und da es auch in der EDMX-Datei definiert ist, kann es auch von LINQ in Entities in SQL übersetzt werden.

Aber warte, du bist noch nicht fertig!

Ich habe festgestellt, dass Ihre LINQ-Anweisung auch einen Aufruf an enthält Math.Round. Ich weiß nicht von ganzem Herzen, wenn Entity Framework eine Übersetzung für diese Methode enthält, aber wenn dies nicht der Fall ist, erhalten Sie den gleichen Fehler für diese Methode, nachdem Sie den Fehler behoben haben Double.Parse. Glücklicherweise ist die Lösung für diesen Fall fast genau dieselbe, außer dass die in der EDMX-Datei definierte Funktion ungefähr so ​​aussehen würde:

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

Sie können diese Liste verwenden Kanonische Funktionen des EDM um zu sehen, was in der <DefiningExpression> Stichworte.


47
2018-05-11 23:22