views:

492

answers:

1

Is it possible to query the context, make a change to an entity, and then re-query the context and get a result set back that includes the changed entity without doing a savechanges? (I don't want to savechanges because I may want to rollback)

I know I can get the changes back by using GetObjectStateEntries, but I'm interested in the entire dataset.. not just the changed entities.

I think the only way to do this is with a savechanges, but wrap a transactionscope around everything so that I can do a rollback if my condition is not met. Or am I missing something easier?

+2  A: 

Why not merge the set of existing entities with those to be added? I tested this out and it seems to work- it doesn't account for Deletes though, but you should be able to get the idea:

// get the entities that have been inserted or modified
var projects = myObjectContext.ObjectStateManager.GetObjectStateEntries(
     EntityState.Added | EntityState.Modified).Where(
          x => x.Entity is Project).Select( x=> (Project) x.Entity);

// get existing entities, exclude those that are being modified
var projects2 = myObjectContext.Projects.Where(
     BuildDoesntContainExpression<Project, int>(z => z.ProjectId, 
          projects.Select(x => x.ProjectId)));

// Union the 2 sets
var projects3 = projects.Union(projects2);

BuildDoesntContainExpression: you can't use contains, and therefore you can't do the inverse, with the EF for some reason, so use this method:

    private static Expression<Func<TElement, bool>> BuildDoesntContainExpression<TElement, TValue>(    
        Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
    {    
        if (null == valueSelector) 
        { 
            throw new ArgumentNullException("valueSelector"); 
        }

        if (null == values) 
        { 
            throw new ArgumentNullException("values"); 
        }    

        ParameterExpression p = valueSelector.Parameters.Single();    

        // p => valueSelector(p) == values[0] || valueSelector(p) == ... 
        if (!values.Any())    
        {        
            return e => false;    
        }    

        var equals = values.Select(
            value => (Expression)Expression.NotEqual(valueSelector.Body, Expression.Constant(value, typeof(TValue))));    

        var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.And(accumulate, equal));    

        return Expression.Lambda<Func<TElement, bool>>(body, p);
     }
Merritt
Yeah, I was considering this sort of approach as well. Shouldn't there be an easier way? I'm surprised this question isn't more common.
itchi
I'm giving you the answer because this technically works. Although, I'm certain there's a simpler way. But you've put some great thought into this and deserve the points :) Thanks!
itchi