This is a migrated thread and some comments may be shown as answers.

[Solved] More than one grid filter gives "an item with the same key has already been added"

5 Answers 131 Views
Grid
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
-glenn-
Top achievements
Rank 1
-glenn- asked on 08 Mar 2012, 08:16 PM
Have an MVC Grid that has filterable columns. I can click the little filter button in the column header and enter some text to filter on in the first or second filter box and it works fine. If I try to enter two filter conditions, say a starts with and an ends with, I get an error "an item with the same key has already been added" trying to get the matching rows from the database.

The GridCommand object passed by the Telerik Grid to my handler method looks correct. The CompositeFilterDescriptor has two FilterDescriptor objects filled in. The first is "AccountName StartsWith 'abc' " and the second is "AccountName EndsWith 'def' ". I create a "where clause" Telerik.Web.Mvc.ExpressionBuilder:

Expression<Func<T, bool>> where = ExpressionBuilder.Expression<T>(
 command.FilterDescriptors);

I create an NHibernate Query object and feed it the where:
IQueryable<T> query = session.Query<T>();
if (where != null) query = query.Where(where);

Then try to get the count of rows that match the filter:

int rowCount = query.Count();

This call to Count gives the error. This works fine if there is only a single filter field entered into the Telerik MVC Grid's filter fields.

The where generated by the ExpressionBuilder looks OK to me. The Body contains a LogicalBinaryExpression, the left part is:

((IIF((item != null), item.AccountName, null) ?? "").ToLower().StartsWith("abc".ToLower()) == True)

and the right part is:
((IIF((item != null), item.AccountName, null) ?? "").ToLower().EndsWith("def".ToLower()) == True)

Anyone else seen this?

5 Answers, 1 is accepted

Sort by
0
Dadv
Top achievements
Rank 1
answered on 09 Mar 2012, 09:41 AM
hi,

Could you copy/paste the entire error message and the grid/controller code please?

I often see this message when i try to return a view in ajax request instead  of a partial view, so the entire page is resend (with the masterpage and the telerik script declaration). Telerik don't allow  to assign it twice.
0
-glenn-
Top achievements
Rank 1
answered on 09 Mar 2012, 02:05 PM
That is the entire error message (An item with the same key has already been added.) There is no inner exception reported. Do you mean the stack trace?

The AJAX controller handler would return a ViewResult object with the Data and Total fields filled in, but it never gets that far because the call to Count gives the error. This very same action method works fine when there is no filters on the grid or there is only one filter on a grid column. The error occurs when there are two filters specified on a grid column.

The stack trace seems to indicate that NHibernate cannot deal with the "where" generated by the Telerik ExpressionBuilder:

