Updating a disconnected object with child objects in linq to sql

In an n-tier application, linq-to-sql does not seem to have a clear solution for updating a disconnected object with child EntitySets.

I have some linq-to-sql objects ...

public partial class Location : INotifyPropertyChanging, INotifyPropertyChanged
{       
    public int id;      
    public System.Nullable<int> idLocation;     
    public string brandingName;     
    public System.Data.Linq.Binary timeStamp;       
    public EntitySet<LocationZipCode> LocationZipCodes;
}

public partial class LocationZipCode : INotifyPropertyChanging, INotifyPropertyChanged
{
    public string zipcode;      
    public string state;        
    public int idLocationDetail;        
    public int id;      
    public System.Data.Linq.Binary timeStamp;       
    public EntityRef<Location> Location;
}

So the object Locationhas EntitySetof LocationZipCodes.

The domain model Locationmaps to the view model that the view layer consumes, and then ultimately sends back the modified view model object, where it maps to the domain model Location. From there I update the object and save the changes. Here's the handler:

public class ProgramZipCodeManagerHandler : IHttpHandler {
    private LocationsZipCodeUnitOfWork _locationsZipCodeUnitOfWork = new LocationsZipCodeUnitOfWork();

    public void ProcessRequest(HttpContext context) {
        if (context.Request.HttpMethod == "POST") {
            string json = Json.getFromInputStream(context.Request.InputStream);

            if (!string.IsNullOrEmpty(json)) {
                Location newLocation = Json.deserialize<Location>(json);
                if (newLocation != null) {
                    //this maps the location view model from the client to the location domain model
                    var newDomainLocation = new Mapper<Location, DomainLocation>(new DomainLocationMapTemplate()).map(newLocation);

                    if (newDomainLocation.id == 0)
                        _locationsZipCodeUnitOfWork.locationRepository.insert(newDomainLocation);
                    else
                        _locationsZipCodeUnitOfWork.locationRepository.update(newDomainLocation);

                    _locationsZipCodeUnitOfWork.saveChanges(ConflictMode.ContinueOnConflict);

                    var viewModel = new Mapper<DomainLocation, Location>(new LocationMapTemplate()).map(newDomainLocation);
                    context.Response.ContentType = "application/json";
                    context.Response.Write(Json.serialize(viewModel);
                }
            }
        }       
    }
}

Here is the update method in mine locationRepository:

protected System.Data.Linq.Table<T> _table;

public void update(T entity) {
    _table.Attach(entity, true);
    _context.Refresh(RefreshMode.KeepCurrentValues, entity);
}

public void update(T newEntity, T oldEntity) {
    _table.Attach(newEntity, oldEntity);
    _context.Refresh(RefreshMode.KeepCurrentValues, newEntity);
}

, , Location, , (public EntitySet<LocationZipCode> LocationZipCodes) .

, EntitySet, ? , , . , .

+5
2

.. .

, , ().

:

, A B, 1000 . A - A B.. A - , AB null .

, , , :
  .

+2

, , ... - , , .., , entitystate.

    /// <summary>
    /// AttachEntityToObjectContext attaches an EntityObject to an ObjectContext
    /// </summary>
    /// <param name="entityWithRelationships">An EntityObject that has relationships</param>
    /// <param name="newContext">The ObjectContext to attach the entity to</param>
    /// <returns>True if the entity has relationships (and therefore the method could succeed). Otherwise false.</returns>
    /// <remarks>Objects are retrieved using one ObjectContext, stored in ViewState and then
    /// an attempt to save them is then made. The save attempt does not save the object. This is because it is a different context which is saving the object.
    /// So the object needs to be detached from its old context, added to the new context and have its EntityState maintained so that it gets saved.</remarks>
    public static bool AttachEntityToObjectContext(this IEntityWithRelationships entityWithRelationships, ObjectContext newContext)
    {
        EntityObject entity = entityWithRelationships as EntityObject;
        if (entity == null)
        {
            return false;
        }

        if (entity.EntityState != EntityState.Detached)
        {
            ObjectContext oldContext = entity.GetContext();
            if (oldContext == null)
            {
                return false;
            }

            if (oldContext != newContext)
            {
                EntityState oldEntityState = entity.EntityState;
                oldContext.Detach(entity);
                newContext.Attach(entity);
                newContext.ObjectStateManager.ChangeObjectState(entity, oldEntityState);
            }
        }

        return true;
    }

    /// <summary>
    /// GetContext gets the ObjectContext currently associated with an entity
    /// </summary>
    /// <param name="entity">An EntityObject</param>
    /// <returns>The ObjectContext which the entity is currently attached to</returns>
    private static ObjectContext GetContext(this IEntityWithRelationships entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }

        var relationshipManager = entity.RelationshipManager;

        var relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();

        if (relatedEnd == null)
        {
            // No relationships found
            return null;
        }

        var query = relatedEnd.CreateSourceQuery() as ObjectQuery;

        if (query == null)
        {
            // The Entity is Detached
            return null;
        }

        return query.Context;
    }
0

All Articles