«SqlException: имя переменной« @ _User_1_Id »уже объявлено» после обновления до Asp.Net Core 2.2 - PullRequest
0 голосов
/ 08 января 2019

У меня есть приложение, которое работает в Asp.Net Core 2.1.6. что я пытаюсь обновить до 2.2. Я начал получать следующее исключение SQL при использовании 2.2:

SqlException: имя переменной '@__ User_1_Id' уже было объявлен. Имена переменных должны быть уникальными в пределах пакета запроса или сохраняться процедура.

Я могу скомпилировать код, нацеленный на 2.2, но запустить его с использованием среды выполнения 2.1.6, и я не получаю сообщение об ошибке, поэтому я знаю, что что-то изменилось по сравнению с 2.1.6, которая привела к этой ошибке.

Исключение возникает при попытке получить все «Запросы на передачу», которые были «Переданы» текущему пользователю. По сути, пользователю разрешено видеть любой запрос, который был ему перенаправлен. Мое приложение использует шаблон спецификации для построения запросов, поэтому вся логика фильтрации создается путем объединения Expression объектов. Мне удалось сузить ошибку до спецификации HasBeenForwardedTo, которая используется для фильтрации списка запросов до тех, которые были направлены указанному пользователю:

public class HasBeenForwardedTo : SpecificationBase<TransferRequest>
{
    public ApplicationUser User { get; set; }

    /// <summary>
    /// Specification for determining if the request has been forwarded to the provided user.
    /// </summary>
    public HasBeenForwardedTo(ApplicationUser user)
    {
        this.User = user;
    }

    public override Expression<Func<TransferRequest, bool>> ToExpression()
    {
        // we only care about people that have been forwarded the request since the
        // last "awaiting approval" event, so ignore any "forwarded to" events that 
        // happened before then.
        var projection = CommonExpressions.LastAwaitingApprovalEvent();

        var requestParam = Expression.Parameter(typeof(TransferRequest));
        var requestToEvent = projection.Body.ReplaceParameter(projection.Parameters[0], requestParam);

        // A request is considered "forwarded to" a user if the user has a "forwarded"
        // event on the request since the last time it was "awaiting reviewing"
        Expression<Func<TransferRequest, TransferRequestEvent, bool>> condition =
           (rqst, evt) =>
                // If there are no "Awaiting Review" events, check to see if the user 
                // has any "Forwarded" events at all.
                (evt == null &&
                    rqst.TransferRequestEvents.Any(e2 =>
                        Equals(e2.EventType, EventType.Forwarded) && Equals(e2.User, User))) ||

                // If there is an "Awaiting Review" event, only use events that have 
                // occurred *after* it.
                (evt != null &&
                    rqst.TransferRequestEvents.Any(e2 =>
                        Equals(e2.EventType, EventType.Forwarded) &&
                        Equals(e2.User, User) &&
                        (e2.EventDateTime > evt.EventDateTime || (e2.EventDateTime == evt.EventDateTime && e2.Id > evt.Id))));

        //combine the expression to for a new Exression<Func<TransferRequest,bool>> 
        //consolidating their parameters.
        var body = condition.Body
                .ReplaceParameter(condition.Parameters[0], requestParam)
                .ReplaceParameter(condition.Parameters[1], requestToEvent);
        var ret = Expression.Lambda<Func<TransferRequest, bool>>(body, requestParam);
        return ret;
    }
}

Этот код использует некоторые другие вспомогательные методы.

Метод расширения для объединения выражений таким образом, что выходные данные одного выражения используются в качестве входных данных для другого выражения:

    public static Expression<Func<TSource, TResult>> Compose<TSource, TIntermediate, TResult>(
        this Expression<Func<TSource, TIntermediate>> first,
        Expression<Func<TIntermediate, TResult>> second)
    {
        var param = Expression.Parameter(typeof(TSource));
        var intermediateValue = first.Body.ReplaceParameter(first.Parameters[0], param);
        var body = second.Body.ReplaceParameter(second.Parameters[0], intermediateValue);
        return Expression.Lambda<Func<TSource, TResult>>(body, param);
    }

Метод расширения для замены всех ссылок на параметр другим параметром.

    public static Expression ReplaceParameter(this Expression expression,
        ParameterExpression toReplace,
        Expression newExpression)
    {
        return new ParameterReplaceVisitor(toReplace, newExpression)
            .Visit(expression);
    }

И ExpressionVisitor, который на самом деле выполняет работу:

public class ParameterReplaceVisitor : ExpressionVisitor
{
    private ParameterExpression from;
    private Expression to;
    public ParameterReplaceVisitor(ParameterExpression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
            return node == from ? to : base.VisitParameter(node);
    }

}
...