I would like to discard all changes made to linq tables (this means -- I use linq, and data are changed on client side, the data on server are intact). How to do this?
EDIT: problem partially solved
http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext/
It works as long as you don't use transaction. When you do and you use mixed "mode" for a record, there is a problem:
begin trans
insert a record
update inserted record
commit trans
When you update record as above Linq counts it as updated record, and in case of exception you have two actions -- transaction is rolled back and data on Linq side are discarded. On discard changes Linq tries to fetch it from the database (discard for update means refetching data for a record), but since all changes were rolled back, there is no records for update.
The question
How to improve DiscardChanges method in a smart general way to work with transactions. Or how to change the workflow of transactions/discard-submitchanges to make all those work together?
Those are not smart solutions:
refetching all data
recreating connection to DB (because it leads to (1))
To add to what Johannes said, I think the confusion here stems from thinking of the DataContext as something similar to a DataSet. It isn't.
A "table" in a DataContext is like a hint on how to retrieve a specific type of data entity from the database. Unlike a DataSet, the DataContext does not actually "contain" data, it simply tracks the discrete entities you've pulled out of it. If the DataContext disappears (is disposed), the entities are still valid, they are simply detached. This is different from a DataSet where the individual DataTables and DataRows are essentially bound to their containers and cannot outlive them.
In order to use the Refresh method of a DataContext, you need to use it on an actual entity or collection of entities. You can't "Refresh" a Table<T> because it's not actually a physical table, it's just a kind of reference.
Changes to entities connected to a DataContext are only persisted when you call the SubmitChanges method. If you dispose of the DataContext, there is absolutely no way that the changes can persist unless you manually reattach the detached entities to a new DataContext.
Simply discard the current DataContext without calling SubmitChanges() and get a new one.
Example:
DataContext myOldDc = new DataContext();
Related
As stated in the title i need to perform delete + insert, i do :
context.DeleteAllOnSubmit ( deleteQuery ) ;
foreach ( var entry in entries )
contex.InsertOnSubmit ( entry ) ;
context.SubmitChanges();
As wrote in that post :
Linq to SQL: execution order when calling SubmitChanges()
I read that the delete operation is the last one applied, but at the moment i see my logic work (i am sure that delete+insert happen dozen of times per day).
What i need is understand if the post is wrong or my logic is and for some reason (update check flag in linq to sql datamodel?) only lucky and avoid the trouble.
After that i would like to know what is the better pattern to make "update" when record cardinality changes.
I mean in my table there is a primary key that identify an entity (an entity has many records) and a subkey that identify each record in the same entity (sub entity).
I need to regenerate (because some sub entity may be inserted, edited or delete) so i use delete + insert (in the messagge form which i write to DB contains only entity and sub enetity that exist, not the deleted ones).
EG:
ID SubID Data
1 1_0 Father
2 2_0 Father
2 2_1 Child 1
3 3_0 Father
3 3_1 Child 1
3 3_2 Child 2
I have no control nor over the table (and data format inside them) nor over the message (that i use to write or delete the table displaied above).
I read that the delete operation is the last one applied, but at the moment i see my logic work (i am sure that delete+insert happen dozen of times per day). What i need is understand if the post is wrong or my logic is and for some reason (update check flag in linq to sql datamodel?) only lucky and avoid the trouble.
Post is correct, delete actually deleted at last.
Your code is working as per design, this is not by chance.
It actually loads all records to be deleted and then deleted all one by one. This happens at last.
This will never fail or will not deleted wrong records, however it has performance issue, you can refer very good msdn article on this
Regardless of how many changes you make to your objects, changes are made only to in-memory replicas. You have made no changes to the actual data in the database. Your changes are not transmitted to the server until you explicitly call SubmitChanges on the DataContext.
When you make this call, the DataContext tries to translate your changes into equivalent SQL commands. You can use your own custom logic to override these actions, but the order of submission is orchestrated by a service of the DataContext known as the change processor.
The sequence of events is as follows: refer msdn
When you call SubmitChanges, LINQ to SQL examines the set of known objects to determine whether new instances have been attached to them. If they have, these new instances are added to the set of tracked objects. This is why we are saying insertion at first
All objects that have pending changes are ordered into a sequence of objects based on the dependencies between them. Objects whose changes depend on other objects are sequenced after their dependencies. then the update
After Update deletion is done
Immediately before any actual changes are transmitted, LINQ to SQL starts a transaction to encapsulate the series of individual commands.
The changes to the objects are translated one by one to SQL commands and sent to the server.
At this point, any errors detected by the database cause the submission process to stop, and an exception is raised.
All changes to the database are rolled back as if no submissions ever occurred. The DataContext still has a full recording of all changes
I was told in L2S, the code for update and insert are the same,
db.InsertOnSubmit(row);
db.SubmitChanges();
and L2S will check to see if it is a insert or update and act approprately in the background.
Is that true?
How about L2E? I tested, looks like in L2E it is not like that. Maybe I did something wrong.
In LINQ to SQL
InsertOnSubmit()
'Adds an entity in a pending insert state to this Table.'
Whereas
SubmitChanges()
'Computes the set of modified objects to be inserted, updated, or deleted, and executes the appropriate commands to implement the changes to the database.'
So Linq to SQL tracks your changes and then uses SubmitChanges to create the neccessary transactions which will commit the changes to your database.
LINQ to Entites uses
SaveChanges()
as the objects in Linq to Entites are not using a lock against the record in the database and so need to be saved rather than the changes submitted.
There's a comprehensive list of differences between L2S and L2E in this stackoverflow question.
when a new entity in my database is created and then i request a table from the datacontext the new entity does not appear.
is linq caching the table and returning the cached version? if so how do i stop linq from doing this.
DALConnector.Dc.Order.InsertOnSubmit(NewOrder);
DALConnector.Dc.SubmitChanges();
now i click a button that shows a form with a gridview on it databound to DALConnector.Dc.Order which doesn't show the new order
How are you rebinding the grid? It does not cache the result, so I am not sure why that is an issue. You have to requery the context to get the new record... Or, if you are rebinding an object's records (like you are binding customers), you could get away with ensurihg the order is added to the Orders collection in the customer object, and not having to requery.
So if you are binding in this way:
grid.DataSource = customer.Orders;
You would only get the new order back if you did:
customer.Orders.Add(newOrder);
dc.Orders.InsertOnSubmit(newOrder);
dc.SubmitChanges();
And then, you could bind customer.Orders directly.
The Linq2Sql DataContext does not cache the complete Table, it only has a cache of the retrieved entities for change tracking purposes. If you would use a new DataContext for querying after you have inserted the order, your result will probably be the same.
AS you are using Linq2Sql, which can only be used with SQL Server, I recommend firing up the SQL Server Profiler and check if a real insert statement is submitted to the database in the first place.
Check your dbml, are you using runtime insert or a stored procedure for Order?
Also check if you're not swallowing any Exceptions the DataContext may raise on SubmitChanges().
If this does not help, please add your query code so we can verify it also.
I am trying to use the attach method to update an entity that was retrieve via a stored proc.
The stored proc is set up to return a specific instance, which is present in my dbml. The retrieval works as expected and returns a fully populated object. The reason I need to use a stored proc is that I need to update a property on that entity at the same time that it is retrieved.
After I have retrieved this entity, I am mapping it using AutoMapper to another model which is used in another tier of the app. This tier performs a few operations, and makes a change to the entity, and passes it back to the repository for updating.
The repository converts this business model back into a database model, and attempts to attach it to the datacontext in order to take advantage of the automagic updating.
No matter what combination of Attach(entity, true) Attach(entity) etc, and it gives me messages like "Row not found or changed" or "Unable to add an entity with the same primary key".
Does anyone have any experience with the Attach method and how it can be used to update entities that did not necessarily come from the data context using query syntax (ie in this case a stored proc)?
Thanks alot
First, if you are creating a copy of the object, making changes and then trying to attach the copied object to the same DataContext as the one with the original object in it, then this would probably result in the "Unable to add an entity with the same primary key" message. One way to handle this is:
1. Get object from DataContext
2. Make changes and map object (or vice versa - whatever order)
3. Update the original object with the new values made in the other tier
4. SubmitChanges on the DataContext containing the original object
or
Get the object from a DataContext and close the DataContext
Make your changes and do your mapping
Retrieve the object from the DataContext to which you want to save
Update that object with the values from your mapped object
SubmitChanges
Alternately, when you say you are using the proc because you need to update a property at the same time that you retrieve it, I'd need to see the proc, but if you are somehow committing this update after retrieving the information, then indeed the message "row not found or changed" is correct. This would be hard to do, but you could do it if you're loading the data into a temp table, doing the update, and then using a select from the temp table to populate the object. One thing you could try is setting that property, in the L2S designer, to AutoUpdate = Never and see if that makes the problem go away. If so, this is your problem.
1: is it the same data-context, and
2: is it the same entity instance (or one that looks like it)
This would only happen for the same data-context, I suspect. If it is the same entity, then it is already there; just call SumbitChanges. Otherwise, either use a second data-context or detach the original entity.
So if I retrieved the entity via a stored proc, is it being tracked by the datacontext?
The thing is.. I'm going from the data model, to a another model that is used by another component, and then back. Its not.. really the same instance, but it does have all the same properties.
IE
public Models.Tag GetEntity()
{
var dbTag = db.PROJ_GetEntity((int)EntityStatuses.Created, (int)EntityStatuses.CreatingInApi).SingleOrDefault();
return FromDb Entity(dbEntity);
}
var appModel = GetEntity(); // gets an Entity from a stored proc (NOT GetEntity_RESULT)
appModel.MakeSomeChanges();
_Repo.Persist(appModel);
public void Persist(Models.AppModel model)
{
var dbEntity = Mapper.Map(model);
db.Attach(dbEntity);
db.SubmitChanges();
}
This is somewhat pseudo code like.. but it demostrates pretty much exactly what I am doing.
Thanks
I'm upvoting weenet's answer because he's right - you can't use Attach to apply the changes.
Unlike Entity Framework, you can only attach an L2S object to a datacontext if it has never been attached before - i.e. it's a newed entity that you want to Insert into a table.
This does cause numerous problems in multi-layered environments - however I've been able to get around many of the issues by creating a generic entity synchronisation system, which uses reflection and expression trees.
After an object has been modified, I run the dynamic delegate against a new object from the DC and the modified object, so that only the differences are tracked in the DC before generating the Update statement. Does get a bit tricky with related entities, though.
Using LINQ to Entities sounds like a great way to query against a database and get actual CLR objects that I can modify, data bind against and so forth. But if I perform the same query a second time do I get back references to the same CLR objects or an entirely new set?
I do not want multiple queries to generate an ever growing number of copies of the same actual data. The problem here is that I could alter the contents of one entity and save it back to the database but another instance of the entity is still in existence elsewhere and holding the old data.
Within the same DataContext, my understanding is that you'll always get the same objects - for queries which return full objects instead of projections.
Different DataContexts will fetch different objects, however - so there's a risk of seeing stale data there, yes.
In the same DataContext you would get the same object if it's queried (DataContext maintains internal cache for this).
Be aware that that the objects you deal are most likely mutable, so instead of one problem (data duplication) you can get another (concurrent access).
Depending on business case it may be ok to let the second transaction with stale data to fail on commit.
Also, imagine a good old IDataReader/DataSet scenario. Two queries would return two different readers that would fill different datasets. So the data duplication problem isn't ORM specific.
[oops; note that this reply applies to Linq-to-SQL, not Entity Framework.]
I've left it here (rather than delete) because it is partly on-topic, and might be useful.
Further to the other replies, note that the data-context also has the ability to avoid doing a round-trip for simply "by primary key" queries - it will check the cache first.
Unfortunately, it was completely broken in 3.5, and is still half-broken in 3.5SP1, but it works for some queries. This can save a lot of time if you are getting individual objects.
So basically, IIRC you need to use:
// uses object identity cache (IIRC)
var obj = ctx.Single(x=>x.Id == id);
But not:
// causes round-trip (IIRC)
var obj = ctx.Where(x=>x.Id == id).Single();