Can I "undo" a LINQ to SQL update? - linq-to-sql

In LINQ-to-SQL if I update an object in the context but haven't called SubmitChanges, is there a way to "undo" or abandon that update so that the changes won't get submitted when I eventually call SubmitChanges?
For example, if I've updated several objects and then decide I want to abandon the changes to one of them before submitting.
Part 2: same question for Entity Framework, v3.5

Both LINQ to SQL and Entity Framework will use the same call (assuming you still have the active Context):
_dbContext.Refresh(RefreshMode.OverwriteCurrentValues, yourObj);
A more appropriate way would be to treat the Context as a Unit of Work, in which case you would no longer have an active context when refreshing the object. You would simply dispose of the object you're using currently and get a fresh copy from a new context.

I think you can use the .GetOriginalEntityState(yourEntity) to retrieve the original values. Then set your updated entity back to the original
dim db as new yourDataContext
//get entity
dim e1 as yourEntity = (from x in db.table1).take(1)
//update entity
e1.someProperty = 'New Value'
//get original entity
dim originalEntity = db.table1.getOrignalEntityState(e1)
e1 = originalEntity
db.submitChanges()
Very pseudo-code but I think it conveys the right idea. Using this method, you could also just undo one or more property changes without refreshing the entire entity.

Related

Do views immediately reflect data changes in their underlying tables?

I have a view ObjectDisplay that is composed of two relevant tables: Object and State. State represents the state of an Object, and the view pulls some of the details from the most recent State for each Object.
On the page that is displaying this information, a user can enter some comments, which creates a new State. After creating the new State, I immediately pull the Object from ObjectDisplay and send it back to be dropped into a partial view and replace the Object in the grid on the page.
// Add new State.
db.States.Add(new State()
{
ObjectId = objectId,
Comments = comments,
UserName = username
});
// Save the changes (executes all of the above).
db.SaveChanges();
// Return the new Object information.
return db.Objects.Single(c => c.ObjectId == objectId);
According to my db trace, the Single call occurs about 70 ms after the SaveChanges call, and it occurs on the same SPID.
Now for the issue: The database defaults the value of RecordDate in State to GETUTCDATE() - I don't provide the date myself. What I'm seeing is that the Object returned has the State's RecordDate of the old State and the Comments of the new State information of the old State. I am seeing that the Object returned has the old State's information. When I refresh the page, all the correct information is there, but the wrong information is returned in the initial call from the database/EF.
So.. what could be wrong? Could the view not be updating quickly enough? Could something be going on with EF? I don't really know where to start looking.
If you've previously loaded the same Object entity in the same DbContext, EF will return the cached instance with the stale values, and ignore the values returned from SQL.
The simplest solution is to reload the entity before returning it:
var result = db.Objects.Single(c => c.ObjectId == objectId);
db.Entry(result).Reload();
return result;
This is indeed odd. In SQL Server views are not persisted by default and therefore show changes in the underlying data right away. You can create a clustered index on a view with effectively persists the query, but in that case the data is updated synchronously, so you should see the change right away.
If you are working with snapshot isolation level your changes might not be visible to other SPIDs right away, but as you are on the same SPID and do not use snapshot isolation, this cant be the culprit either.
The only thing left at this point is the application layer. Are you actually using the result of the Single call higher up in the call stack or does that get lost somewhere. I assume that a refresh of the page uses a different code path, which would explain why it is working there.

Confusion with Entity Framework context

I'm a bit confused in regards to how EF's dbContext works.
If I do something like _context.Persons.Add(_person) (assuming person is a valid entity), if I then (before calling _context.SaveChanges()) query Persons, will the person I just added be included in the results?
For example:
Person _person = new Person() {Firstname = "Bill", Lastname = "Snerdly"};
_context.Persons.Add(_person);
var _personList = _context.Persons.Where(p => p.Lastname.StartsWith("Sne"));
Whenever I try this, it seems as though the context loses track of the fact that I've added this new person to the context.
What confuses me is that if I edit an existing person and attach the person and set the state to modified, querying the context seems to keep track of the changes that were made and returns them in the results. For example:
//Assuming that Person 5 exists with the name William Snerdly
Person _person = new Person() {Id = 5, Firstname = "Bill", Lastname = "Snerdly"};
_context.Persons.Attach(_person);
_context.Entry(_person).State = System.Data.EntityState.Modified;
var _personList = _context.Persons.Where(p => p.Lastname.StartsWith("Sne"));
In this case, it seems like the person with the id of 5 will show up in the list with the name Bill instead of William. IOW, the context queried the data but retained the changes while in the first scenario, the context queried the data but ignored any added items. It just seems a bit inconsistant.
Am I understanding this correctly or am I missing something?
Thanks for your help with this.
No, as it does not yet exist in the database. It will, however, be accessible through the ObjectStateManager of the ObjectContext, or alternatively, if you're using the DbContext/DbSet wrappers, through the .Local property of the DbSet.
In the case of the edit, you're seeing the ORM's first level cache at work. The query is executed against the database (and so compares against the values in there - your example would get even weirder if you modified the Lastname in the context, but still get the result from the query looking for the unmodified Lastname), but when its results are processed, first the ID of the returned entity is checked, and since the entity with that ID is already present in the context, you get that instance back. This is the default "AppendOnly" mode of operation.
I don't know what you want to do, but I had to understand all that when I wanted to validate my changes according to rules that needed to use the values of both loaded and unread entities. I ended up starting a transaction, saving the changes with the "None" options, doing my validation queries againt the database (which then contained the "merged" view of the data), and the rolling back the transaction if the data was invalid, or accepting the changes and committing the transaction otherwise.

