Suppose we have class PersonModel, user edits a detail form in the browser and hits the submit button.
How to write a controller logic to create an UPDATE SqlComand (no EF) and update only those of fields from class PersonModel (FirstName, LastName, Age...) which have been changed.
What should be an argument of the /Person/Edit/<id> controller?
You don't do anything special to your MVC code, and you don't add any special URL parameters.
If you only want to update the changed fields, then you have to write a lot of code. You have to get the current record, compare each of your models fields to the records fields, figure out which ones have changed, then you have to construct a SQL statement based on the changed fields, then update it, making sure to use optomistic record locking to insure the field has not changed between when you retrieved it and when you update it.
This is probably going to be a couple hundred lines of code. Or it could be one line of code if you were using an ORM.
Also, keep in mind you need to use parameterized statements as well, to insure against a SQL injection attack (something you get for free in an ORM as well).
Good luck, I certainly am not going to write it.
What I would suggest is that you don't use the generalized PersonModel which I assume is a 1:1 representation of your data model. You should create a watered down view model of with only the fields you care about. Then use something like AutoMapper to map the ViewModel back to your DomainModel.
Here is a reference on how to use AutoMapper for such a scenario.
How to cross map objects using AutoMapper
You may use Linq and let the datacontext do everything for you.
In the Model you just create your data class with the linq queries for the update, retrieve the object, set all the values that have been passed from the view in the object you've retrieved (you'll have to do this anyway, since the pattern decouples the view from the model | Remember too, that MVC implements observer for letting the view to know about changes in the model, so you can't know what was modified in the view from the controller), and then you call the DataContext.SubmitChanges(); method. The data context will do the job in its own. It will know what to change and modify and will make the most performant query.
Related
Excuse me for my broken English.
In my application, all objects in the context have a property called ObsoleteFlag, which basically means if the object should still be used on the frontend. It's some sort of "soft-delete" flag without actually having to delete the data.
Now I want to prevent EF from returning any object where ObsoleteFlag is set to true (1)
If for example I retrieve object X, the navigational list property Y contains all the related objects of type Y, no matter what the ObsoleteFlag is set to.
Is there some general way of preventing EF from doing this? I don't want to check on the ObsoleteFlag property everywhere I access the context, and for every navigational property that may be loaded too.
Thanks and sorry for my broken English.
Two different approaches:
In your repository layer have a GetAllWhatever() that returns IQueryable<Whatever> and uses Where(x => !x.Obsolete) and use this whenever you retrieve objects of this type.
Create a view of Create View ActiveWhatever As Select * from ActiveWhatever Where obsolete = 0 and bind to that rather than the table.
The first is essentially checking the flag every time, but doing so in one place, so you don't have to keep thinking about it.
The second is much the same, but the work is pushed to the database instead of the .NET code. If you are going to modify the entities or add new entities you will have to make it a modifiable view, but just how that is done depends on the database in question (e.g. you can do it with triggers in SQL Server, and triggers or rules in PostgreSQL).
The second can also include having a rule or trigger for DELETE that sets your obsolete property instead of deleting, so that a normal delete as far as Entity Framework is concerned becomes one of your soft-deletes as far as the database is concerned.
I'd go for that approach unless you had a reason to object to a view existing just to help the application's implementation (that is you're heavily into the database being "pure" in being concerned with the data rather than its use). But then, if it's handy for one application it's likely handy for more, given the very meaning of this "obsolete".
I have an EDM used to bring back a collection of "Product" entities within a DAL project. An MVC website project references and directly instantiates the ObjectContext and returns an IQueryable to the website for paging and displaying of Products.
This Entity, to simplify things, we'll say only has "ID", "Rate" and "Description" properties. I want to create another calculated property called "CostPerMonth" which will take an input from the website called "LoanAmount", and, again, to keep things simple, this "CostPerMonth" property will be made up of (("LoanAmount" * "Rate") / 12).
I can't help but feel this calculation should be done in the DAL project to make the code more reusable, as whereever this data is used, a "LoanAmount" will always be specified. The possible solutions I have had are below:
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the website controller, when the data is returned, populate this new column by iterating through the returned data and doing the calculations?
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the DAL project, create a helper class that has a method that accepts a "LoanAmount" parameter and returns a List. The trouble with this is I would need to materialize the data in order to do the calculations. The method could accept a "Skip" and "Take" parameter that could be used in the Linq query used to return the products?
Create a partial class for Product, add a new property "CostPerMonth" to Product. Add another tier to the solution using WCF web services, within the service method do the calculations and use REST to return the data to the MVC web site?
Any advice would be very much appreciated.
Best regards,
Mark
If we take a step back and actually breakdown what you are asking in your question it might be easier to explain my answer.
We have an object/entity named Products
There is a calculated field which will be (("LoanAmount" * "Rate") / 12)
CostPerMonth does not need to be stored in the database
So this calculated field is a business rule for the Product Entity. Given that you are using MVC, there is only one place where this code/logic can go and that is the model.
Given that your using EF It will sit in a non mapped/computed field and the code to give you an idea will look something like this....
[NotMapped]
public decimal CostPerMonth
{
get { return (LoanAmount * Rate)/12 ; }
}
I can go on for days about the problems about having fragmented business logic throughout various layers.
Now if you want your this logic to be consumed easily by other clients, you need to expose a service to do that. (you can use webAPI/service stack/ wcf, etc) it is really another entire question based on your needs. But the point here is that your logic is in one spot.
I've recently started creating a WPF application, and am just hoping that someone can confirm to me that I'm building my overall system architecture properly, or correct me if I'm heading off in the wrong direction somewhere. Especially since I'm trying to do MVVM, there are a lot of layers involved, and I'm not sure I'm doing things properly.
Here's a simplified description of the system:
Data is stored in an SQL Server database, which is accessed through Linq to SQL. Let's say that the database contains two tables, USERS and USER_GROUPS. Each table has an auto-generated Linq to SQL class, DB_USER and DB_USER_GROUP.
Now in the application, I want to display a ListBox with each ListBoxItem containing various UI elements for displaying/modifying the users' info, which is done using a DataTemplate.
I have a view model class for the window, which uses a Linq to SQL query (joining the two tables) to populate an ObservableCollection<User> named UserList, which the ListBox in the window has bound as its ItemsSource. User is a class implementing INotifyPropertyChanged that handles all the formatting/getting/setting of database data into what's needed by the WPF controls. The section of code handling this is something like:
DBDataContext db = new DBDataContext();
var allUsers = from user in db.USERs
.Where(u => u.ENABLED == true)
from group in db.USER_GROUPs
.Where(g => g.GROUPID == u.GROUPID)
.DefaultIfEmpty()
select new { user, group };
foreach (var user in allUsers)
{
User u = new User(db, user.user, user.group);
UserList.Add(u);
}
So the User class is constructed with private properties for a DB_USER, a DB_USER_GROUP, and the database DataContext class. All of a User's public properties basically wrap the relevant columns, with their get methods returning the values for WPF to use, and set changing the column(s) and then calling SubmitChanges() on the private DataContext property to update the database.
This is all working fine, but it feels a little unwieldy, so I'm just wondering if I've missed something that would make it cleaner. Specifically, storing a DataContext inside each element of UserList seems odd, but I wasn't sure of a better method to be able to update the database whenever data was changed in the UI.
Any feedback is appreciated, and please let me know if anything's unclear, I'm not sure how well I've explained it.
Starting off, let's put some labels on what you are doing here: DB_USER is your Model and User is your ViewModel (I 'd have preferred UserViewModel for the latter just so that it's more clear what's going on).
One thing that's immediately obvious is that it's not really proper for your ViewModel to have functionality suited to your Model, i.e. that DataContext does not belong where it currently is. This is a piece of information that should either be in your Model, or alternatively encapsulated in some DataStore/DataService (take your pick) class. Your ViewModel would then be responsible, when the time comes to save any changes, to tell the DataStore "here's an updated snapshot of this model, please save it for me" (this would most likely be exposed to the UI through an ICommand). This feels cleaner and underscores the idea that your ViewModel is a layer that adapts the realities of your model to your choice of UI.
Other than the above, there's nothing in what you describe that I feel needs to be "corrected". However, I can offer some suggestions regarding things that you have not elaborated on.
Exposing data from a Model through a ViewModel is always something that can be implemented in many ways. When considering what approach to take, you should take into account the possibility of the same Model being exposed through different Views at the same time. In this case, IMHO the preferred approach is to have a separate ViewModel for each View (the Views may well be of different types, so they could have different expectations from the ViewModel adapter thus pointing to multiple types of ViewModels as well), so you would need to use a pattern that allows changes to be communicated from one ViewModel to any others in "real time".
One way to do this would be to make your Models implement INotifyPropertyChanged themselves and have each ViewModel hook into its Model for notifications, so when a change occurs ViewModel A pushes the change to the Model, and the Model notifies ViewModel B.
However personally I don't like polluting my Models with what is in essence code that only caters to the needs of the UI, so another approach is needed. That would be making the DataService I mentioned above expose functionality (methods and events) through which ViewModel A can tell the service "hey, the Model I 'm wrapping has had some changes" ; note that this is different from "I want you to persist the current snapshot of this Model". ViewModel B has already hooked into a suitable "ModelChanged" event, so it gets notified and pulls the updated information from the service. This has the added benefit that if at any time the service detects that the backing data repository has been updated by a source external to the current process, there's a ready made mechanism to broadcast a "Calling all ViewModels: Model X has been updated, any interested parties please talk to me about learning the details" message.
Above all, always keep in mind that there is no "one true MVVM style" and there are myriads of possible approaches. Which one to take depends not only on hard facts and the current position of the slider on the YAGNI/HyperEngineering scale, but also on, dare I say, your taste.
Tricky question, and I can see why people aren't jumping all over themselves to answer—mainly because you aren't doing anything technically wrong. But since you ask, I'll tell you what I'd change to tighten up both MVVM (which you asked for) and the data acess (which you didn't).
The way I approach a ViewModel is as a wrapper for my underlying data model, rather than as an enhancement to my View. It assists the view by providing INotifyPropertyChanged and all that, but I try to make the ViewModel useful for whatever view it'll end up inside. That's the main difference, IMO, between MVC and MVVM. What you have is more of an MVC with your User object acting as a controller for the View.
Also, I'd probably do away with UserList and use the ListBox.ItemsSource to manage the list after binding it once. Actually, in WPF, I've gotten more used to having a CollectionViewSource and binding the UI controls to that. Makes it simpler to track selected items and adding to them and removing from them isn't too onerous.
For the data access, I wouldn't feed those into the object at all. Data access belongs in your model and persisting changes should be handled there. The .Net framework does a pretty good job with connection management, to the point where re-instantiation and teardown are the next best thing to costless. That allows you to keep things tight and wrap data connections in using clauses. If you really feel like you have to persist to the database on every property change, have your model subscribe to the PropertyChanged event—that's what it's there for, after all. :)
Usually, I keep my models as dumb as possible (POCO). My viewmodel has the heavy logic of querying the database and setting its properties that are bound to the UI. In that layout, the viewmodel has a single instance of your DataContext and there is no need for it to be passed around inside of the models.
I generally follow that approach with some differences, big surprise there :) In larger projects I don't like to wrap or include my domain entities in my ViewModels. This is something I carried over from the ASP.NET MVC in Action books where you map (AutoMapper) domain entities to display models before the view receives them. Its nice when there is an impedance between the domain entity(s) and what needs to be displayed.
It also comes in handy when mocking up the screens, I can work from the screen backwards to the DisplayModel knowing I'll map what I need from the domain entity. I'm big on my Views being blendable so a designer can open the View up and it looks pretty close to run time View.
So in some cases I'll have my entity models (User/UserGroup), my DisplayModel (User), and my ViewModel (UserViewModel).
As mentioned in other answers I tend to keep the data business out of the ViewModel. I'll create a Repositiory or a service of some type and inject it into my ViewModels. So in my ViewModel I might call var user = UserRepository.GetUsers(); and then map the results to my DisplayModel. Or UerRepository.InsertOrUpdate(user); UserRepository.Save();
Unrelated, AutoMapper is a great tool as well as Caliburn Micro or MVVM-Light.
I am building a ASP.NET MVC application where I use the following flow :
Get Entity
Run Action at a controller
Fetch data from FactoryClass that operates against the Model(Entity Framework)
Get data back to the Action in the controller
Use AutoMapper to translate from Model object to ModelView object
Return the ModelView object to the strongly typed View
Update Entity
Run Action with ModelView Entity as input (DefaultDataBinder will be used)
Validate ModelView Entity
Send the ModelView object direcly to the right factory method.
Check if the ModelView object has id and if so fetch the Model object from database
Use AutoMapper to translate the incoming ModelView object to a Model object/entity. If its a update, then use the fetched Model object as destination.
If it is a update use Refresh Client.Wins else use Add
Run SaveChanges and return to the controler.
Problem 1
The ModelView classes is special made for the views that the controler actions is connected to (it could contain both edeting objects and lists). It´s common that several actions with diffrent views uses the same ModelView Class, that means that not all objects in the ModelView object will be used in every action/view.
As long as the View uses all the properties of ModelViewObjects that can be updated there is no problem but...
Say that we got a View where some of the properties of the ModelViewObject is not used, this ModelViewObject is sent to the factory(to be updated) where the corsponding ModelObject is fetched(from db/entity framework) and then merged with the ModelViewObject with AutoMapper. The problem here is that properties on the ModelViewObject that is not set(not used in the view) will result in a overwrite of real data in the ModelObject.
To solve this u usually use AutoMapper ForMember Ignor(), but this will be a problem when a complete ModelViewObject(all properties set) will update db.
How do you handle this? Do you have diffrent Update methods in the factorys where diffrent AutoMapper setting?
It would be nice If I could only have a method like this : UpdateMyEnityt(MyEntity entity) and this methid will update och add MyEntity object.
Problem 2
Where should I place the AutoMapper mappings? So far I have placed Updates in the factory and Get in the controller. I have thought of placeing the mappings in the ModelViewObject for example ModelViewObject.ToDataModel but if I do not need a complete translate(som properties is to be ignored) then I will have to do this AutoMapper else where.
How do you handle this?
Problem 3
Say that you have an working update method in our factory class where you use AutoMapper with som ignors to translate a ModelViewObject to a ModelView(entity framework object). Say now that we updates the database table with a new field/propertie, if we run a view that handles the ModelViewObject corsponding to this tabel but do not handle the new propertie this will mean that the propertie will always be set to null/string.empty/0. When running the regular update method in the factory there will not be a ignor on this propertie and this means that the zero value will overrite the real value.
Its a big risk that these kind of updates will be done and its a big risk that I will not remember to handle this in old code.
How do I handle this?
Problem 4
AutoMapper have a validation method where you can check if the mappings will be possible, right now I am having these validations where the mapping is done, should I maby put this in some other method where the validation will be executed as fast as the application starts? Else problems in the mappings will show first when using the function.
BestRegards
At first you should use viewModel for each view. And fetch only date that you need.
You should add facility to manual mapping for "difficult" issue.
I thing that AutoMapper is wrong way for transfer date from Db object to View Object.
Problem 1: If you are using a different View, use a different ViewModel. This way only the properties that are displayed will be automapped.
Problem 2: Different Automapper Settings in each project with
Project1.AutomapperSettings.Execute();
Project2.AutomapperSettings.Execute();
etc
in the Global.asax or similar entry point.
Problem 3: See problem 1
Problem 4: Use ValidationAttribute on viewmodel properties and let mvc take care of it
What is the best way to mark some entities DeleteOnSubmit(). Is there a way to check and say to the context that this is for deletion?
Example: I have an Entity which reference an EntitySet<> and i delete from the EntitySet<> 4 of the 8 entities. When submitting changes i want to say DeleteOnSubmit() on those 4! This scenario should play on a single EntityRef<> too.
Of course DataContext lives in another layer so...grabbing, changing, sending back is the job.
Thank you.
This is pretty hard to answer based on the description of your architecture. Just because you're using a layered approach doesn't mean that you can't call DeleteOnSubmit... you'd just call your own method that wraps that I presume.
Unless, of course, you're instantiating your DataContext object in the update routine. in this case you'd have to do something else. Your data layer could expose a method like MarkForDelete() which just adds the entity to a collection, then expose a separate SubmitChanges() that iterates over the collected items for deletion, attaches them to the datacontext and then does the actual DeleteAllOnSubmit() call.
That said I've never really bothered with the whole entity serialization/deserialization/reattach thing as it seems fraught with peril. I usually just collect the primary keys in a list, select out the entities and re-delete them. It's no more work, really.
Take a look at DeleteAllOnSubmit(). You pass this method a list of entities to be deleted.