none
Entity Framework entity state is modified without any modification RRS feed

  • Question

  • I have the following issue on update of the entities. Given below is my WCF method. (Update is called by public Save method after determining if it is update or add). 

        protected bool UpdateSalesMaster(SalesMaster order)
        {
            using (var context = new MyContext())
            {
                SalesMaster original = context.SalesMasters.FirstOrDefault(o => o.OrderID == order.OrderID);
    
                if (original != null)
                {
                    context.Entry(original).CurrentValues.SetValues(order);
    
                    foreach (SalesDetail detail in order.SalesDetails)
                    {
                        if (detail.OrderDetailID == 0)
                            context.SalesDetails.Add(detail);
                        else
                        {
                            SalesDetails originalDetail = context.SalesDetails.FirstOrDefault(o => o.OrderDetailID == detail.OrderDetailID);
                            if (originalDetail != null)
                                context.Entry(originalDetail).CurrentValues.SetValues(detail);
                        }
                    }
    
                    context.SaveChanges();
                    return true;
                }
                else
                {
                    throw new FaultException(string.Format("Invalid Order specified: {0}", order.OrderID));
                }
            }
        }

    When I just update the OrderDate in SalesMaster and don't change any in the detail, an update query is fired to the database for detail. I expected to see Update query only for SalesMaster.

    Can someone let me know what am I doing wrong here? I don't want to fire update queries to the DB if nothing is changed.

    I use the approach of getting the original value from the database to determine if any values are updated using context.Entry(originalDetail).CurrentValues.SetValues(detail);

    I also override the SaveChanges to set the LastModified date by checking for IAuditable implementation of the entity. This is when I find that the state of the detail entity is identified as modified. But the only update that happens in the DB is LastModifiedBy which was updated in my save changes. I am not sure how it was set to state of Modified when nothing changed in detail.

    public override int SaveChanges()
        {
            var changeSet = ChangeTracker.Entries<IAuditable>();
    
            if (changeSet != null)
            {
                foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
                {
                    if (entry.State == EntityState.Added)
                        entry.Entity.DateCreated = DateTime.Now;
    
                    if (entry.State == EntityState.Modified)
                    {
                        entry.Property(a => a.CreatedByUser).IsModified = false;
                        entry.Property(a => a.DateCreated).IsModified = false;
                    }
                    entry.Entity.DateModified = DateTime.Now;
                }
            }
            try
            {
                return base.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                throw ex;
            }
    
        }

    My solution structure is:

    1. Client - Windows forms UI
    2. Entities - POCO as seperate library
    3. WCF - All business logic, add, update, delete of objects.
    4. Data - Entity Framework context with Fluent mapping.

    Also, I have disabled Lazyloading and ProxyGeneration.

    Thanks!


    • Edited by Isakavis Tuesday, April 30, 2013 6:10 PM
    Tuesday, April 30, 2013 5:04 PM

All replies

  • Hi Isakavis,

    I don't see how OrderDate in SalesMaster is changed in your code. Did you modify the property of a SalesMaster instance and then pass to UpdateSalesMaster method? Is that an identity key for the tables or not?

    By default, I think EF's change tracker should be able to track whether one record is modified or not. Would like to check which fields are updated from the sql command if you can use SQL Server Profiler.

    Best regards,


    Chester Hong
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, May 3, 2013 7:24 AM
    Moderator
  • Hello Chester,

    I have not posted the full code here. I do the following in the client and call update. Here is the flow.

    Client:

    SalesMaster master = _service.GetSalesMaster(122); // This returns me a SalesMaster with 2 Detail Items.

    master.OrderDate = DateTime.Now(); // This is the only change. Rest of the properties in master are untouched. OrderID is the identity key

    _service.SaveSalesMaster();

    Server:

    public SalesMaster SaveSalesMaster(SalesMaster order)
    {

         if(order.SalesMasterID == 0)
             AddSalesMaster(order);
         else
            UpdateSalesMaster(order);

          return order;

    }

    Expectation: I wanted the profiler to show only update to SalesMaster.

    Behavior: Instead I get update queries for SalesMaster and SalesDetail show up in the profiler.

    These are pure POCO classes and don't have any fixup logic or EF related code except the context uses DbContext with DbSet.

    I do override SaveChanges to update the CreatedDate and LastUpdated date. This where I find that even though SalesDetail was not changed it is marked as Modified (probably by this? context.Entry(originalDetail).CurrentValues.SetValues(detail);). I expected CurrentValues.SetValues() to find no changes between original and detail for the SalesDetail.

    SQL query shows

    Update SalesMaster set OrderDate = <Date>, LastUpdatedBy = <User>, LastUpdateDate = <Date> where orderId = @OrderID

    and it also shows update of SalesDetail

    Update SalesDetail set LastUpdatedBy = <User>, LastUpdateDate = <Date> where OrderDetailID = @OrderDetailID

    The second update happens for all the line items in detail. This should not have happened to start with. This was due to context.Entry(originalDetail).CurrentValues.SetValues(detail) identifying that changes were made.




    • Edited by Isakavis Tuesday, May 7, 2013 8:25 PM
    Monday, May 6, 2013 12:18 PM