Linq SubmittingChanges after assigning new object

If I make changes to an existing linq object by assigning a "new" object of the same type (with different values), SubmitChanges does not make the changes in the database. why not?
existing= new Data.Item{a=1, b=2...};
vs
existing.a= 1;
existing.b= 2;
Because you are not changing the object, you are assigning a new object to the variable.
You need to assign to fields one by one, (or InsertOnSubmit... but that will create a new object in the database and it does not sound like that is what you want to do).
This approach will sort of work if you we assigning the newly created object to a field of an object that LINQ to SQL knows about, but once again, that would be creating a new object rather than changing the one that field previously pointed to (which could result in a bunch of garbage rows in your database if you never get rid of them).

How to update in Linq to SqL?

every example I seen shows how to do a update query in linq to sql by doing this.
// grab entity you want to update
entity.UserId = "123"; // update the fields you want to update.
entity.Name = "bob";
Dbcontext.SubmitChanges();
I am wondering can you juse pass in a new object and have it figure it out?
Like could I do this?
Enity myEntity = new Entity();
myEntity.UserId = "123";
myEntity.Name = bob:
// grab entity record
// shove record ito the found record
// it figured out what to update and what no to update
Depending on what exactly you want to do you either need the InsertOnSubmit method, or the Attach method of the respective table (i.e. dbContext.Entities). InsertOnSubmit is used to add a record, while Attach can be used if you want to affect an UPDATE without having to first SELECT the record (you already know the primary key value)
In the case you have the dbContext available and ready, just add InsertOnSubmit:
Entity myEntity = new Entity();
myEntity.UserId = "123";
myEntity.Name = bob:
Dbcontext.InsertOnSubmit(myEntity);
Dbcontext.SubmitChanges();
As the name of the method implies, this will insert your new entity into the database on calling SubmitChanges.
Marc
If you want to do this for performance reasons then you shouldn't worry about it. Linq to Sql will cache objects locally so that just grabbing an entity by ID to modify some fields is very cheap.
It's possible to attach and persist it to the database, however you may want to set a field to check for concurrency (ie LastModified).
If you are going to use the Attach method on the data context, you need to set the primary/composite keys before you attach the entity (so you don't trigger INotifyPropertyChanging, INotifyPropertyChanged events).

DLINQ- Entities being inserted without .InsertOnSubmit(...)?

I ran into an interesting problem while using DLINQ. When I instantiate an entity, calling .SubmitChanges() on the DataContext will insert a new row into the database - without having ever called .Insert[All]OnSubmit(...).
//Code sample:
Data.NetServices _netServices = new Data.NetServices(_connString);
Data.ProductOption[] test = new Data.ProductOption[]
{
new Data.ProductOption
{
Name="TEST1",
//Notice the assignment here
ProductOptionCategory=_netServices.ProductOptionCategory.First(poc => poc.Name == "laminate")
}
};
_netServices.SubmitChanges();
Running the code above will insert a new row in the database. I noticed this effect while writing an app to parse an XML file and populate some tables. I noticed there were 1000+ inserts when I was only expecting around 50 or so - then I finally isolated this behavior.
How can I prevent these objects from being persisted implicitly?
Thanks,
-Charles
Think of the relationship as having two sides. When you set one side of the relationship the other side needs to be updated so in the case above as well as setting the ProductOptionCategory it is effectively adding the new object to the ProductOptions relationship on the laminate ProductOptionCategory side.
The work-around is as you have already discovered and to set the underlying foreign key instead so LINQ to SQL will not track the objects in the usual way and require implicit indication it should persist the object.
Of course the best solution for performance would be to determine from the source data which objects you don't want to add and never create the instance in the first place.