29

I have not run into this before, because I usually handled collections by them selves instead of modifying them directly on the entity.

public class Schedule: BaseEntity
        {
            public Guid Id {get;set;}
            public virtual int? DayOfTheWeekTypeId { get; set; }
            public virtual DayOfTheWeekType DayOfTheWeekType { get; set; }
            public virtual ICollection<Instructor> Instructors { get; set; }
            public DateTime? StartDateTime { get; set; }
            public DateTime? EndDateTime { get; set; }
            public string SpecialInstructions { get; set; }
        }

Mapping class:

    public ScheduleMapping()
            {
                HasMany(c => c.Instructors).WithMany().Map(m => { m.MapLeftKey("ScheduleId");
m.MapRightKey("InstructorId"); 
m.ToTable("Schedule_Instructors");
                });
                HasOptional(s => s.DayOfTheWeekType).WithMany().HasForeignKey(s => s.DayOfTheWeekTypeId).WillCascadeOnDelete(false);
                Property(s => s.SpecialInstructions).IsMaxLength();
            }

This is my update method:

public virtual void Update(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            //this is the original persisted entity
            var persistedEntity = _repository.GetById(entity.Id);
            if(originalEntity != null)
            {
                entity.Id = persistedEntity.Id;                
                UnitOfWork.ApplyCurrentValues<TEntity>(originalEntity,entity);
                UnitOfWork.Commit();
            }
        }

This is the Method that handled the "merge"

public void ApplyCurrentValues<TEntity>(TEntity original, TEntity current) where TEntity : class
        {
            base.Entry<TEntity>(original).CurrentValues.SetValues(current);
        }

If I modify the Instructors collection then try to apply the update, it seems to keep my original values. I have tried loading the the Schedule entity prior to the update and make my changes, but sometimes that causes a PK error (on the Instructors collection) in entity framework. As if it is trying to add an entity with the same key. So, instead I am rebuilding the Schedule entity (including the ID) manually and then updating it. When I do that I do not get any more errors, however, the Instructors collections doesn't change. I am thinking because CurrentValues. SetValues is being applied based on the persisted entity and not my updated version. the Should I handle my updates differently or do I need to manully

DDiVita
  • 4,225
  • 5
  • 63
  • 117

1 Answers1

40

SetValues never updates navigation properties. When you execute your code it only knows about changes in simple / complex properties of the entity passed to your Update method. EF even don't know about related entities of the entity passed to your Update method.

You must manually tell EF about each change in your object graph - EF doesn't have any resolution mechanism for object graphs.

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • You are so correct and realized I had forgotten about this. Looking at some old examples I had POCed when first learning EF I had figured this out long ago. I have reverted to updating individual collections manually. It makes sense right now until EF handles it automatically. Thanks Ladislav – DDiVita Jul 29 '12 at 23:41
  • 4
    It does however happily update a matching `ID` for a navigation property, and this answer sent me off down the wrong track. Turns out my actual problem was to do with the id being set in the detached entity already, meaning that `SetValues` thought it was unchanged so didn't flip the `IsModified` bit, which in turn meant the value wasn't persisted on `SaveChanges()`. – Tim Abell Jun 03 '16 at 11:02
  • @TimAbell I had the same situation – Mohammed Noureldin Jun 16 '18 at 02:42