8

recently I discover that EF doesn't update nested object. For few days I try to figure out how to do this but unfortunately I'm stuck with this problem.

I have Object

public class ProjectEntity : AuditableEntity<int>
{

    public string CustumerCompany { get; set; }
    public string CustomerRepresentative { get; set; }

    public string ProjectTitle { get; set; }
    public string WwsNumber { get; set; }

    [ForeignKey("ParentProjectId")]
    public virtual ProjectEntity ParentProject { get; set; }

    public int? ParentProjectId { get; set; }

    public virtual ICollection<ProjectServicesEntity> Service { get; set; }
}

Then Service object

public class ProjectServicesEntity : AuditableEntity<int>
{
    /// <summary>
    /// Service Number
    /// </summary>
    public int Number { get; set; }
    /// <summary>
    /// Service Name
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Positions
    /// </summary>
    public virtual ICollection<ProjectPositionsEntity> Positions { get; set; }

    [ForeignKey("ProjectId")]
    public virtual ProjectEntity Project { get; set; }

    public int ProjectId { get; set; }
}

and Positions object:

public class ProjectPositionsEntity : AuditableEntity<int>
{
    /// <summary>
    /// Position number
    /// </summary>
    public int Number { get; set; }

    /// <summary>
    /// Position Name
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Organization Unit for position
    /// </summary>
    public virtual ICollection<ProjectsOutsourcedPositionEntity> OrganizationUnit { get; set; }
    /// <summary>
    /// Represents if position is outsourced
    /// </summary>
    public bool OutSource { get; set; }
    /// <summary>
    /// Comments for position
    /// </summary>
    public string Remarks { get; set; }

    [ForeignKey("ServiceId")]
    public virtual ProjectServicesEntity Service { get; set; }

    public int ServiceId { get; set; }

}}

And my update method:

public void Update(T entity)
    {

            DbContext.Entry(entity).State = EntityState.Modified;
            DbContext.SaveChanges();
}

When have page were all data is represented and when I try to edit some data in Service's or in Position's it doesn't update. Anybody had this kind of problem ?

Every example that I saw it was only with nested object that has 1 level deep but as you can see my object has 2 level nest.

Daniil T.
  • 1,145
  • 2
  • 13
  • 33
  • Are you quite sure the changes are reaching the server from your page? If you try this in a test harness (a console app) does it behave the same? For example, write a small console app that loads in some data and changes the objects, then saves it. Does the save work? – Adam Benson Jan 19 '17 at 11:28
  • I guess you are speaking about disconnected objects. It never has been addressed by EF, you can take a look at [GraphDiff](https://www.nuget.org/packages/RefactorThis.GraphDiff) package. – Ivan Stoev Jan 19 '17 at 11:33
  • @AdamBenson yes, i'm sure. Problem was that EF only updates EF object that are marked Modified and this state doesn't apply on child objects. So I need to set modified for them to. I posted my solution – Daniil T. Jan 19 '17 at 12:01

1 Answers1

6

So I figure out how I can make this work. In specific repository class I made few foreach loops that set EntityState to modified. By our business rules Project required to have Service and Position and OrganizationUnit for Position is optional so I check if it's not null. Here is my solution:

DbContext.Entry(entity).State = EntityState.Modified;
            foreach (var service in entity.Service)
            {
                DbContext.Entry(service).State = EntityState.Modified;
                foreach (var position in service.Positions)
                {
                    DbContext.Entry(position).State = EntityState.Modified;
                    if (position.OrganizationUnit == null) continue;
                    foreach (var organizationUnit in position.OrganizationUnit)
                    {
                        DbContext.Entry(organizationUnit).State = EntityState.Modified;
                    }
                }
            }
            DbContext.SaveChanges();

Now when I want to update my object on any level it will update in my DB.

Daniil T.
  • 1,145
  • 2
  • 13
  • 33
  • How do you track deleted items on levels 2 and 3? – Jacques Aug 14 '18 at 15:51
  • Basically the same way as I modify them – Daniil T. Aug 17 '18 at 09:54
  • I'm back at this problem. I pass an Order with OrderItems down to an Angular project where the user can delete individual OrderItems then hit Save. What I'm doing is sending the Order, back up to the server, which has the OrderItems removed. EFC isn't doing anything so I'm guessing those removed OrderItems should be kept there and somehow marked as deleted? – Jacques Aug 23 '18 at 11:25
  • @Jacques It's hard to say something without seeing your code. Could you share your code so I could take a look. – Daniil T. Aug 23 '18 at 18:55