In EF, call SaveChanges from SavingChanges event? - c#

I'm using EF 4.1 in an MVC 3 application.
My goal is to save all changes in another database for logging purposes.
I have implemented the SavingChanges event for an EntityContext. In that event, I'm extracting changes via the GetObjectStateEntries() , that works fine.
Then, I have another EntityContext, that works against a different model and database, for the logging. I create that Context, create logging Entities, adding them to the logging Context. All seems to work fine. Then when I call SaveChanges() on the logging context, Exception occurs, that says that I cant insert because the Id is null (which I know for sure that it isn't).
Does anyone know if it's impossible to achieve this? Am I missing some important detail?

The case was that I had used "Model first" in my logging model, and "DB first" in all other models. That resulted in the mistake that the EF configuration was expecting take care of the Id (GUID) itself, but I was trying to supply one myself. I deleted the entities from the model, and instead, imported them from the DB, and that solved the problem!
Thanks to #Eranga for setting me in the right direction.

Related

Calling SaveChanges when database objects have not been changed

I am coding a MVC 5 internet application with EF6 and I have a question about what happens when the context.SaveChanges() method is called.
Does the DbContext object store the CRUD actions that occur, such that if the SaveChanges() method is called, and none of the data in the database is updated, no action occurs?
Here is an example:
I create a simple model object, then add this to the database and call SaveChanges.
I retrieve this simple object, set one of the objects values to be the same as it currently is, and then call SaveChanges.
In the above example, are any changes made to the database? Do any database transactions occur?
I have done some research, but could not find the answer to this question.
Thanks in advance.
EF6 uses the change tracker to detect if there are any changes.
When you do a call to SaveChanges(), one of the first things EF6 is doing is calling DetectChanges() which will inspect the change tracker.
Now suppose you really want to know if something has changed you can look in the changetracker yourself too. This post shows how in the answer :
Entity Framework 6: audit/track changes
No, if entitys are not changed, it's state is unchanged, so EF is not interested in those.
You can force saving by changing state of entity manualy if required.

Log actions with NHibernate in database

I need a solution for logging and save the database user actions in the system, I need to record the User, the entity, the previous state and the current state of the entity and the date that the user made the change. I am using NHibernate,Autofac and .net 4.0 c#. I thought of creating an attribute filter and put in methods that need to generate the log, but also have interceptors that were created with the Autofac, but still can not think of the best solution, I really need help because they still have not implemented anything like
You could use some Listeners in Nhibernate. It works like triggers in database but in the ORM level. For sample, on PreUpdate method, you could take the old state and the new state of the object the ORM are changing and track some log. If you have a user logged on your AppDomain, you could take this information from the IPrincipal object. You have to inherit from the interfaces like IPreUpdateEventListener and IPreInsertEventListener and implement some method of these interfaces in a class. After it, configure your SessionFactory to use these listeners. There a lot of listerners you can see here.
Look these links:
http://darrell.mozingo.net/2009/08/31/auditing-with-nhibernate-listeners/
http://ayende.com/blog/3987/nhibernate-ipreupdateeventlistener-ipreinserteventlistener
http://nhibernate.info/doc/howto/various/creating-an-audit-log-using-nhibernate-events.html
PS: When you set a listener, it will work for every entity, do not forget to check the type you want to add this behaviour.
To audit database changes I can recommend NHibernate.Envers. I've used it in a previous project with good results.
NHibernate.Envers

Auto Refresh Data In Entity Framework

I using visual studio 2010 and using Entity Framework, and SQL Server 2008 R2. I have after trigger on my table, and When Save one record in table, another column in other table changed.
Is it possible to change automatically changed record on my application.
There is an InsertOnSubmit event that fires as noted here, not sure that's going to help you..
but there are various event fired when saving / modifying entities, but you'd have to bring your "trigger" logic into the code side, and then probably intelligently handle various Entity Changes.. here's more here : How To Execute Business Logic When Saving Changes
and after taking a deeper look at the title of your question it seems that you're trying to get the data from the updated table.. and as the comment suggests.. anything outside the scope of the entity "context" is going to have to be "reloaded". Now if that "loading" code is handled in your "change event" handling, you could accomplish this.. so why not just put all of that logic in your code layer? make the updates to your 2 "entities" and then save them in one swoop..
Though, not the answer you are after, I think you should move the "trigger" logic from the database to the application code. That will solve your problem, AND allow you to write a unit test verifying that data is updated correctly.
I Search for this question and find below code to refresh data in EF :
MyModelEntities.Refresh(System.Data.Objects.RefreshMode.StoreWins, TbMyRecord);

NHibernate & Cancelling Changes to Entities

This seems like it would be a common issue to be but I don't know the best way to solve it. I want to be able to send an Entity to a view, have changes be made to the entity in the view, but then cancel (remove) those changes if the user cancels out of the view. What is the proper way to do this.
Here are two options I have but I think there should be others that are better
1) Take an entity, create a clone, send the clone to the view...if changes are accepted, update the original entity with the clone's values
2) Send the entity to the view, if the user cancels, remove the entity from NHibernate's cache and reload it from the database
For (2), the issue for me would be that the old entity could still be referenced throughout my project after it has been removed from the cache.
Edit:
Ok, so the evict method is the way to go if I am implementing method (2). Thanks, I could not remember the details of that one. However, the issue of view objects referencing my old evicted entities makes the issue tough to deal with. I can't just have my view automatically update to a new entity without having custom code in each one to rebind when my custom eviction event is raised. And rebinding may not be trivial in certain cases. I need to think on this some more as I may be over complicating but at the moment, this method seems trickier.
I suspect I am going to be stuck with method (1) which has its own set of problems but will wait a bit longer to see if anyone else has some ideas.
Edit 2: Just found this. I think it pretty much covers the answer in detail and comes with a great demo project - Building a Desktop To-Do Application with NHibernate - http://msdn.microsoft.com/en-us/magazine/ee819139.aspx
In addition to this, NHibernate has a Session.Refresh(Object entity) function which seems to solve the exact problem. So, when an entity is changed but then cancelled before save, I can just call Session.Refresh to reload it from the database and discard the changes.
I'll go for option 1 and use what is called a ViewModel instead of your entity.
The ViewModel is representation of you model for a specific view. In the ViewModel you can mix data from different entities and pre-format values to fit the view. Is an elegant way of passing data to a view and you can accomplish what you want easily.
Using ViewModels is becoming the preferred way of working in ASP.net MVC and Silverlight / WPF.
To read more about Viewmodels: http://blogs.msdn.com/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx
The best way to do this is to call the Evict method on the ISession used to load the object. This will remove the object from the session cache. and you can then reload and redisplay it.
Evicting the object from the session makes it transient detached so if there are still references to it in the project they will not be persisted when the session is flushed. How you deal with that depends on your application but I would suggest raising an event to notify subscribers that they need to re-load the object.

DotNetOpenAuth - Database.DataContext.AddToUser(user) does not work

I am incorporating DotNetOpenAuth to my asp.net website. I am new with Entity framework.
Database.DataContext.AddToUser(user) located in LogingFrame.aspx.cs does not add a user into the database. User and AuthenticationToken records are filled correctly. The same code from template project, which points to the same database, works fine. Probably I missed something during incorporation. Could you
please point what I have to check? Please let me know if you need any code to be provided.
...does not add a user into the database. User and AuthenticationToken records are filled correctly.
Your question seems to contradict itself, or I'm reading it wrong. It sounds like you're saying no user is added, but then a user is added.
Let me take a stab at it though and let you know how this project template works. A database transaction wraps all database changes within a single HTTP request. It's built into the RelyingPartyLogic assembly to have this behavior. Also, at the end of a successful HTTP request (one that didn't result in an unhandled exception) SaveChanges() is called and the transaction is committed. If an unhandled exception is thrown, the changes and transaction are rolled back. This helps to protect the integrity of your database.
A side-effect of this is, however, that if you're debugging through an "add a user" method and after you see AddToUser executed you jump to the users table to see if it was added, it won't be there because SaveChanges hasn't yet been called and the transaction hasn't been committed yet.
Per standard Entity Framework behavior, SaveChanges must be called for your changes to be persisted in the database, but as I said before, the RelyingPartyLogic library makes this call for you. But you may sometimes need to call SaveChanges yourself in your own code in order to (for example) get the ID of a newly added row. This works even within a transaction before committing it.
Hope that helps.
Did you forget to call DataContext.SaveChanges()?

Categories

Resources