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.
Related
I am new to Entity Framework and Linq, I would like to understand how dbset/dbcontext works when executing the following kind of LINQ request:
from x in db.Products select x
db is the data context object, Products the dataset.
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset? And then we complete and retrieve the records that are not yet tracked/in the dbset?
In other words what is the path of the loading of these elements?
Thank you,
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset?
It's done so at the "base table level" in the Database Server by receiving the results directly from the query and then DataContext will return any existing entity that it already have track of and create new entities if it doesn't have any track for those records.
And then we complete and retrieve the records that are not yet tracked/in the dbset?
The DataContext will create new entities for those records and it'll be tracked if you didn't explicitly specify AsNoTracking.
In other words what is the path of the loading of these elements?
The way it works from this document is that when you make a LINQ Query like this:
from x in db.Products select x
It will generates a LINQ Expression and then pass that expression to the Database Provider to generate the actual database query specific to the database engine it's made for (it may not have all of the query compiled, so some of the query may be computed from the application side.)
It will then execute the query and receive the result from that query and if the query is made with tracking, then it'll return any existing entity that the DataContext already have track of and create new entities if not.
The entity and record will be tied by the key and whenever there is any part of the query using Keyless Entity Type, the whole query would be made as a NoTracking query.
Note that if the database record for such existing entity have changed, it will not update the values in the existing entity, you will have to manually reload that entity like so:
db.Entry(product).ReloadAsync();
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 have read mythz's post here about how ORMLite can read anything up from SQL and fit it into a POCO of the same shape. That is great.
On the other hand, how does ORMLite handle these "View POCOs" when saving them back into the database? Since they are not tables, they may be views or they may be just any sql select queries like that:
var rows = dbCmd.Select<ShipperTypeCount>(
"SELECT ShipperTypeId, COUNT(*) AS Total FROM Shippers GROUP BY ShipperTypeId ORDER BY COUNT(*)");
There's nothing special about the POCOs you use with OrmLite, they're not tied or related back to any underlying tables and there's no hidden magic state that OrmLite caches in between calls so it knows what fields map to.
With every DB call OrmLite just uses the POCO to create the appropriate SELECT, INSERT, UPDATE or DELETE statement based on the schema definition of the type. The INSERT Apis shows some examples of this.
It's best to think of OrmLite as just turning your POCO into an SQL statement, which is what it does. So trying to insert a ShipperTypeCount will attempt to insert a record into a table called ShipperTypeCount unless it has an [Alias("UseTableNameInstead")] attribute which it will use instead.
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();
I have a many-to-many relationship defined between two entities using an association table and cascade="save-update".
Entity1 contains a list of Entity2, and conversely, Entity2 contains a list of Entity1. The SQL outputted from this worflow seems ok...
Create an Entity1 and Entity2 object
Add Entity2 to the List on Entity1
Call session.Save on Entity1
-> Insert statements are run for both entities and then a record inserted into the association table linking them together.
However, if I first call session.Save on Entity2, add it to the List, then call session.Save on Entity1 there is an additional UPDATE statement run which sets all of Entity2's values to exactly the same as what was inserted at the start.
Although not causing any issues, it is an additional query reduce performance. I've played with the inverse attribute but this doesn't eliminate the extra update statement. Currently both sides have inverse="false" as I want the association table updated no matter which entity is saved.
Any ideas?
From the docs:
inverse (optional - defaults to false): If enabled, Hibernate will not try to insert or update the properties defined by this join.
My suggestion: In some cases to prevent additional updates with 2-way joins BOTH collections may need to be updated:
Contact c;
Address a;
c.Addresses.Add(a);
a.Contacts.Add(c);
You are probably getting the additional Update statement because both sides have inverse=false and the first entity's relationship list was saved empty. NH is only doing what it thinks it needs to in order to get all relationships updated.
Thanks for the response but I believe I've found the problem. I had a repository class for each type of entity which implemented the CRUD operations. Each CRUD operation started it's own session/transaction, called Save/Update/etc then closed the transaction/session.
If I call the session.Save for Entity2 then session.Save for Entity1 (which contains the list of Entity2) NH seems to know that it has already persisted Entity2 in the session and hence doesn't try to update the record.
On the other hand, if I call session.Save for Entity2 then session.Save for Entity1 in a separate session/transaction it wants to update Entity2 again. I'm new to NH so not sure how it tracks which objects require updating, but it must reset between sessions?
Kinda makes my nice DDD repositories a little less useful though! Maybe the repositories should use a singleton session or something similar to avoid this problem?
Thanks,
John