Reputation: 711
Using EF and C#, I'm trying to make a clone of an entity which has a lot of related records. I want to clone the related records as well. The top level object is a Bid
.
class Bid
{
Collection<ItemGroup> ItemGroups {get;set;}
Collection<Evaluator> Evaluators {get;set;}
}
Children being ItemGroups
and Evaluators
. They are many-to-many.
class ItemGroup
{
Collection<Evaluator> Evaluators {get;set;}
}
Class Evaluator
{
Collection<ItemGroup> ItemGroups {get;set;}
}
I clone the Bid
, and all of it's children, by querying the database
Bid bid = dbContext.Bids.AsNoTracking().FirstOrDefault()
.Include(b => b.ItemGroups)
.Include(b => b.ItemGroups.Select(e => e.Evaluators))
and adding the Bid
back in with
database.Bids.Add(bid);
database.SaveChanges();
The problem is the many-to-many relationship between Evaluators
and ItemGroups
. Because their collections reference eachother, when you add the Bid
back in, it DUPLICATES the records.
So, before clone, I have a Bid:
Original Bid -
Number of ItemGroups = 3
Number of Evaluators = 2
and, after clone, I have a new Bid, with:
New Bid -
Number of ItemGroups = 3
Number of Evaluators = 6
Which is obviously incorrect. How do I clone this relationship without having EF add duplicates?
Is the problem my original query? I've tried all sorts of options, using .Include()s
that trace from Bid -> Evaluators -> Item Groups
, or simply just go Bid -> Evaluator
and Bid -> ItemGroup
, but nothing seems to get me quite what I want. Any and all help is greatly appreciated, and please just let me know if I can offer some clarifications. Thanks in advance.
Upvotes: 1
Views: 498
Reputation: 711
Well, here's my super janky solution until someone can tell me a better way to do it. Basically, I leave out the many-to-many relationships in my query Include()s
, querying for bid.ItemGroups
, and bid.Evaluators
only.
I add those as normal, which gives me a Bid
with the appropriate number of item groups, and 0 evaluators, as the ItemGroup -> Evaluator relationships weren't established because i did not query for them.
Then, after calling database.Bids.Add(bid)
, I re-query for the original bid and it's Evaluator/ItemGroup relationships, and manually hook up all of the Evaluator/ItemGroup references using names/id's/whatever identifiers are available.
List<Evaluator> originalEvals = db.Bids.Where(b => b.Id == entityId)
.Select(b => b.Evaluators)
.FirstOrDefault()
.ToList();
foreach(Evaluator origEval in originalEvals)
{
db.Entry(origEval).Reference(e => e.ClientUser).Load();
db.Entry(origEval).Collection(e => e.ItemGroups).Load();
}
foreach (Evaluator newEval in bid.Evaluators)
{
Evaluator originalEval = originalEvals.Where(e => e.ClientUserId == newEval.ClientUserId).FirstOrDefault();
foreach (ItemGroup ig in originalEval.ItemGroups)
{
newEval.ItemGroups.Add(bid.ItemGroups.Where(g => g.Name == ig.Name).FirstOrDefault());
}
}
Shitty, but it works.
Upvotes: 1