tags:

views:

323

answers:

1

When I call a property "InnerText" on XmlNode in LINQ query I am getting a strange error: "An item with the same key has already been added.".

Query looks like:

var partnersXml = from partnerTable in dataContext.SomeTableInDb
                  where partnerTable.XmlType == "partner"
                  select new
                  {
                     partnerId = XmlDocumentWrapper(partnerTable.XmlDocument).SelectSingleNode("//*[name()='partnerId']").InnerText                 
                  };

Explanation:

  • partnerTable.XmlDocument is string xml in DB
  • XmlDocumentWrapper method returns a XmlDocument for a given xml string

Query works perfectly without "InnerText" (then partnerId contains XmlNode). Is this some kind of bug in LINQ or what? What is a workaround of this problem?

Stack trace:

System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary2.Insert(TKey key, TValue value, Boolean add) at System.Data.Linq.Mapping.UnmappedType.GetDataMember(MemberInfo mi) at System.Data.Linq.SqlClient.SqlFactory.Member(SqlExpression expr, MemberInfo member) at System.Data.Linq.SqlClient.QueryConverter.VisitMemberAccess(MemberExpression ma) at System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) at System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node) at System.Data.Linq.SqlClient.QueryConverter.VisitExpression(Expression exp) at System.Data.Linq.SqlClient.QueryConverter.VisitNew(NewExpression qn) at System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) at System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node) at System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector) at System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc) at System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc) at System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) at System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node) at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations) at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) at System.Data.Linq.DataQuery1.System.Collections.Generic.IEnumerable.GetEnumerator()

+2  A: 

It looks like LINQ to SQL is trying to do some mapping whereas you want it to be done at the .NET side. (I assume - if you want the database to do the XPath, I have no idea I'm afraid.) Try this:

var partnersXml = dataContext.SomeTableInDb
     .Where(x => x.XmlType == "partner")
     .AsEnumerable() // This forces the rest of the query to be done in the CLR
     .Select(x => new {
          partnerId = XmlDocumentWrapper(x.XmlDocument)
                           .SelectSingleNode("//*[name()='partnerId']")
                           .InnerText
     });
Jon Skeet
Jon, great solution. I'll buy you a beer on StackOverflow Dev Days in London. :)The key is ".AsEnumerable()" and is not necesseary to query this with lambda expressions. It can be done like - from partnerTable in dataContext.SomeTableInDb.AsEnumerable() -, too.
Peter Stegnar
Don't you want the "where" clause to be executed in SQL though? You need to work out how much of the query you want to happen in SQL, and how much you want to happen in the CLR.
Jon Skeet
Yes I want, but I just put an example how to solve this problem if you want to have non lambda query.But as is running where clause in the SQL almost always better idea (performance) is your lambda solution perfect.
Peter Stegnar
You could still do it without any lambdas and run the where clause in SQL, but it would involve two query expressions and be ugly as anything ;)
Jon Skeet
Thank you Jon! I just had a similar issue with the same exception and this fixed it.
jrummell