I get
Unhandled Exception: System.ArgumentException: A parameter named 'EntityKeyValue1' already exists in the parameter collection. Parameter names must be unique in the parameter collection.
Parameter name: item
at System.Data.Entity.Core.Objects.ObjectParameterCollection.Add(ObjectParameter item)
at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__a()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__9()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
when combining two queries built from db.Entry(e).Collection(e => e.e2s).Query()
This happens both in EF5 and EF6.
Here's a complete repro:
class Author
{
public int ID { get; set; }
}
class Post
{
public int ID { get; set; }
public ICollection<Author> Authors { get; set; }
public ICollection<Comment> Comments { get; set; }
}
class Comment
{
public int ID { get; set; }
public Post Post { get; set; }
public ICollection<Author> Authors { get; set; }
}
class Context : DbContext
{
public DbSet<Post> Posts { get; set; }
static void Main()
{
using (Context db1 = new Context())
{
if (!db1.Posts.Any(p => p.ID == 1))
{
db1.Posts.Add(new Post { ID = 1, });
db1.SaveChanges();
}
}
using (Context db = new Context())
{
Post post = db.Posts.Find(1);
List<Author> authors = db.Entry(post).Collection(p => p.Authors).Query()
.Concat(db.Entry(post).Collection(p => p.Comments).Query().SelectMany(c => c.Authors))
.ToList();
}
}
}
Comments: I have a temporary workaround for this that seems to work. I had a look at the EF code and the issue is the AliasGenerator isn't aware of any existing usages when combining the queries. I am not sure the best place to either keep track of the EntityKeyValue's. As a workaround I grabbed the original ObjectQuery and did a string replace to avoid the conflicts. public static ObjectQuery<T> QueryDuplicateKeyFix<T>(ObjectQuery<T> brokenQuery, string suffix = "B") { var query = new ObjectQuery<T>(brokenQuery.CommandText.Replace("EntityKeyValue", "EntityKeyValueB"), brokenQuery.Context); foreach (var p in brokenQuery.Parameters) { var p1 = p; if (p.Name.StartsWith("EntityKeyValue" + suffix)) { p1 = new ObjectParameter(p.Name.Replace("EntityKeyValue", "EntityKeyValue" + suffix), p.Value); } query.Parameters.Add(p1); } return query; }
Unhandled Exception: System.ArgumentException: A parameter named 'EntityKeyValue1' already exists in the parameter collection. Parameter names must be unique in the parameter collection.
Parameter name: item
at System.Data.Entity.Core.Objects.ObjectParameterCollection.Add(ObjectParameter item)
at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__a()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__9()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
when combining two queries built from db.Entry(e).Collection(e => e.e2s).Query()
This happens both in EF5 and EF6.
Here's a complete repro:
class Author
{
public int ID { get; set; }
}
class Post
{
public int ID { get; set; }
public ICollection<Author> Authors { get; set; }
public ICollection<Comment> Comments { get; set; }
}
class Comment
{
public int ID { get; set; }
public Post Post { get; set; }
public ICollection<Author> Authors { get; set; }
}
class Context : DbContext
{
public DbSet<Post> Posts { get; set; }
static void Main()
{
using (Context db1 = new Context())
{
if (!db1.Posts.Any(p => p.ID == 1))
{
db1.Posts.Add(new Post { ID = 1, });
db1.SaveChanges();
}
}
using (Context db = new Context())
{
Post post = db.Posts.Find(1);
List<Author> authors = db.Entry(post).Collection(p => p.Authors).Query()
.Concat(db.Entry(post).Collection(p => p.Comments).Query().SelectMany(c => c.Authors))
.ToList();
}
}
}
Comments: I have a temporary workaround for this that seems to work. I had a look at the EF code and the issue is the AliasGenerator isn't aware of any existing usages when combining the queries. I am not sure the best place to either keep track of the EntityKeyValue's. As a workaround I grabbed the original ObjectQuery and did a string replace to avoid the conflicts. public static ObjectQuery<T> QueryDuplicateKeyFix<T>(ObjectQuery<T> brokenQuery, string suffix = "B") { var query = new ObjectQuery<T>(brokenQuery.CommandText.Replace("EntityKeyValue", "EntityKeyValueB"), brokenQuery.Context); foreach (var p in brokenQuery.Parameters) { var p1 = p; if (p.Name.StartsWith("EntityKeyValue" + suffix)) { p1 = new ObjectParameter(p.Name.Replace("EntityKeyValue", "EntityKeyValue" + suffix), p.Value); } query.Parameters.Add(p1); } return query; }