This has probably already been asked and answered 1000 times, but Google has not been not my friend this morning.
I'm making the switch from using stored procedures and business objects to using Entity Framework. I like the simplicity of generating your POCOs from the generated EDM (Database-First approach here). And I like how much less typing it is.
I'm having a hard time wrapping my head around a suitable design for a VERY COMMON application scenario (in my world, anyway).
Basically, picture a data entry application, let's say for an online store's administrator (I'm doing it in WPF, but it could easily be web-based).
The admin will want to view a list of Customers (Manage Customers view) in a data grid. For each row, there is button to edit the Customer or delete it. At the bottom of the grid there is a button to create a new Customer.
If they delete a Customer, it is removed (after a confirmation) immediately from the data grid, as well as the back-end data store. If they edit a Customer, a window pops up (Edit Customer View), displaying the current data for that Customer. They can edit the data, then click either Submit, or Cancel. Submit saves the changes to the data store, and cancel discards the changes. Both buttons close the Window.
If, they click the New Customer button from the Manage Customer view, then a new Customer object is created (not saved to the DB yet), and the same Edit Customer view is opened, displaying the new, blank Customer.
Here is what I've got so far:
When the Manage Customers View Model is constructed, it populates a public list of Customers, something like:
public List<Customer> customers {get; set; }
using (WebStoreEndities context = new WebStoreEntities())
{
customers = context.Customers.ToList();
}
Then, if the admin user clicks the Edit button in a Customer row, the bound Customer object is passed to the constructor of the Edit Customer view. That view constructs its view model, which has the customer property that the view is bound to. The user can make their changes to the Customer object in the view, then either click Save or Cancel.
This is where I get lost. In my business object/stored procedure implementation, I would just have two Customer objects: one for the Customer being edited (bound to the view), and one copy of that Customer, called backupCustomer, used for reverting changes if they cancel out of the Edit Customer view (since I'm using MVVM, the properties of the Customer are changed immediately from the UI, and if they start making changes, and then click Cancel, they'll expect not to see their changes in that Customer).
More to the point, if they do click Submit in the Edit Customer view, that calls the Customer business object's Save() method, which reaches into the DAL and fires off the stored procedure to update the data store.
Okay, so now on to Entity Framework reality.
Issue #1. There is no way to save an individual entity. So even if I extend the Customer entity to have a Save() method, it would have to create a new WebStoreEntities context and call SaveChanges() on it:
using (WebStoreEntities context = new WebStoreEntities())
{
context.SaveChanges();
}
That seems weird to me. I wouldn't think you'd want have an entity instance creating entity contexts and stuff.
Issue #2. In my business objects implementation, I cache my objects, so I only need to ever fetch them from the DB once. If they make changes to a Customer, great. I just call save() on it and it updates the data store. Same with deletes and inserts. But I never have to fetch the same collection of Customers more than once (concurrency is not an issue on this particular project). In my EF implementation, every time they open the Manage Customers view, it's firing off the code above to get a list of Customers. I suppose I could just keep one data context open during the entire application, but that seems like a bad design too. Tying up a connection the the data store for the entire user session, just because they might open the same view more than once.
Please help me with my above issues, if you can, don't get hung up on what I'm about to say (it's just my initial impression anyway):
It seems like EF muddies the logical boundaries in my separation of concerns:
You have to keep a copy of the Entity connection string in your UI project (I keep my business objects and data objects in a separate project usually).
You can't tell an entity to save itself or delete itself. You have to do it from the underlying context, which is typically in the UI layer. In my UI, I like to be able to say myBusinessObject.Save() or myBusinessObject.Delete(), knowing that the object knows how to save or delete itself.
Anyway, it seems like EF is the future, so I'm going to stick with it. I would love your recommendations.
Thanks so much!
The Funk Monkey.
While most examples have you implement queries surrounded by a using you shouldn't actually do that in your case. Each EF context tracks it's own entity changes, by using multiple usings you won't know which context did the look up to call SaveChanges on it. So just use one context per user and dispose when your completely done (on exit, ect). You can use a singleton or a static class, in a desktop app it doesn't seem to make much difference from my experience. In an MVVM scenario you may be able to get away with the ViewModel handling the context as well, so when you instantiate your ViewModel instantiate your context and dispose your context on dispose, that might make more logical sense depending on how your handle the data internally.
For being able to revert changes EF actually tracks both the original DB version of the object as well as your changed version of the object. However to get that information is a little convoluted:
Disconnect and look up the entity:
((IObjectContextAdapter)myContext).ObjectContext.Detach(dbObject);
var entry = myContext.Entry(dbObject);
var original = entry.OriginalValues;
Personally I just handle copying and keeping the original object in code, it's cleaner and seems to be safer. It's also probably faster, but I've never run tests to prove that. If you're in a multi-user environment you may benefit from simply reloading the data from the DB though so that you don't mistakenly display stale data.
Issue #1: You want you entity to have a Save method but you want to avoid creating a coupling between the entity and the persistence layer (e.g. the EF context)? Well, if the Save method is implemented by the entity then you cannot avoid that. Better perhaps, is to move the Save method to a repository:
repository.Update(entity);
Now it is the responsibility of the repository to create the EF context, not the entity.
Issue #2: EF contexts are lightweight and the normal pattern of usage is as you describe where the context is created transiently and then disposed after changes have been saved. Conceivably, you can create a desktop app the has one context for the lifetime of the application but if the database is changed while the app is running the content of the context will get out of date. Sooner or later inconsistency in state will hit you and I would think that you get a more maintainable application if you stick to the transient context pattern. If you are writing a web app you will not have the option to keep a database context alive between requests and that pattern has proven to be very successful when writing business apps.
So I recommend this:
Implement persistence in a repository or service class, not in the entity class.
When reading or writing entities do it in a manner that ensures that the EF context only exists for the duration of the operation (unit of work). Optionally, you can use a row version number to ensure that an entity cannot be updated if it has been changed in the database after the last write.
By the sounds of it...you prefer the ActiveRecord pattern...but EF follows the UnitOfWork pattern...in your case you are using POCO Entities....which are "persistent-ignorant".
http://randolphcabral.wordpress.com/2008/04/03/active-record-vs-unit-of-work/
refactoring: swicthing from custom data access layer to Entity Framework
One approach to hide the "EF technology", is to create a "repository" layer inside of which you hide all the EF logic i.e. management of the "context". But creating another layer can be a lot of repetitive work. Typically your repositories would share the same context.
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
http://www.dataworks.ie/blog/entity_framework_5_with_automapper_and_repository_pattern
If you keep the EF context around, then it manages the change-tracking and caching of already retrieved objects for you.
Alternatively, you can work in a disconnected mode...where you create the context each time you want to retrieve/perist entities...however, you then have to do the caching and state-tracking yourself and "reattach" the objects to the context, before submitting.
Related
The Problem
We have an app that stores hierarchical data in a database. We have defined a POCO object which represents a row of data.
The problem is we need certain properties to be dependent on the item's children and others on their ancestors. As an example, if a ((great)grand)child has incomplete state, then implicitly all of its parents are also incomplete. Similarly, if a parent has a status of disabled, then all children should be implicitly disabled as well.
On the database side of things, everything works thanks to triggers. However, the issue we're having is then synching those changes to any in-memory ORM objects that may have been affected.
That's why we're thinking to do all of this, we need to ensure there is only ever one model instance in memory for any specific row in the database. That's the crux of the entire problem.
We're currently doing that with triggers in the DB, and one giant hash-set of weak references to the objects keyed on the database's ID for the in-memory ORM objects, but we're not sure that's the proper way to go.
Initial Design
Our 'rookie' design started by loading all objects from the database which quickly blew out the memory, let alone took a lot of time loading data that may never actually be displayed in the UI as the user may never navigate to it.
Attempt 2
Our next attempt expanded on the former by dynamically loading only the levels needed for actual display in the UI, which greatly sped up loading, but now doesn't allow the state of the hierarchy to be polled without several calls to the database.
Attempt 2B
Similar to above, but we added persistent 'implicit status' fields which were updated via triggers in the database. That way if a parent was disabled, a trigger updated all children accordingly. Then the model objects simply refreshed themselves with the latest values from the database. This has the down-side of putting some business logic in the model layer and some in the database triggers as well as making both database writes and reads needed for every operation.
Fully Dynamic
This time we tried to make our models 'dumb' and removed our business layer completely from the code, moving that logic entirely to the database. That way there was only single-ownership of the business rules. Plus, this guaranteed bad data couldn't be inserted into the database in the first place. However, here too we needed to constantly poll the database for the 'current' values, meaning some logic did have to be built in to know which objects needed to be refreshed.
Fully Dynamic with Metadata
Similar to above, but all write calls to the database returned an update token that told the models if they had to refresh any loaded parents or children.
I'm hoping to get some feedback from the SO community on how to solve this issue.
I'm using ASP.NET WebApi 2 and loading in part of a relational database structure into the front end website. This allows the user to make changes to multiple tables in a single store and to also view some extra data.
This mostly works pretty well. It means I can store changes to, say a person table and their related clothes and hair color on one call as follows:
db.person.Add(person);
db.SaveChanges();
The problem is that, I don't want to load all the related data. So where the shoe table may be loaded, I don't want the laces table to load with info about laces.
The issue I'm running into is that there is an attempt to store a duplicate shoe table to the database even though this was only loaded to allow the user to view these details. I imagine that this is because, I'm using [JsonIgnore] attributes to ignore certain parts of the object - it is thus recognizing this as a new object, when it isn't.
I could loop through the object removing any shoe information before call Add, but this would be slow.
Perhaps it is best to post a second object that only includes the items that have changed (after tracking these in the front end). Is there a better way?
When you use DbSet<T>.Add() in EF, the entity (or all the entitis in the tree, if it's an entity with related child entities) is attached to the DbContext as Added. That means that when you call SaveChanges EF will try to insert all the objects in the database. That's why you're getting duplication problems.
You need to learn how to work in disconnected mode with EF. Basically you need to track the state of each entity (i.e. control if they have to be inserted, deleted or updated), and set the correct state when you attach the entities in the context.
Look for docs on working with disconnected entities in EF, for example:
Persistence in Entity Framework
Add, Attach and Entity States
These will explain you how to handle disconnected entities.
[EDITED]
I am looking for a way to implement Linq To Entities in a WPF (MVVM) application and make each View (or ViewModel) responsible to manage their underlying entities separately.
Here is an example of a simple structure and what I would like to achieve:
[Customers] (1..1) <----> (0..* ) [Orders] (0..* ) <-- [OrderLine] --> (1..* ) [Product]
First view displays the list of customers
loads all the customers but not their orders
allows to Create or Delete customers
Second view displays the detail of a customer and the list of its orders
allows to Update the properties of the customer
loads all the orders of a specific customer, but not the orderLines
allows to Create or Delete orders
there might be several views managing separately several customers.
Third view displays the detail of an order and the list of order lines
allows to Update the properties of the order
loads all the orderLines of a specific order, and all products related to these orderLines
allows to Create or Delete orderLines
there might be several views managing separately several orders.
Fourth view displays the detail of a product
allows to Update the properties of the product
the related product might already be loaded by the third view
there might be several views opened at the same time and managing separately their own products. I do not want to update all the products at once but only the related product of the view.
According to Microsoft's recommendation, there must be one DbContext instance per view instance (or viewModel instance) (https://msdn.microsoft.com/en-us/data/jj729737.aspx).
The above scheme is of course very simplified. In the real application we will have much more entities and views. Aditionaly their might be different flows in which the views are opened, making it difficult to know in advance which entities are already loaded from the database when a new view is opened.
Still, there is one principle: a view (or the corresponding ViewModel) should be responsible to update the set of entities that it displays, without asking the DbContext to update entities handled by another view.
QUESTIONS
The DbContext of the productView should be able to push changes on the related product to the database. However, it should not load the product from the database if it was already loaded previously (i.e. by the DbContext associated to the orderLinesView). The problem is that a DbContext, as I understand it, encapsulates a transaction which makes me think it can hardly be responsible of saving entities that it didn't load by itself proviously. How to address such issue?
It is pretty clear that I must have a DbContext instance per view instance so that SaveChanges() only process the data of the current view. What is unclear is weather I should have several classes that inherits DbContext or a single class representing the DbContext of the application.
Is it necessary to add a DbSet<> property on the DbContext for each entitity type we want to update? That seems like the DbContext will need to change all the time as the application grows with new entities. Additionaly, that means repetitive code in the viewModels to point out which DbSet<> should be loaded, etc.
Wouldn't it be more efficient to have a mechanism (1) that can receive a set of entities to update (no matter their type), and another mechanism (2) that allows to select a set of entities to pass to mechanism (1)? The second mechanism could be either manual (for flexible scenarios) or automatic (by looking all the entities listed in a ViewModel for example).
If I want to put the database access mechanism in a web service, how can I continue to manage their underlying entities of each view separately ? In such case, where and how the DbContexts should be instantiated?
I look forward to any advices you can give.
You could be implementing something like the Unit of Work and Repository Pattern
This way you can keep the changes performed to the database as part of a work (window in your case) separated from the others. If you use the same context for all this is going to be complicated.
EDIT: trying to answer some of your questions:
1) As long as the next view doesn't alter the entities from other views you can pass the DTOs to it for logic on them. However this could cause some concurrency issues if the data you based your login on has changed. There is no easy way on working around this without saving all the entities related in one go. You can try to create your own cache and use it instead of querying the DbContext in those scenarios, but again this could be a problem with multiple users.
2 and 3) Have a look at the Unit of Work and Repository patterns I mentioned above. This should make a nice wrapper to avoid duplicating code.
4) For web service you should create a DbContext per each request, otherwise you could end up again with concurrency problems. Having a cache here could improve performance too.
Most of the examples I've seen online shows object change tracking in a WinForms/WPF context. Or if it's on the web, connected objects are used, therefore, the changes made to each object can be tracked.
In my scenario, the objects are disconnected once they leave the data layer (Mapped into business objects in WCF, and mapped into DTO on the MVC application)
When the users make changes to the object on MVC (e.g., changing 1 field property), how do I send that change from the View, all the way down to the DB?
I would like to have an audit table, that saves the changes made to a particular object. What I would like to save is the before & after values of an object only for the properties that we modified
I can think of a few ways to do this
1) Implement an IsDirty flag for each property for all Models in the MVC layer(or in the javascript?). Propagate that information all the way back down to the service layer, and finally the data layer.
2) Having this change tracking mechanism within the service layer would be great, but how would I then keep track of the "original" values after the modified values have been passed back from MVC?
3) Database triggers? But I'm not sure how to get started. Is this even possible?
Are there any known object change tracking implementations out there for an n-tier mvc-wcf solution?
Example of the audit table:
Audit table
Id Object Property OldValue NewValue
--------------------------------------------------------------------------------------
1 Customer Name Bob Joe
2 Customer Age 21 22
Possible solutions to this problem will depend in large part on what changes you allow in the database while the user is editing the data.
In otherwords, once it "leaves" the database, is it locked exclusively for the user or can other users or processes update it in the meantime?
For example, if the user can get the data and sit on it for a couple of hours or days, but the database continues to allow updates to the data, then you really want to track the changes the user has made to the version currently in the database, not the changes that the user made to the data they are viewing.
The way that we handle this scenario is to start a transaction, read the entire existing object, and then use reflection to compare the old and new values, logging the changes into an audit log. This gets a little complex when dealing with nested records, but is well worth the time spent to implement.
If, on the other hand, no other users or processes are allowed to alter the data, then you have a couple of different options that vary in complexity, data storage, and impact to existing data structures.
For example, you could modify each property in each of your classes to record when it has changed and keep a running tally of these changes in the class (obviously a base class implementation helps substantially here).
However, depending on the point at which you capture the user's changes (every time they update the field in the form, for example), this could generate a substantial amount of non-useful log information because you probably only want to know what changed from the database perspective, not from the UI perspective.
You could also deep clone the object and pass that around the layers. Then, when it is time to determine what has changed, you can again use reflection. However, depending on the size of your business objects, this approach can impose a hefty performance penalty since a complete copy has to be moved over the wire and retained with the original record.
You could also implement the same approach as the "updates allowed while editing" approach. This, in my mind, is the cleanest solution because the original data doesn't have to travel with the edited data, there is no possibility of tampering with the original data and it supports numerous clients without having to support the change tracking in the UI level.
There are two parts to your question:
How to do it in MVC:
The usual way: you send the changes back to the server, a controller handles them, etc. etc..
The is nothing unusual in your use case that mandates a change in the way MVC usually works.
It is better for your use case scenario for the changes to be encoded as individual change operations, not as a modified object were you need to use reflection to find out what changes if any the user made.
How to do it on the database:
This is probably your intended question:
First of all stay away from ORM frameworks, life is too complex as it.
On the last step of the save operation you should have the following information:
The objects and fields that need to change and their new values.
You need to keep track of the following information:
What the last change to the object you intend to modify in the database.
This can be obtained from the Audit table and needs to be saved in a Session (or Session like object).
Then you need to do the following in a transaction:
Obtain the last change to the object(s) being modified from the database.
If the objects have changed abort, and inform the user of the collision.
If not obtain the current values of the fields being changed.
Save the new values.
Update the Audit table.
I would use a stored procedure for this to make the process less chatty, and for greater separations of concerns between the database code and the application code.
I'm using a single instance of DbContext scenario to shadow entire copy of the database locally in a WPF app. I've heard this is bad practice, but my database is small and I need an entire copy of it locally while the app is running.
An extension method for IQueryable, Load() lets me preload the elements of a DbSet<>, so that I can bind things to the Local property of DbSet<>. Data in the database changes rapidly, so I want to SaveChanges() and reload everything, even objects that are already tracked. Calling the Load() method again doesn't update the items that are tracked but are not marked as changed, which are already loaded.
What is the preferred method of reloading the preloaded items in a DbSet<>? Off the top of my head, I can only think of calling SaveChanges(), then go through all entries and set both tracked and original values to the current values in the database, then Load() whatever new objects that might have been added. In my scenario it's not possible to delete objects, but I might have to support item deletion in the long run. This doesn't seem right, there should be a way to drop everything and reload. It would seem that it's easier to drop my context and just start anew, but all the elements in WPF are already bound to the Local´ObservableCollection<>, and this just messes up the interface.
This is not the way you are supposed to use DbContext, and because of that it is almost impossible to reload the data. Keeping a single context around for a long time is incorrect usage. The link will also answer why your tracked entities are not updated.
You can selectively reload a single entity by calling Reload on DbEntityEntry:
context.Entry(entity).Reload();
You can also revert back to ObjectContext and use ObjectQuery with MergeOption.OverrideChanges, or use Refresh for a collection of entities with RefreshMode.StoreWins.
All these approaches suffers some problems:
If the record is deleted in the database, it will not be removed from the context.
Changes in relations are not always refreshed.
The only correct way to get fresh data is Dispose the context, create a new one and load everything from scratch - and you are doing this anyway.
With Entity Framework 4.1, the recommendation for WPF data binding has changed to use .Local and a persistent DbContext.
http://blogs.msdn.com/b/efdesign/archive/2010/09/08/data-binding-with-dbcontext.aspx
It's, of course, possible to dispose of it whenever you need to, but it can negatively impact the UI if you do.
Here's another method, but I'm not sure that it takes EF4.1's features into account:
http://msdn.microsoft.com/en-us/library/cc716735.aspx
DbContexts are supposed to live short time,
Consider after saving changes disposing it and reloading all from the start.
Have 2 sets of objects.. one from db and another for binding.
Please use using() for CRUD.It will automatically reload the updated data.
using (myDbContext context = new myDbContext())
{
}
Best Regards,
Thet Tin Oo