GraphDiff
GraphDiff copied to clipboard
Merge on Unique Key (not Primary Key)
For synchronisation purpose sometimes we add a GUID column with an unique constraint but keep an autoinc int PKEY for regular work (avoiding fragmentation, unreadable keys,...). If we could specify the column(s) on which the equality should be done during merge that would be great.
Context.UpdateGraph(document, map => map.OwnedCollection(d => d.Lines, withKey : line => line.UniqueId));
Without it, GraphDiff removes and re-adds the lines instead of updating them.
Is the Int set as the sole primary key in fluent api or data annotations? Can you show an example of the mappings & model?
Here is my context
public class MyContext : DbContext
{
public DbSet<Owner> Owners { get; set; }
public DbSet<Line> Lines { get; set; }
}
public class Owner
{
public Owner()
{
Lines = new HashSet<Line>();
}
[Key]
public int Id { get; set; }
public virtual ICollection<Line> Lines { get; private set; }
}
public class Line
{
[Key]
public int Id { get; set; }
public int OwnerId { get; set; }
public string Caption { get; set; }
[Index(IsUnique=true)]
public Guid UniqueId { get; set; }
}
And my failing test method
[TestMethod]
public void TestMethod1()
{
Owner existingOwner = new Owner();
existingOwner.Lines.Add(new Line() { Caption = "EXISTING LINE", UniqueId = new Guid("D605A6BE-9CF7-4387-8B52-E40AA526AF26")});
using (var context = new MyContext())
{
context.Database.Delete();
context.Database.Create();
context.Owners.Add(existingOwner);
context.SaveChanges();
}
Owner externalOwner = new Owner() { Id = existingOwner.Id };
externalOwner.Lines.Add(new Line() { Caption = "UPDATED LINE", UniqueId = new Guid("D605A6BE-9CF7-4387-8B52-E40AA526AF26") });
Owner updatedOwner;
using (var context = new MyContext())
{
updatedOwner = context.UpdateGraph(externalOwner, map => map.OwnedCollection(o => o.Lines));
context.SaveChanges();
}
Assert.AreEqual(existingOwner.Lines.Single().Id, updatedOwner.Lines.Single().Id);
}
The line you are updating must have the primary key specified. It doesn't make sense not to. If the entity was detached from the database it would have a primary key and this is not being set in your test for the updating line.
I know but I have to synchronize my context with data from another application that cannot use the same pkey : if I add objects on both sides then synchronize, pkey will collide so we use another column for synchronization purposes (we don't have the PKEY in our DTO). I know that I can add a step to retrieve Ids from Guids but that's one more step and a lot of code. I think it could be part of GraphDiff.
That's my request : I would like to be able to merge using a specified column (and not the PKEY) to match row identity because I don't have the PKEY. That's a common pattern in synchronization and that would be great to have GraphDiff merge doing it natively.
Ah right I understand now, sounds like it could be useful and not very hard to implement. If you are willing to give it a go that would be great otherwise I may get a chance next week to do some more work
@refactorthis what do you think about my implementation of this feature ?
Was this ever implemented in the main branch? Any intentions to include, or even allow for a custom expression for equality? I.e. with a lambda expression in case of multiple keys. Thanks
Hey, I'm willing to implement this feature but I think I need a little hint or suggestion (@refactorthis ). I think the right place to implement this feature is within "GraphDiffer.FindEntityMatching" there we can use an custom IComparer<T>implementation to find the "correct" entity.
Thanks