GraphDiff icon indicating copy to clipboard operation
GraphDiff copied to clipboard

Delete an owned entity on update?

Open cryo75 opened this issue 9 years ago • 5 comments

I have the following model:

public class Address
{
    public int Id {get; set;}
    public string Street {get; set;}
    public int PostCodeId {get; set;}
    public PostCode PostCode {get; set;}
    //etc...
}

public class Customer
{
    public int Id {get; set;}
    public string Name {get; set;}
    public int AddressId {get; set;}
    public virtual void Address Address {get; set;}
}

I load an existing customer with his address, and I want to delete address, so I do:

customer.Address = null;

customer = dbContext.UpdateGraph<Customer>
                (entity, map => map.OwnedEntity(x => x.Address, with => with.AssociatedEntity(x => x.PostCode)));   

The customer's address id is set to null correctly. However the address is not being deleted from the db. How can I delete the owned entity from the db?

cryo75 avatar Feb 26 '15 13:02 cryo75

This is most likely an EF-configuration issue. The default relation in EF for a one-way nav property is one-to-many. (It doesn't know Address is unique to this customer)

Try setting your config to: HasRequired(c=> c.Address).WithRequired() or HasOptional(c=> c.Address).WithRequired() depending on whether or not Address is optional for a Customer.

josh-dastmalchi avatar Mar 03 '15 17:03 josh-dastmalchi

I used HasOptional(c => c.Address).WithRequired().

However, it doesn't work because the address is now not being set in the customer although the correct SQL statement is being used.

cryo75 avatar Mar 06 '15 10:03 cryo75

This issue is still not solved. Could it be because I'm not using EF's default naming conventions?

cryo75 avatar Mar 19 '15 06:03 cryo75

I am having the same issue.

sundeepyama avatar Jun 17 '15 20:06 sundeepyama

I had similar issues, fixed both in OwnedEntityGraphNode's Update method below..

  1. setting new value null was not deleting the record - fixed it by adding "changeTracker.RemoveItem(dbValue);" when newValue is null - first IF

  2. replace value of child by setting a new instance was not deleting the old record - fix it by adding "changeTracker.RemoveItem(dbValue);" when new value has id = 0 and old value has id > 0

public override void Update<T>(DbContext context, T persisted, T updating)
        {
            var dbValue = GetValue<object>(persisted);
            var newValue = GetValue<object>(updating);

            if (dbValue == null && newValue == null)
                return;

            // Merging options
            // 1. No new value, set value to null. entity will be removed if cascade rules set.
            // 2. If new value is same as old value lets update the members
            // 3. Otherwise new value is set and we don't care about old dbValue, so create a new one.
            if (newValue == null)
            {
                SetValue(persisted, null);
                RemoveElement(context, dbValue);
                return;
            }

            if (dbValue != null && IsKeyIdentical(context, newValue, dbValue))
                UpdateValuesWithConcurrencyCheck(context, newValue, dbValue);
            else
            {
                var newEntity = CreateEntityKey(context, newValue);
                var dbEntity = dbValue != null ? CreateEntityKey(context, dbValue) : null;
                if (dbEntity != null &&
                    ((int)newEntity.EntityKeyValues[0].Value <= 0
                        && (int)dbEntity.EntityKeyValues[0].Value > 0))
                {
                    RemoveElement(context, dbValue);
                }

                dbValue = CreateNewPersistedEntity(context, persisted, newValue);
            }

            AttachCyclicNavigationProperty(context, persisted, newValue);

            // if (dbValue != null) // make an error throw or not?
            foreach (var childMember in Members)
                childMember.Update(context, dbValue, newValue);
        }

        private void RemoveElement(DbContext context, object dbItem)
        {
            context.Set(ObjectContext.GetObjectType(dbItem.GetType())).Remove(dbItem);
        }

Old version of code

public override void Update<T>(IChangeTracker changeTracker, IEntityManager entityManager, T persisted, T updating)
        {
            var dbValue = GetValue<object>(persisted);
            var newValue = GetValue<object>(updating);

            if (dbValue == null && newValue == null)
            {
                return;
            }

            // Merging options
            // 1. No new value, set value to null. entity will be removed if cascade rules set.
            // 2. If new value is same as old value lets update the members
            // 3. Otherwise new value is set and we don't care about old dbValue, so create a new one.
            if (newValue == null)
            {
                SetValue(persisted, null);
                // fix - 1) setting new value null was not deleting the record
                changeTracker.RemoveItem(dbValue);
                return;
            }


            if (dbValue != null && entityManager.AreKeysIdentical(newValue, dbValue))
            {
                changeTracker.UpdateItem(newValue, dbValue, true);
            }
            else
            {
                // fix - 2) replace value of child by setting a new instance was not deleting the old record
                var newEntity = entityManager.CreateEntityKey(newValue);
                var dbEntity = dbValue != null ? entityManager.CreateEntityKey(dbValue) : null;
                if (dbEntity != null &&
                    ((int)newEntity.EntityKeyValues[0].Value == 0
                        && (int)dbEntity.EntityKeyValues[0].Value > 0))
                {
                    changeTracker.RemoveItem(dbValue);
                }
               

                dbValue = CreateNewPersistedEntity(changeTracker, persisted, newValue);
            }

            changeTracker.AttachCyclicNavigationProperty(persisted, newValue, GetMappedNaviationProperties());

            foreach (var childMember in Members)
            {
                childMember.Update(changeTracker, entityManager, dbValue, newValue);
            }
        }

MilanRaval avatar May 03 '22 13:05 MilanRaval