at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at NHibernate.Linq.Visitors.ExpressionParameterVisitor.VisitConstantExpression(ConstantExpression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\ExpressionParameterVisitor.cs:line 42
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitLambdaExpression(LambdaExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitUnaryExpression(UnaryExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](T expression, String methodName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.<>c__DisplayClass6`1.<VisitAndConvert>b__5(T expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](ReadOnlyCollection`1 expressions, String callerName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](T expression, String methodName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.<>c__DisplayClass6`1.<VisitAndConvert>b__5(T expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](ReadOnlyCollection`1 expressions, String callerName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](T expression, String methodName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.<>c__DisplayClass6`1.<VisitAndConvert>b__5(T expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](ReadOnlyCollection`1 expressions, String callerName) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
at Remotion.Data.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
at NHibernate.Linq.Visitors.ExpressionParameterVisitor.Visit(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\ExpressionParameterVisitor.cs:line 20
at NHibernate.Linq.NhLinqExpression..ctor(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\NhLinqExpression.cs:line 37
at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs:line 41
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs:line 26
at NHibernate.Linq.NhQueryProvider.Execute[TResult](Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs:line 103
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
at Services.LookupTableServiceBase`1.GetLookupGrid(GridCommand command, IUserInfo`1 userInfo, String userNameMember) in G:\Services\LookupTableServiceBase.cs:line 169
at Controllers.LookupTablesController.LookupIndex[T](GridCommand command, ILookupTableService`1 lookupService) in G:\Controllers\LookupTablesController.cs:line 80
at Controllers.LookupTablesController._NicknameIndex(GridCommand command) in G:\Controllers\LookupTablesController.cs:line 471
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
0
Dadv
Top achievements
Rank 1
answered on 09 Mar 2012, 02:23 PM
Could you provide a sample project please?
0
-glenn-
Top achievements
Rank 1
answered on 09 Mar 2012, 07:59 PM
Uh, not anytime soon. At least not a project that goes against a database and all that.

I've gone ahead and converted my code to use the technique from this library:

http://nuget.org/packages/TelerikMvcGridCustomBindingHelper.NHibernate

I ripped out some of the code and made some extensions. These use IQueryOver and populate the SQL where/sorting using a different technique than the way I was doing it before. I've attached the code for anyone who is interested.

public static class GridExtensions
{
    public static IQueryOver ApplyGridSorting(this IQueryOver query,
        IList<SortDescriptor> sortDescriptors)
    {
        foreach (var sort in sortDescriptors.Reverse())
        {
            var propertyName = sort.Member;
            int delim = propertyName.LastIndexOf('.');
            if (delim != -1)
                propertyName = propertyName.Substring(delim+1);
 
            query.RootCriteria.AddOrder(
                sort.SortDirection == ListSortDirection.Descending ?
                        Order.Desc(propertyName) :
                        Order.Asc(propertyName));
        }
 
        return query;
    }
 
    static IEnumerable<IFilterDescriptor> UnwrapFilterDescriptors(
        IEnumerable<IFilterDescriptor> filterDescriptors)
    {
        var result = new List<IFilterDescriptor>();
        foreach (var filterDescriptor in filterDescriptors)
        {
            if (filterDescriptor.GetType() == typeof(FilterDescriptor))
                result.Add(filterDescriptor);
 
            var compositeFilterDescriptor = filterDescriptor as
                CompositeFilterDescriptor;
            if (compositeFilterDescriptor != null)
                result.AddRange(UnwrapFilterDescriptors(
                    compositeFilterDescriptor.FilterDescriptors));
        }
        return result;
    }
 
    public static IQueryOver ApplyGridFilters(this IQueryOver query,
        IList<IFilterDescriptor> filterDescriptors)
    {
        if (!filterDescriptors.Any()) return query;
 
        var descriptors = UnwrapFilterDescriptors(
                filterDescriptors);
        foreach (var filter in descriptors
            .Cast<FilterDescriptor>()
            .Reverse())
        {
            var propertyName = filter.Member;
            int delim = propertyName.LastIndexOf('.');
            if (delim != -1)
                propertyName = propertyName.Substring(delim+1);
 
            query.ApplyGridFilter(filter, propertyName, filter.Operator);
        }
 
        return query;
    }
 
    public static IQueryOver ApplyGridFilter(this IQueryOver query,
        FilterDescriptor filter, string propertyName,
        FilterOperator filterOperator)
    {
        switch (filterOperator)
        {
        case FilterOperator.Contains:
            query.RootCriteria.Add(Restrictions.Like(
                propertyName, filter.Value.ToString(),
                MatchMode.Anywhere));
            break;
        case FilterOperator.EndsWith:
            query.RootCriteria.Add(Restrictions.Like(
                propertyName, filter.Value.ToString(),
                MatchMode.End));
            break;
        case FilterOperator.IsContainedIn:
            throw new NotSupportedException("Filter method " +
                            "“IsContainedIn” is not supported.");
        case FilterOperator.IsEqualTo:
            query.RootCriteria.Add(
                Restrictions.Eq(propertyName, filter.Value));
            break;
        case FilterOperator.IsGreaterThan:
            query.RootCriteria.Add(Restrictions.Gt(
                propertyName, filter.Value));
            break;
        case FilterOperator.IsGreaterThanOrEqualTo:
            query.RootCriteria.Add(Restrictions.Ge(
                propertyName, filter.Value));
            break;
        case FilterOperator.IsLessThan:
            query.RootCriteria.Add(Restrictions.Lt(
                propertyName, filter.Value));
            break;
        case FilterOperator.IsLessThanOrEqualTo:
            query.RootCriteria.Add(Restrictions.Le(
                propertyName, filter.Value));
            break;
        case FilterOperator.IsNotEqualTo:
            query.RootCriteria.Add(
                Restrictions.Not(Restrictions.Eq(propertyName,
                filter.Value)));
            break;
        case FilterOperator.StartsWith:
        default:
            query.RootCriteria.Add(Restrictions.Like(
                propertyName, filter.Value.ToString(),
                MatchMode.Start));
            break;
        }
 
        return query;
    }
}
0
-glenn-
Top achievements
Rank 1
answered on 10 Mar 2012, 04:15 PM
I have asked about this in the nhusers group too:

Error: An item with the same key has already been added
Tags
Grid
Asked by
-glenn-
Top achievements
Rank 1
Answers by
Dadv
Top achievements
Rank 1
-glenn-
Top achievements
Rank 1
Share this question
or