LINQ to Entities не распознает метод метода Double Parse (System.String), и этот метод нельзя преобразовать в выражение хранилища - PullRequest
16 голосов
/ 12 мая 2011

Я получаю сообщение об ошибке при попытке запустить отчет.Проблема здесь: 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 Ответ

47 голосов
/ 12 мая 2011

Проблема в том, что ваш запрос переводится в SQL и выполняется в базе данных, а Entity Framework не знает, как перевести Double.Parse в действительный код SQL. Однако вы можете определить пользовательский метод для анализа и указать Entity Framework, как преобразовать этот метод в SQL. Вот как это происходит:

Определить перевод

Откройте файл * .edmx в текстовом редакторе и найдите тег <edmx:ConceptualModels>. Под этим вы должны увидеть тег <Schema Namespace="YourModel" ...>. Внутри тега схемы добавьте следующее:

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

Это определяет код Enity-SQL, в который будет преобразована ваша пользовательская функция ParseDouble.

Создать метод для перевода

Теперь нам нужно определить соответствующую функцию в коде, которую вы можете вставить в оператор 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, его также можно преобразовать в SQL с помощью LINQ to Entities.

Но подождите, вы еще не закончили!

Я заметил, что ваш оператор 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>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...