jamie
jamie

Reputation: 1234

Azure Mobile Services Soft Delete Issue / Practices

With soft delete turned on, I add a single record on the client, push, delete the added record push and then attempt to add a new record (and then push) with the same primary key as the initial record I get an exception. It would appear that EntityDomainManager just attempts to do a new insert without checking to see if the record is to be 'updated' instead of inserted.

However if I turn off soft delete in the domain manager constructor everything works fine.

We are using incremental sync, so soft delete as I understand it is required to make this work, so we don't end up with different pictures of what's right between mobile and server.

When is/are the recommended approach? A Custom EntityDomainManager (or other DomainManager)? If so it would be useful for more clarity on the interactions between the table controller and the domain manager.

I have constructed this custom domain manager which seems to work, but would appreciate any guidance/suggestions.

public class CustomEntityDomainManager<TData> : EntityDomainManager<TData> where TData : class, ITableData
{

    public CustomEntityDomainManager(DbContext context, HttpRequestMessage request, ApiServices services)
        : base(context, request, services)
    {
    }

    public CustomEntityDomainManager(DbContext context, HttpRequestMessage request, ApiServices services, bool enableSoftDelete) : base(context, request, services, enableSoftDelete)
    {
    }

    public async override Task<TData> InsertAsync(TData data)
    {
        if (data == null)
        {
            throw new ArgumentNullException("data");
        }

        // now then, if we have soft delete enabled & data has been provided with an id in it 
        if (EnableSoftDelete && data.Id != null)
        {
            // now look to see if the record exists and if it is deleted
    // if so we look to remove the record before then attempting the insert

            // record old value of deleted, since need to query to see if deleted.
            var oldIncludeDeleted = IncludeDeleted;

            try
            {
                IncludeDeleted = true;
                var existingData = await this.Lookup(data.Id).Queryable.FirstOrDefaultAsync();

                // if record exists, and its soft deleted then truly delete it
                if (existingData != null && existingData.Deleted)
                {
                    // now need to remove this record...
                    this.Context.Set<TData>().Remove(existingData);
                }
            }
            finally
            {
                IncludeDeleted = oldIncludeDeleted;        
            }
        }

        if (data.Id == null)
        {
            data.Id = Guid.NewGuid().ToString("N");
        }

        return await base.InsertAsync(data);
    }

Upvotes: 2

Views: 723

Answers (1)

lindydonna
lindydonna

Reputation: 3875

This behavior is by design--we require that you do an explicit undelete before doing the update.

The solution you've presented is fine. You can also move the code to your table controller, assuming you only need this behavior in one table. If you need it in multiple tables, then the custom domain manager is the best approach.

Upvotes: 1

Related Questions