How NHibernate track changes made to the fields in my entity? - c#

How NHibernate track changes made to the fields in my entity? If I use second level cache and I change my entity, How does it apply my changes to db?

When you change an entity, the entity becomes "dirty" and nhibernate knows the update the entity in your database when the session is flushed. That said, sometimes its possible for entities to get marked dirty even though you have made no change. This results in unnecessary update calls to your database.
It is best to isolate your entities from your views via view models. Once you pull an entity out of the database, convert it to a view model that you can mangle up.

Related

ef core best practice to update complexe objects

We are leading into some issues with ef-core on sql databases in a web-api when trying to update complexe objects on the database provided by a client.
A detailed example: When receiving an object "Blog" with 1-n "Posts" from an client and trying to update this existing object on database, should we:
Make sure the primary keys are set and just use
dbContext.Update(blogFromClient)
Load and track the blog while
including the posts from database, then patch the changes from
client onto this object and use SaveChanges()
When using approach (1) we got issues with:
Existing posts for the existing blog on database are not deleted
when the client does not post them any more, needing to manually
figure them out and delete them
Getting tracking issues ("is already been tracked") if
dependencies of the blog (for example an "User" as "Creator") are
already in ChangeTracker
Cannot unit test our business logic without using a real DbContext
while using a repository pattern (tracking errors do just not exist)
While using a real DbContext with InMemoryDatabase for tests cannot rely on things like foreign-key exceptions or computed
columns
when using approach (2):
we can easily manage updated relations and keep an easy track of
the object
lead into performance penalty because of loading the
object which we do not really need
need to map many manual things
as tools like AutoMapper cannot be used to automaticlly map
objects with n-n relations while keeping a correct track by ef core (getting some primary key errors, as some objects are deleted from lists and are added again with the same primary
key, which is not allowed as the primary key cannot be set on insert)
n-n relations can be easily damaged by this as on database
there could be n-n blog to post, while the post in blog does hold
the same relation to its posts. if only one relation is (blog to
post, but not post to blog - which is the same in sql) is posted and
the other part is deleted from list, ef core will track this entry
as "deleted".
in vanilla SQL we would manage this by
deleting all existing relations for the blog to posts
updating the post itself
creating all new relations
in ef core we cannot write such statements like deleting of bulk relations without loading them before and then keeping detailed track on each relation.
Is there any best practice, how to handle an update of complexe objects with deep relations while getting the "new" data from a client?
The correct approach is #2: "Load and track the blog while including the posts from database, then patch the changes from client onto this object and use SaveChanges()".
As to your concerns:
lead into performance penalty because of loading the object which we do not really need
You are incorrect in assuming you don't need this. You do in fact need this because you absolutely shouldn't be posting every single property on every single entity and related entity, including things that should not be be changed like audit props and such. If you don't post every property, then you will end up nulling stuff out when you save. As such, the only correct path is to always load the full dataset from the database and then modify that via what was posted. Doing it any other way will cause problems and is totally and completely 100% wrong.
need to map many manual things as tools like AutoMapper cannot be used to automaticlly map objects with n-n relations while keeping a correct track by ef core
What you're describing here is a limitation of any automatic mapping. In order to map entity to entity in collections, the tool would have to somehow know what identifies each entity uniquely. That's usually going to be a PK, of course, but AutoMapper doesn't (and shouldn't) make assumptions about that. Instead, the default and naive behavior is to simply replace the collection on the destination with the collection on the source. To EF, though, that looks like you're deleting everything in the collection and then adding new items to the collection, which is the source of your issue.
There's two paths forward. First, you can simply ignore the collection props on the source, and then manually map these. You can still use AutoMapper for the mapping, but you'd simply need to iterate over each item in the collection individually matching it with the appropriate item that should map to it, based on your knowledge of what identifies the entity (i.e. the part AutoMapper doesn't know).
Second, there's actually an additional library for AutoMapper to make this easier: AutoMapper.Collection. The entire point of this library is to provide the ability to tell AutoMapper how to identify your entities, so that it can then map collections correctly. If you utilize this library and add the additional necessary configuration, then you can map your entities as normal without worrying about collections getting messed up.

What is happening behind EF SaveChanges()

Assume that I have a domain object which has association with couple of other entities (ofcourse mapped to multiple tables). And I made changes in master and associated entities. Naturally EF has to update this in multiple tables on save.
Whether it be ObjectContext or DbContext, a call to SaveChanges() method will tell Entity Framework to "Saves all changes made in this context to the underlying database."
Could anyone tell me "What is happening behind SaveChanges()"?
Is all resulting sql statements INSERT/UPDATE/DELETE goes to database in one go as prepared statement?
or is EF doing back and forth with DB to execute the sql statement one by one?
Is there any configuration in EF to switch between this?
At the moment statements for CUD operations are not batched. We have a work item to fix this. Feel free to upvote
From what I understand, each modified entity will result in a roundtrip to the database (all bound by a single transaction). While I'm not aware of any configuration that will change this behavior, I won't say that there are not EF implementations out there that achieve this "batching" functionality. I just don't think they are available, out of the box.

Nhibernate: how to postpone update or delete?

i need help:
I'm a beginner with Nhibernate.
I have created a wpf application that load a datagrid binded with an observable collection.
This collection is loaded with repository pattern and Nhibernate querying database.
I want to modify this collection with UI (edit, add, delete).
When i click to my save button i want to persist my changes to db table.
I read nhibernate documentation and i learn that there are 2 level of cache, my idea is to modify objects in first level cache, and when I am sure of my changes i want to persist.
there are some best practices for doing this?
How to mark for deletion or update an object and delete or update it after "save changes" click?
This should be an interesting read: Building a Desktop To-Do Application with NHibernate
Basically, you should use the ISession object's methods, and do operations inside a transaction, i.e. ISession.BeginTransaction()
It depends on how you get your entities. If they are root entities, e.g. employee then when you delete an entity from the grid, you should keep track of these deleted entities and call delete on all of them. You should also keep track of the added entities.
Then basically what you are left with are the updated entities. NH keeps track of the state and knows if an entity was modified.
We have ISession.Save/Update/Delete.
When you have done this for every modified entity, call Commit on the transaction. This will save the changes to the database.
If your entities are not roots, but e.g. are employees addresses, then it will be enough to call save on the employee - if your mappings are correct.

How to save it in entity right

Assume i have a big entity and want to create a typical CRUD application. A user shouldn't have the ability to save some fields of my entity.
So i see two ways to implement change-save logic:
a)
Get entity from DB
Out to page with all fields(fields which user shoudnt change outed as hidden inputs)
Take entity by post method
Attach to context and save
In this case i need to out on page useless fields. And it is sucks no doubt.
b)
Get entity from DB
Out to page only necessary fields(fields which user can change)
Take entity by post method
Get entity from DB
Fill DB entity by new values and save
In this case i need to do additional query to DB. So it is not good for perfomance.
What is right way?
or C):
Get entity from DB
Map entity to ViewModel with only the allowed fields
Post ViewModel with data back to controller
Map ViewModel back to Entity
Attach and Save.
EDIT:
I highly recommend AutoMapper for the mapping to and fro
Interestingly enough, I just watched a video made by Julie Lerman in which she discusses almost the exact same problem. Neither of your solutions was what she went with:
Have a separate entity class that contains the fields that you want to go on the screen, but still maps to the same table that the regular one does. Then just query that DbSet for grabbing the entity (with only those fields), and save the updates to that.
She mentioned this while discussing implementing Domain Driven Design on top of Entity Framework. So that if you have different DbContexts for different functions in your application, you can still have a DbContext that you're using write to the table, but you can restrict which fields that context can write to.
It is recommended to use different ViewModels for different tasks. If you want to show the user some fields of the Model to edit, then you can do so using EditModel and while saving use CreateModel to create and populate the database. This way you can avoid your database structure to be known to the user, thus ensuring protection and security.

