简体   繁体   中英

Undo / Redo with change tracking in Entity Framework

I'm trying to implement an Undo / Redo feature based on entity framework with POCO entities. Therefor after each change that I want to track I call the ChangeTracker for any modification to entities an I call the ObjectStateManger for changes to relationships (ie navigation properties). I store all the changes with the current and previous values to be able to go back and forth in the history.

My problem now is that for entities with a navigation property and a corresponding foreign key these two values are not properly synced if the referenced entity was newly added to the DbContext.

To clarify: Say I have these classes:

public class EntityFilter
{
    [Key]
    public Guid ID { get; set; }

    public virtual ICollection<EntityConnection> IsSource { get; set; }

    public virtual ICollection<EntityConnection> IsSink { get; set; }

    //other stuff
}

public class EntityConnection
{
    [Key]
    public Guid SinkFilterID { get; set; }

    [ForeignKey("SinkFilterID")]
    public virtual EntityFilter Sink { get; set; }

    public Guid SourceFilterID { get; set; }

    [ForeignKey("SourceFilterID")]
    public virtual EntityFilter Source { get; set; }

    //more stuff
}

EntityConnection is basically a many-to-many relationship between filters, but it actually contains more fields which is why I cannot get rid of it. Also I want to be as general as possible and not depend on our actual data model.

The problem arises if I add a new filter and then connect it to an existing filter (could also be a new one). Undoing the connection is still ok, but when I try to redo my program will crash. I can see in the restored connection that the foreign key SinkFilterID has the correct value but Sink is null (the same might happen for source, depending on the direction of the connection). Manually calling DetectChanges makes no difference. Adding a connection between two existing filters (ie they are already stored in the db before) is no problem.

The detected changes for a new connection of this type only contain entity changes from the ChangeTracker and no relationship changes from the ObjectStateManger . I guess this is because the relationship is already handled by the foreign key, which is included in the properties from PreviousValues .

I've read that entities in the EntityState.Added state get temporary keys and that change tracking for them is not fully supported. Can I get this to work somehow?

I've tried to check with the MetadataWorkspace if my updated entities have a foreign key and a corresponding navigation property and in that case update it manually via reflection, but I'm not sure what data I actually have to check.

Is there a way to keep foreign keys and navigation properties to added entities in sync? Or do you have any suggestions what I might try?

Thank you very much.

Here is what I ended up with:

I keep a separate list of all the added entities. Then when I have to restore a navigation property that is backed by a foreign key I search that list and manually set the navigation property. The hardest part was to figure out how to check in the data model if this fixup was at all needed and to find the name of the corresponding property.

The overall system still has some flaws for maximum generality but it works quite well for what we need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM