I wanted to get your opinions on the easiest way to track changes that users make when they do CRUD events. I am working on a system where the users are less interested on permissions, but really want to have a sophisticated log of what changes a user made. I am using ASP.NET MVC 3, EF, and NLog.
Any advice is greatly appreciated :)
Steve
I use a convention based approach. Each entity has an associated audit entity which includes all properties from the base entity plus information on the change, including whether it was successful or not. I override the SaveChanges method on the DB context. For each entity being changed it creates an audit entity from it holding the new values. It attempts to save the changes, then uses a separate, auditing context to save each of the audited entities with the results of the save operation. I use an injected utility in the data context to get access to the current user (via HttpContext.Current for web, via the Environment.User for non-web) when constructing the audit entities.
I blogged about an earlier version of this for LINQ to SQL at http://farm-fresh-code.blogspot.com/2009/05/auditing-inserts-and-updates-using-linq.html. You should be able to get the basic idea from that.
Related
We have a feature in our system where the unit tests have been passing for the passed year.
Since yesterday, they are failing and when looking into those unit tests, it seems the unit tests should never have passed because the associating entities are just not there.
My question is whether there is a audit trail for when someone deletes an entity connected to another entity?
When you navigate to Settings - Auditing - Audit summary view you will be able to see all the entries of Audit including Delete action for all the entities across the CRM system.
Click on Enable/Disable filters, then apply the filter whatever you want like Event, Entity, Date, etc to drill down & see the desired data.
Read more
i have upgraded our application to SWF 2 and have implemented FMPC pattern. majority of our existing flow definitions doesn't have end-state, now using FMPC as described here, you can trigger commit by putting commit=true to your end-state. Example of our flow:
get form object
save details to db (we want to commit here)
fetch the same object with refreshed data
display to view
its currently working with previous SWF and just using Open Session in View pattern. but we imlemented FMPC to avoid any LazyInitializationException. Now what's happening is steps 1-4 is happening except that changes are not committed, so in the view, we don't see any changes. it seems difficult to add end-state at the middle just to commit to DB and also this means we need to add so many end-state, so my question is how to tell (SWF/FMPC) to commit "programmaticaly" without having to add the end-state tag. If you know better approach, please tell also. Thanks!
Spring Web Flows can have inheritance, so you can implement the end-state in your parent flow and then have it as a parent for all your flows.
I resolved my issue. I finally found out that indeed Hibernate is auto-committing all my read-write operations. The problem is when refreshing the object concerned which gave me the impression that there is no read-write done while in fact there is. Doing sessioFactory.refresh(object) instead of plain find() effectively fetched the updated data from the DB. I guess its because the hibernate session is still alive (due to FMPC) that's why doing "find" will retrieve from the hibernate cache while "refresh" means re-reading the data directly from underlying database. Please correct my analysis as necessary.
In a SPA app using breeze, how would I go about combining metadata from multiple sources for related data so that I can use them in 1 manager on the client. For example, I might have the following
Entity Framework Metadata from WebAPI controller (e.g. Account)
Custom Metadata from DTOs (e.g. Invoices)
Data from a third party service with metadata provided from client side metadata (e.g. Invoice transmission result)
In each case the data has related properties so I might want to be able to use Account.Transactions.TransmissionResults
UPDATE
I have tried several ways of getting this to work but to no avail. From Jay's answer, it is not possible at present to update the metadata from the server once it has been retrieved, so if and until that changes (see breeze user voice issue) I am left with one of the following approaches
1 Retrieve metadata from the server from Entity Framework and add metadata on the client to add extra entities. This worked to a degree but I could not add navigation properties from entity types added on the client to entity types retrieved from the server because I cannot add the foreign key association to the entity retrieved from the server, again back to the need to modifying metadata after it has been retrieved.
2 Write the complete metadata by hand, which will work but makes maintainability that much harder and seems wrong to be manually writing mostly the same code that the designer would write.
3 Generate most of the code from Entity Framework as described in the docs and then update it afterwards to add in the custom entities. Again similar issues than with option 2, it seems hacky.
Anyone else tried something similar? Is there something I am missing, which I could be, I've only started with breeze and js.
Thanks
A breeze EntityManager can have metadata from any number of DataService endpoints, and you can manually add metadata (new EntityTypes) on the client at any point. The only current restriction is that once you have metadata from a specific service, you can't change it. ( We are considering reviewing the last restriction).
So the question is, what are you trying to do that you can't right now?
Anyone please help me on how to disable DELETE option in EF6?
I mean from the application, now record should be deleted (even accidentally)
Thanks.
Create a user/role in the database that does not have permissions to delete/modify records and use it in your application. EF itself is not meant to be a security tool and there are always options to perform a delete operation (e.g. a developer can send any arbitrary SQL query/command to the database bypassing all the 'security' measures implemented in the data access layer)
When getting the entities call with AsNoTracking() option.
eg :- Context.Users.AsNoTracking()
Edit after Stevens Comment
Its true that anyone can still go and change the entity state to Deleted manually. I would recommend, using Repository Pattern for data access and can restrict delete operation. By hiding the DbContext outside of the assembly.
I'm looking at using Subsonic with a multi-tenant ASP.net web application. There are multiple DB's (one per client/instance). The user logs in with a domain suffix to their username (e.g. user#tenant1, user#tenant2).
The custom membership provider will then determine which database a user is using, and authenticate against it. All user-initiated calls in the webapp will be wrapped in a SharedDbConnectionScope call, however I have a question regarding caching subsonic items.
Basically each instance will have a few records that rarely change (search options/configurations). I would like to read these in the Application_Start event, and cache them into the ApplicationState.
In the Application_Start event, it would loop over each client database, use a SharedDbConnectionScope to connect to each DB, and create these cached records (e.g. Application('tenant1_search_obj') = subsonic_object
When a user loads the search page, it would then check what domain a user is in, and then retreive that search option from the cache.
Is this feasible? I'm just concerned that if I cache an object, when I retrieve it from the application cache it won't know what connection its using, and might possibly pull in the wrong data.
I'd like to avoid putting this in the session object if possible.
it's possible, but probably not a good idea since it doesn't scale at all - you're going to pop a new connection for every single client whether they show up or not.
Maybe your best bet is to "lazy load" the setting - first hit on the search page loads the config into the cache or Application settings and there it stays.
Other than that - to answer your question it is possible. If you're using SubSonic 3, just create a new provider on the fly using ProviderFactory.GetProvider(connectionString, "System.Data.SqlClient") and then execute your stuff against it.
For SubSonic 2 - SharedConnectionScope is what you want.