What does LINQ-to-SQL Table<T>.Attach do?

What exactly does the LINQ-to-SQL method Table<T>.Attach() and Table<T>.AttachAll() and what is an example/situation for their proper usage?
Also, please check out this related question: How to detach a LINQ-to-SQL data object from the DataContext's tracking mechanism?
It is really useful in multi-tier applications that serialize/deserialize data to other layers.
Short version:
Attach() tells DataContext the entity is not new (for insert) but an updated entity that is meant to be updated in the DB.
Long version:
You have a DataContext where your entities exist. New entities get inserted, existing ones get updated. Now you need to send some entity to another tier, DataContext then detaches said entity and sends it away.
On the other tier the entity gets modified and sent back to your data layer. Now the former DataContext that had your entity may not exist anymore (eg. if it is stateless) or does not know your deserialized entity so what do you do? You create a new DataContext or use the existing one and use the Attach() method - this way the DataContext knows the entity is meant to be updated and should not be inserted into the database.
The same goes for AttachAll() but for multiple entities.
LINQ to SQL maintains the state of entities in a DataContext object. Entities that are loaded from the database are associated with a DataContext that is responsible for tracking any changes to the entity so when you save it the appropriate changes are made to the database.
Entities can become detached from the DataContext when they are serialized (for passing to a client for example in an n-tier application). When the client returns the entity back to your DA layer you will need to reattach it to a DataContext before it can be updated or deleted in the database. The Attach method performs this operation.

Categories

Resources