2

I am using Entity Framework to deal with database, and I have self-referencing model as following:

public class PhysicalObject
{
    public PhysicalObject()
    {
        SubPhysicalObjects = new HashSet<PhysicalObject>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? ParentId { get; set; }

    [StringLength(150)]
    public string Title { get; set; }

    public virtual PhysicalObject Parent { get; set; }

    public virtual ICollection<PhysicalObject> SubPhysicalObjects { get; set; }

}

I was using GraphDiff library to update disconnected graphs but it seems it does not support updating self-referencing graphs.

My question is: what is the best way to update self-referencing graphs using Entity Framework by:

  • Deleting/Updating existing physicalObjects

  • Inserting not existing physicalObjects

Simple Code
  • 2,354
  • 2
  • 27
  • 56

1 Answers1

0

Let's say I have two entities as followings:

public class PhysicalObject
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? ParentId { get; set; }

    public int StorageRequestId { get; set; }

    public string Title { get; set; }

    public virtual PhysicalObject Parent { get; set; }

    public virtual ICollection<PhysicalObject> SubPhysicalObjects { get; set; }

    public virtual StorageRequest StorageRequest { get; set; }

}

public class StorageRequest
{
    public StorageRequest()
    {
        PhysicalObjects = new HashSet<PhysicalObject>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Title { get; set; }

    public virtual ICollection<PhysicalObject> PhysicalObjects { get; set; }
}

Notice that PhysicalObject is self-referencing table .

Not let's update graphs using entity framework:

 var oldPhysicalObjects = dbContext.PhysicalObjects.Where(x => x.StorageRequestId== storageRequestId).ToList();

 var existingIds = new HashSet<int>();
 foreach (var item in newGraphDto.PhysicalObjects.ToList())
   {
     updateGraph(item, oldPhysicalObjects, dbContext, storageRequestId,existingIds);
   }
 var posToDelete = oldPhysicalObjects.Where(x => existingIds.All(e => e != x.Id)).ToList();
 dbContext.PhysicalObjects.RemoveRange(posToDelete);
 dbContext.SaveChanges();

updateGraph method will update every tree of PhysicalObjects recursively and it looks like:

private void updateGraph(PhysicalObjectDto physicalObjectDto, IList<PhysicalObject> oldPhysicalObjects, MyDbContext dbContext, int storageRequestId, HashSet<int> existingIds, PhysicalObject parent = null)
    {
        if (physicalObjectAddEditDto.Id == 0)
        {
            PhysicalObject po = new PhysicalObject
            {
                Id = physicalObjectAddEditDto.Id,
                Title = physicalObjectAddEditDto.Title,
                StorageRequestId = storageRequestId,
                Parent=parent

            };

            dbContext.PhysicalObjects.Add(po);

            parent = po;
        }
        else
        {
            var po = oldPhysicalObjects.FirstOrDefault(x => x.Id == physicalObjectAddEditDto.Id);
            po.Title = physicalObjectAddEditDto.Title;
            po.StorageRequestId = storageRequestId;
            po.Parent = parent;
            dbContext.Entry(po).CurrentValues.SetValues(po);

            parent = po;
        }


        existingIds.Add(parent.Id);
        foreach (var subPhysicalObject in physicalObjectAddEditDto.SubPhysicalObjects)
        {
            updateGraph(subPhysicalObject, oldPhysicalObjects, dbContext, mailRoomRequestId, existingIds, parent);
        }

    }

I hope my code will help others to know how to update graph trees of self-referencing table

Simple Code
  • 2,354
  • 2
  • 27
  • 56