Supposing I had, by way of demonstration, a controller that looked like this:
public class ProjectController : Controller
{
private IProjectRepository projectRepository;
public ProjectController()
{
DBContext context = new DBContext();
this.projectRepository = new ProjectRepository(context);
}
public ActionResult Create(Project project)
{
if (ModelState.IsValid)
{
// do whatever
}
else
{
return View(project);
}
}
}
And suppose that this was the controller for a model that looked like this:
public class Project : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// this is where I would like to add code
}
}
My question is: is there really no way in the validation code to reference the projectRepository object on the controller? Yes, I could technically add quasi-validation to the Create() function on the controller, do the check there, and add errors directly - but in the real case, there are a number of actions that would all perform the same validation, which is really tied to the model you're trying to create (or edit, or copy, or whatever else). But it's tied to the model and to other existing instances of the same model, which only the controller knows how to query for. Is there any way to get around that?
(The goal is to check that the current model object under validation isn't the same as one that exists already; I'm open to other suggestions of how to do that as well, it just seemed like it clearly should be a job for standard validation code, either using IValidatableObject or using a ValidationAttribute. But I am not an expert in .net MVC validation, or for that matter, .net MVC at all.)
Thanks!
IValidatableObject belongs to the DataAnnotations namespace. To my mind, Data Annotations are great for input validation. Where they start to fall down is when you start applying complex business rules where your domain model's validity depends on the state of other domain models.
When that happens, introduce a service layer. Put all your business rules in there, and allow the service to mediate the conversation between your models. At the end of the day, a service is supposed to be the interface with which you communicate with your model.
This is where I usually say to myself, "Hey, your app has now reached the 'medium-complexity' stage"! :)
An older but still relevant tutorial can be found here: http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs
IMO, there is a bit of a convention issue at play. The model that the controller returns to the client is a ViewModel, not an entity. This comes into play when thinking about which objects have knowledge of dependent objects.
The repository deals with models (entities), and the controller deals with ViewModels. ViewModels are really just a bunch of data and formatting, so set-level validations don't make sense on a ViewModel.
And really want the business-layer or repository to perform set-level validation, not the model itself. You could set a reference to the repository on the model when it is created and have the model call the repository for set-level validation. But this becomes problematic when you want to clone or deserialize the entity.
By the way, EntityFramework solves these problems by allowing you to Attach a disconnected entity. You might want to use EF instead of the repository pattern.
But for you immediate issue, I would not try to perform set-level validation from within the entity or viewmodel.
You might be better of putting your validation in the service layer
The online scaffolding tool CamoteQ generate its model validation code this way, which is a good reference for self-study.
Related
The majority of MVC examples I see seem to use Entity Framework. I am currently writing an MVC application that will not use EF (using Dapper instead) and I'm wondering where I should include the data persistence logic?
My first thought was to place it in along with the classes for my model. This would mean that my model classes would look something like below:
class User
{
public int id {get; set;}
public string name {get; set;}
Create(string name)
{
// dapper to perform insert
}
Remove(int id)
{
// dapper to perform delete
}
//Update(),Delete() etc.
}
But I haven't used MVC much so I'm not sure if this is a common practice or not.
Is placing data persistence logic in with the Model a good practice or should I be taking a different approach?
Also, I believe that Stack Exchange uses MVC and Dapper - if anyone knows of anywhere that they have spoken about how they structured their code, feel free to point me towards it.
You wouldn't expect to have to open your computer and press a button on the harddrive to save data to it would you?
Basically the purpose of the MVC pattern, and SOLID design principles in general, is to separate your concerns. Putting logic related to saving, modifying or updating your database inside of your model, whose responsibility is to be an object that contains data, is counter to the philosophy of the pattern you're supposed to subscribe to in MVC.
Your controller is where you want to perform the logic to save your information, but there is still a data access layer that the concern of interacting with the database is abstracted to.
So you would have:
public class MyController {
IDataAccessLayer _dataAccessLayer;
public MyController(IDataAccessLayer dataAccessLayer) {
_dataAccessLayer = dataAccessLayer;
}
public ActionResult Create(Model myModel){
_dataAccessLayer.InsertIntoDatabase(myModel);
return View();
}
}
As per design of MVC persistence never be a problem. You can use any ORM you want. For MVC pattern to work you need Model ( partial ViewModel) to display your data in View. Controller will handle your flow of application.
Now from controller you can call any process to save your data.
I think you can use Repository pattern with Dapper as well same as EF.
Main thing to take care that your application should not be persistence aware. You can develop with Dapper and later you can also provide support for EF without much changing at your UI level.
I'm using ASP .NET MVC (C#) and EntityFramework (database first) for a project.
Let's say I'm on a "Movie detail" page which shows the detail of one movie of my database. I can click on each movie and edit each one.
Therefore, I have a Movie class, and a Database.Movie class generated with EF.
My index action looks like :
public ActionResult MovieDetail(int id)
{
Movie movie = Movie.GetInstance(id);
return View("MovieDetail", movie);
}
GetInstance method is supposed to return an instance of Movie class which looks like this for the moment :
public static Movie GetInstance(int dbId)
{
using (var db = new MoviesEntities())
{
Database.Movie dbObject = db.Movies.SingleOrDefault(r => r.Id == dbId);
if (dbObject != null)
{
Movie m = new Movie(dbObject.Id, dbObject.Name, dbObject.Description);
return m;
}
return null;
}
}
It works fine but is this a good way to implement it? Is there an other cleaner way to get my instance of Movie class ?
Thanks
is this a good way to implement it?
That's a very subjective question. It's valid, and there's nothing technically wrong with this implementation. For my small-size home projects, I've used similar things.
But for business applications, it's better to keep your entities unrelated to your MVC application. This means that your data context + EF + generated entities should be kept in a separate project (let's call it the 'Data' project), and the actual data is passed in the form of a DTO.
So if your entity resembles this:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
You'd expect there to be an equivalent DTO class that is able to pass that data:
public class PersonDTO {
public int Id { get; set; }
public string Name { get; set; }
}
This means that your 'Data' project only replies with DTO classes, not entities.
public static MovieDTO GetInstance(int dbId)
{
...
}
It makes the most sense that your DTOs are also in a separate project. The reason for all this abstraction is that when you have to change your datacontext (e.g. the application will start using a different data source), you only need to make sure that the new data project also communicates with the same DTOs. How it works internally, and which entities it uses, is only relevant inside the project. From the outside (e.g. from your MVC application), it doesn't matter how you get the data, only that you pass it in a form that your MVC projects already understand (the DTO classes).
All your MVC controller logic will not have to change, because the DTO objects haven't changed. This could save you hours. If you link the entity to your Controller AND View, you'll have to rewrite both if you suddenly decide to change the entity.
If you're worried about the amount of code you'll have to write for converting entities to DTOs and vice versa, you can look into tools like Automapper.
The main question: Is this needed?
That, again, is a very subjective question. It's relative to the scope of the project, but also the expected lifetime of the application. If it's supposed to be used for a long time, it might be worth it to keep everything interchangeable. If this is a small scale, short lifetime project, the added time to implement this might not be worth it.
I can't give you a definitive answer on this. Evaluate how well you want the application to adapt to changes, but also how likely it is that the applicaiton will change in the future.
Disclaimer: This is how we do it at the company where I work. This is not the only solution to this type of problem, but it's the one I'm familiar with. Personally, I don't like making abstractions unless there's a functional reason for it.
A few things:
The naming you're using is a little awkward and confusing. Generally, you don't ever want to have two classes in your project named the same, even if they're in different namespaces. There's nothing technically wrong with it, but it creates confusion. Which Movie do I need here? And if I'm dealing with a Movie instance, is it Movie or Database.Movie? If you stick to names like Movie and MovieDTO or Movie and MovieViewModel, the class names clearly indicate the purpose (lack of suffix indicates a database-backed entity).
Especially if you're coming from another MVC framework like Rails or Django, ASP.NET's particular flavor of MVC can be a little disorienting. Most other MVC frameworks have a true Model, a single class that functions as the container for all the business logic and also acts as a repository (which could be considered business logic, in a sense). ASP.NET MVC doesn't work that way. Your entities (classes that represent database tables) are and should be dumb. They're just a place for Entity Framework to stuff data it pulls from the database. Your Model (the M in MVC) is really more a combination of your view models and your service/DAL layer. Your Movie class (not to be confused with Database.Movie... see why that naming bit is important) on the other hand is trying to do triple duty, acting as the entity, view model and repository. That's simply too much. Your classes should do one thing and do it well.
Again, if you have a class that's going to act as a service or repository, it should be an actual service or repository, with everything those patterns imply. Even then, you should not instantiate your context in a method. The easiest correct way to handle it is to simply have your context be a class instance variable. Something like:
public class MovieRepository
{
private readonly MovieEntities context;
public MovieRepository()
{
this.context = new MovieEntities();
}
}
Even better, though is to use inversion of control and pass in the context:
public class MovieRepository
{
private readonly MovieEntities context;
public MovieRepository(MovieEntities context)
{
this.context = context;
}
}
Then, you can employ a dependency injection framework, like Ninject or Unity to satisfy the dependency for you (preferably with a request-scoped object) whenever you need an instance of MovieRepository. That's a bit high-level if you're just starting out, though, so it's understandable if you hold off on going the whole mile for now. However, you should still design your classes with this in mind. The point of inversion of control is to abstract dependencies (things like the context for a class that needs to pull entities from the database), so that you can switch out these dependencies if the need should arise (say perhaps if there comes a time when you're going to retrieve the entities from an Web API instead of through Entity Framework, or even if you just decide to switch to a different ORM, such as NHibernate). In your code's current iteration, you would have to touch every method (and make changes to your class in general, violating open-closed).
entity-model never should act as view-model. Offering data to the views is an essential role of the view-model. view-model can easily be recognized because it doesn’t have any other role or responsibility other than holding data and business rules that act solely upon that data. It thus has all the advantages of any other pure model such as unit-testability.
A good explanation of this can be found in Dino Esposito’s The Three Models of ASP.NET MVC Apps.
You can use AutoMapper
What is AutoMapper?
AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. This type of code is rather dreary and boring to write, so why not invent a tool to do it for us?
How do I get started?
Check out the getting started guide.
Where can I get it?
First, install NuGet. Then, install AutoMapper from the package manager console:
PM> Install-Package AutoMapper
I have just started working on an MVC project and things are going ok but it looks like I am creating alot of spaghetti code with just too many objects. Can anyone see how I can simplify this solution before the whole projects gets out of hand?
ok, here's my set up:
DAL - has Entity framework connections and methods to obtain data then convert the data to my model objects in the model layer
BLL - sends the data back up to the UI
Model - this contains all the model objects that are used throughout the site, anything coming from the DAL is converted into these objects by creating a new object then populating the variables.
UI - my MVC solution
The DAL,BLL and Model are also used by other solutions.
Now with MVC, I am trying to use the validation annotations ([Required], etc) which means I have to re-create the model objects with the annotations. This is fine but if I want to save the data back into the database I need to convert the classes which is just messy.
Can anyone see how I can use my current model class library with MVC model objects that use the validation annotations?
If I have not explained myself clearly please let me know and I will provide more details.
Thanks
Ideally there needs to be a separation from the domain models on one hand and MVC models (they are really ViewModels) on the other hand. This separation is really crucial and strongly advised.
These will look a lot similar in most cases although ViewModel can contain extra stuff. Then you can use AutoMapper to convert from one to the other.
For example:
public class User // in entity DLL
{
[Required]
public string Name {get; set;}
}
public class UserViewModel : User // in MVC DLL
{
public string LastVisitedPage {get; set;} // which only MVC needs to know
}
Mapper.Map<User, UserViewModel>();
Mapper.Map<UserViewModel, User>();
you can put the metadata in metadata objects without recreating the model objects. Here is a very simple way of doing it, however it does require that the model objects themselves are marked as partial. I hope that is OK if not this solution will not work for you.
[MetadataType(typeof(PreviousResultsMetaData))]
public partial class PreviousResults
{
public class PreviousResultsMetaData
{
[DisplayName("Class Ranking Score")]
[Required]
[Range(0.0, 100.0)]
public object ClassRankingScore { get; set; }
}
}
in the example above there is a data model object called PreviousResults that is created elsewhere by some scaffolding code. It defines the POCO object that is sent to and from database using LINQ. The MetadataType attribute indicates the class that will be used to hold the metadata. Then you simply create plain objects that match the names of your real data members and annotate them.
I hope this helps.
You can use FluentValidation framework for validation. Look here
http://fluentvalidation.codeplex.com/
You can perfectly add attributes to your BLL (the business entities). Just add a reference and add a using statement for System.ComponentModel.DataAnnotations. Apart from that, you can implement the IValidatableObject interface (which is pretty easy, see below).
For the mapping, you can use for example AutoMapper, so you don't have to write to much of mapping logic yourself (if you can take advantage of the name mapping magic).
Validate example:
ICollection<ValidationResult> validationErrors = new List<ValidationResult>();
var validationContext = new ValidationContext(this, null, null);
Validator.TryValidateObject(this, validationContext, ValidationErrors, true);
return validationErrors;
I have made this post over a year ago, and I think it makes sense to update it as it's getting quite a few views.
I'm either missing something out or Microsoft has really messed up MVC. I worked on Java MVC projects and they were clean and simple. This is however a complete mess IMO. Examples online such as NerdDinner and projects discussed on ASP.Net are too basic, hence why they "simply" work. Excuse if this sounds negative, but this is my experience so far.
I have a repository and a service that speaks to the repository. Controllers call service.
My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet.
*Update: Of course Microsoft hasn't messed anything up - I did. I didn't fully understand the tools that were at my disposal. The major flaw in what I have done, was that I have chosen a wrong technology for persisting my entities. LINQ to SQL works well in stateful applications as the data context can be easily tracked. However, this is not a case in stateless context. What would be the right choice? Entity Framework code first or code only work pretty well, but what's more importantly, is that it shouldn't matter. MVC, or front end applications must should not aware of how data is persisted. *
When creating entites I can use object binding:
[HttpPost]
public ActionResult Create(Customer c)
{
// Persistance logic and return view
}
This works great, MVC does some binding behind the scene and everything is "jolly good".
It wasn't "Jolly Good". Customer was a domain model, and what was worse, it was dependent on persistence medium, because it was generated by SQL metal. What I would do now, is design my domain model, which would be independent of data storage or presentation layers. I would then create view model from my domain model and use that instead.
As soon as I'd like to do some more complex, e.g. - save Order which is linked to the customer everything seems to break:
[HttpPost]
public ActionResult Create(Order o)
{
// Persistance logic and return view
}
To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId. I don't fancy sitting around debugging MVC code as I won't be able to change it in a hosting envrionment either way.
Ok, a bit of moaning here, sorry. What I would do now, is create a view model called NewOrder, or SaveOrder, or EditOrder depending on what I'm trying to achieve. This view model would contain all the properties that I'm interested in. Out-of-the-box auto binding, as the name implies, will bind submitted values and nothing will be lost. If I want custom behaviour, then I can implement my own "binding" and it will do the job.
Alternative is to use FormCollection:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
// Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.
}
This is used in books and tutorials, but I don't see a point in a method which has an alternative: TryUpdateModel - if this crashes or model is invalid, it attempts to update it either way. How can you be certain that this is going to work?
Autobinding with view models will work the most of the time. If it doesn't, then you can override it. How do you know it will always work? You unit test it and you sleep well.
Another approach that I have tried is using ViewModel - wrapper objects with validation rules. This sounds like a good idea, except that I don't want to add annotations to Entity classes. This approach is great for displaying the data, but what do you do when it comes to writing data?
[HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
// Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}
** View model is a good way forward. There would have to be some mapping code from view model to the domain model, which can then be passed to the relevant service. This is not a correct way, but it's one way of doing it. Auto mapping tools are you best friends and you should find the one that suits your requirements, otherwise you'll be writing tons of boilerplate code.**
Am I missing something out or is this the way Microsoft MVC3 should work? I don't see how this is simplifying things, especiialy in comparisson to Java MVC.
I'm sorry if this sounds negative, but this has been my experience so far. I appreciate the fact that the framework is constantly being improved, methods like UpdateModel get introduced, but where is the documentation? Maybe it's time to stop and think for a little bit? I prefer my code to be consistent throughout, but with what I have seen so far, I have no confidence whatsoever that this is a right way forward.
I love the framework. There is so much to learn and it's not a lot more exciting then it has ever been. Should probably make another post regarding web forms. I hope this is helpful.
1) For the case of saving an order, and not having CustomerId present. If Order has a CustomerId property on it, and you have a stongly typed view, then you can persist this back to your controller action by adding
#Html.HiddenFor(model => model.CustomerId)
Doing this will have the default model binder populate things for you.
2) With respect to using a view model, I would recommend that approach. If you utilize something like AutoMapper you can take some of the pain out of redundant mapping scenarios. If you use something like Fluent Validation then you can separate validation concerns nicely.
Here's a good link on a general ASP.NET MVC implementation approach.
I don't think your issue is with asp.net MVC but with all the pieces You Choose to use together.
You want it raw and simple?
Use POCOs all around, and implement the repository where you need it.
I haven't used Java MVC, but it'd make the whole question look less like a rant if you include how you solved the particular problem in there.
Let's clear some misconceptions or maybe miscommunication:
You can pass complex objects through a post to the view. But you only want to do so if it makes sense, see next bullet
The sample you picked there rings some alarms. Accepting Customer data or CustomerID for an order and not checking authorization can be a Big security hole. The same could be said for an Order depending on what you are accepting/allowing. This is a Huge case for the use of ViewModels, regardless of POCOs, LINQ, Asp.net MVC or Java MVC.
You can pass simple values not being showed through a post to the view. It's done with hidden fields (which asp.net MVC supports very simply to use the model value), and in some scenarios it generates the hidden fields for you.
You are in no way forced to use linq2sql with Asp.net MVC. If you find it lacking for how you intend to use it, move away from it. Note I love linq2sql, but how it is tied to your view of what you can do with asp.net mvc is weird.
" I worked on Java MVC projects and they were clean and simple". Working on a project is not the same as designing the project yourself. Design skills does affect what you get out of anything. Not saying is your case, but just wanted to point that out given the lack of specifics on what you're missing from Java MVC.
"My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet". You picked the wrong technology, linq2sql is Not meant to fit that requirement. It haven't been a problem in the projects I've used it, but everything is designed in such a way that way less tied to its specifics than you seem to be. That said, just move to something else. btw, You should have shared what you used with Java MVC.
"CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId." If the property is in Order, You can bet your code has the bug. Now, that'd have been a totally different Real question, why it isn't using the CustomerId / such question would come with: your Customer class, the View, what you are passing to the View ... answers would include, but not be limited to: inspect the HTML source in the browser to see what value you are really posting with the source (alternatively use fiddler to see the same), make sure that CustomerId really has the value when you pass it to the View.
You said: ""magic" UpdateModel method which sometimes works and sometimes doesn't". It's not magic, you can see what it does and certainly find information on it. Something is off in the information you are posting, my bet is non optional fields or wrong values for information that's parsed ... views support adding validations for that. Without the validations, this can be lacking.
You said in a comment: "After UpdateModel is called, i can't explicitly set the CustomerId, I'll have to retrieve a customer object and then assign it to the order, which seems like an overhead as all that I need is CustomerId" ... you are accepting a CustomerId that is user input (even if it is a hidden field), you really want to Validate that input. Additionally you are contradicting yourself, you claim to just need CustomerId, but then you say you need the full Customer Object related to the order bound. Which is it, if you are only binding the CustomerId, you still need to go get that Customer and assign it to the property. There is no magic besides the scenes ...
Also in a comment: "Update model is something I'm avoiding completely now as I don't know how it will behave with LINQ entities. In the view model class I have created constructor that converts LINQ entity to my view model. This decreased amount of code in controller, but still doesn't feel right". Reason to use ViewModel (or EditModel) is not because it is linq2sql ... it is because, among many other reasons, you are exposing a model that allows to manipulate way beyond what you actually want to allow the user to modify. Exposing the raw model, if it has fields the user shouldn't be allowed to modify, is the real issue.
If your view is correctly defined then you can easily do this >
[HttpPost]
public ActionResult Create(Order o, int CustomerId)
{
//you got the id, life back to jolly good (hopefully)
// Persistance logic and return view
}
EDIT:
as attadieni mentioned, by correct view I meant you have something like this inside the form tag >
#Html.HiddenFor(model => model.CustomerId)
ASP.NET MVC will automatically bind to the respective parameters.
I must be missing the problem.
You have a controller Order with an Action of Create just like you said:
public class OrderController()
{
[HttpGet]
public ViewResult Create()
{
var vm = new OrderCreateViewModel {
Customers = _customersService.All(),
//An option, not the only solution; for simplicities sake
CustomerId = *some value which you might already know*;
//If you know it set it, if you don't use another scheme.
}
return View(vm);
}
[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
// Persistance logic and return view
}
}
The Create action posts back a view model of type OrderCreateViewModel that looks like such.
public class OrderCreateViewModel
{
// a whole bunch of order properties....
public Cart OrderItems { get; set; }
public int CustomerId { get; set; }
// Different options
public List<Customer> Customers { get; set; } // An option
public string CustomerName { get; set; } // An option to use as a client side search
}
Your view has a dropdown list of customers which you could add as a property to the viewmodel or a textbox which you wire up to to searching on the server side via JQuery where you could set a hidden field of CustomerId when a match is made, however you decide to do it. And if you already know the customerId ahead of time (which some of the other posts seems to imply) then just set it in the viewmodel and bypass all the above.
You have all of your order data. You have the customer Id of the customer attached to this order. You're good to go.
"To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId."
What? Why? If CustomerId was in the view, set, and posted back, it's in the model for the HttpPost Create method which is exactly where you need it. What do you mean it's being lost?
The ViewModel gets mapped to a Model object of type order. As suggested, using AutoMapper is helpful...
[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// Persistance logic and return view
var orderToCreate = new Order();
//Build an AutoMapper map
Mapper.CreateMap<OrderCreateViewModel, Order>();
//Map View Model to object(s)
Mapper.Map(model, orderToCreate);
//Other specialized mapping and logic
_orderService.Create(orderToCreate);
//Handle outcome. return view, spit out error, etc.
}
It's not a necessity, you can map it manually, but it just makes things easier.
And you're set. If you don't want to use data annotations for validation, fine, do it in the service layer, use the fluent validation library mentioned, whatever you choose. Once you call the Create() method of your service layer with all the data, you're good to go.
Where's the disconnect? What are we missing?
ataddeini's answer is correct, I'm just trying to show a bit more code. Upvote ataddeini
If the Customer Id is already in the Order model (in this example) it should be available without extending the method signature. If you view the source on the rendered view, is the customer id correctly emitted in a hidden field within the form? Are you using the [Bind] attribute on the Order model class and inadvertently preventing the Customer Id from being populated?
I would think the Order table would include a CustomerID field, if so, the only problem is maybe you are not including any control in the view to keep that value, then is lost.
Try to follow this example.
1) GET action before sending to the View, let's say you assign the CustomerID at this point.
public ActionResult Create()
{
var o = new Order();
o.CustomerID = User.Identity.Name; // or any other wher you store the customerID
return View(o);
}
2) The View, if you don't use any control for the CustomerID, like textbox, combobox, etc, you must use a hidden field to keep the value.
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.CustomerID)
<label>Requested Date:</label>
#Html.TextBoxFor(m => m.DateRequested)
...
}
3) Finally, the POST action to get and persist the order. In here, as CustomerID was kept in the hidden value, the Model Binder will automatically put all the Form values into the Order object o, then you just need to use CRUD methods and persist it.
[HttpPost]
public ActionResult Create(Order o)
{
return View();
}
Can be two approaches for this, one to implicit save all Model values even if not used in the View, and the other is to keep only those values used. I think MVC is doing the right thing to follow the later, avoid unnecessary keep a lot of junk for bigger models, when the only think is, to name one, a CustomerName, somehow it can give you control on what data to keep through the whole cycle action-view-action and save memory.
For more complex scenarios, where not all fields are in the same model, you need to use ViewModels. For example for mater-detail scenarios you would create a OrderViewModel that has two properties: Order o, and IEnumerable< OrderDetail > od, but again, you will need explicit use the values in the View, or use hidden fields.
In recent releases now you can use POCO classes and Code-First that makes all cleaner and easier, You may want to try EF4 + CTP5.
if you are using services (aka; service layer, business facade), to process lets say the OrderModel, you can extract an Interface, and get your ViewModel/DTO to implement it, so that you can pass back the ViewModel/DTO to the service.
If you are using Repositories to directly manage the data (without a servie layer) in the controller, then you can do it the good old way of Loading the object from a repository and then doing an UpdateModel on it.
[HttpPost]
public ActionResult Create(string customerCode, int customerId, Order order)
{
var cust = _customerRepository.Get(customerId);
cust.AddOrder(order);//this should carry the customerId to the order.CustomerId
}
Also, URLs might help a bit where it makes sense, I mean you can add the customer identifier in the url to create the order for.
UpdateModel should work, if your FormCollection has values for non-nullable properties and they are empty/null in the FormCollection, then UpdateModel should fail.
Is it possible to expose the DataContext when extending a class in the DataContext? Consider this:
public partial class SomeClass {
public object SomeExtraProperty {
this.DataContext.ExecuteQuery<T>("{SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE}");
}
}
How can I go about doing this? I have a sloppy version working now, where I pass the DataContext to the view model and from there I pass it to the method I have setup in the partial class. I'd like to avoid the whole DataContext passing around and just have a property that I can reference.
UPDATE FOR #Aaronaught
So, how would I go about writing the code? I know that's a vague question, but from what I've seen online so far, all the tutorials feel like they assume I know where to place the code and how use it, etc.
Say I have a very simple application structured as (in folders):
Controllers
Models
Views
Where do the repository files go? In the Models folder or can I create a "Repositories" folder just for them?
Past that how is the repository aware of the DataContext? Do I have to create a new instance of it in each method of the repository (if so that seems in-efficient... and wouldn't that cause problems with pulling an object out of one instance and using it in a controller that's using a different instance...)?
For example I currently have this setup:
public class BaseController : Controller {
protected DataContext dc = new DataContext();
}
public class XController : BaseController {
// stuff
}
This way I have a "global" DataContext available to all controllers who inherit from BaseController. It is my understanding that that is efficient (I could be wrong...).
In my Models folder I have a "Collections" folder, which really serve as the ViewModels:
public class BaseCollection {
// Common properties for the Master page
}
public class XCollection : BaseCollection {
// X View specific properties
}
So, taking all of this where and how would the repository plug-in? Would it be something like this (using the real objects of my app):
public interface IJobRepository {
public Job GetById(int JobId);
}
public class JobRepository : IJobRepository {
public Job GetById(int JobId) {
using (DataContext dc = new DataContext()) {
return dc.Jobs.Single(j => (j.JobId == JobId));
};
}
}
Also, what's the point of the interface? Is it so other services can hook up to my app? What if I don't plan on having any such capabilities?
Moving on, would it be better to have an abstraction object that collects all the information for the real object? For example an IJob object which would have all of the properties of the Job + the additional properties I may want to add such as the Name? So would the repository change to:
public interface IJobRepository {
public IJob GetById(int JobId);
}
public class JobRepository : IJobRepository {
public IJob GetById(int JobId) {
using (DataContext dc = new DataContext()) {
return dc.Jobs.Single(j => new IJob {
Name = dc.SP(JobId) // of course, the project here is wrong,
// but you get the point...
});
};
}
}
My head is so confused now. I would love to see a tutorial from start to finish, i.e., "File -> New -> Do this -> Do that".
Anyway, #Aaronaught, sorry for slamming such a huge question at you, but you obviously have substantially more knowledge at this than I do, so I want to pick your brain as much as I can.
Honestly, this isn't the kind of scenario that Linq to SQL is designed for. Linq to SQL is essentially a thin veneer over the database; your entity model is supposed to closely mirror your data model, and oftentimes your Linq to SQL "entity model" simply isn't appropriate to use as your domain model (which is the "model" in MVC).
Your controller should be making use of a repository or service of some kind. It should be that object's responsibility to load the specific entities along with any additional data that's necessary for the view model. If you don't have a repository/service, you can embed this logic directly into the controller, but if you do this a lot then you're going to end up with a brittle design that's difficult to maintain - better to start with a good design from the get-go.
Do not try to design your entity classes to reference the DataContext. That's exactly the kind of situation that ORMs such as Linq to SQL attempt to avoid. If your entities are actually aware of the DataContext then they're violating the encapsulation provided by Linq to SQL and leaking the implementation to public callers.
You need to have one class responsible for assembling the view models, and that class should either be aware of the DataContext itself, or various other classes that reference the DataContext. Normally the class in question is, as stated above, a domain repository of some kind that abstracts away all the database access.
P.S. Some people will insist that a repository should exclusively deal with domain objects and not presentation (view) objects, and refer to the latter as services or builders; call it what you like, the principle is essentially the same, a class that wraps your data-access classes and is responsible for loading one specific type of object (view model).
Let's say you're building an auto trading site and need to display information about the domain model (the actual car/listing) as well as some related-but-not-linked information that has to be obtained separately (let's say the price range for that particular model). So you'd have a view model like this:
public class CarViewModel
{
public Car Car { get; set; }
public decimal LowestModelPrice { get; set; }
public decimal HighestModelPrice { get; set; }
}
Your view model builder could be as simple as this:
public class CarViewModelService
{
private readonly CarRepository carRepository;
private readonly PriceService priceService;
public CarViewModelService(CarRepository cr, PriceService ps) { ... }
public CarViewModel GetCarData(int carID)
{
var car = carRepository.GetCar(carID);
decimal lowestPrice = priceService.GetLowestPrice(car.ModelNumber);
decimal highestPrice = priceService.GetHighestPrice(car.ModelNumber);
return new CarViewModel { Car = car, LowestPrice = lowestPrice,
HighestPrice = highestPrice };
}
}
That's it. CarRepository is a repository that wraps your DataContext and loads/saves Cars, and PriceService essentially wraps a bunch of stored procedures set up in the same DataContext.
It may seem like a lot of effort to create all these classes, but once you get into the swing of it, it's really not that time-consuming, and you'll ultimately find it way easier to maintain.
Update: Answers to New Questions
Where do the repository files go? In the Models folder or can I create a "Repositories" folder just for them?
Repositories are part of your model if they are responsible for persisting model classes. If they deal with view models (AKA they are "services" or "view model builders") then they are part of your presentation logic; technically they are somewhere between the Controller and Model, which is why in my MVC apps I normally have both a Model namespace (containing actual domain classes) and a ViewModel namespace (containing presentation classes).
how is the repository aware of the DataContext?
In most instances you're going to want to pass it in through the constructor. This allows you to share the same DataContext instance across multiple repositories, which becomes important when you need to write back a View Model that comprises multiple domain objects.
Also, if you later decide to start using a Dependency Injection (DI) Framework then it can handle all of the dependency resolution automatically (by binding the DataContext as HTTP-request-scoped). Normally your controllers shouldn't be creating DataContext instances, they should actually be injected (again, through the constructor) with the pre-existing individual repositories, but this can get a little complicated without a DI framework in place, so if you don't have one, it's OK (not great) to have your controllers actually go and create these objects.
In my Models folder I have a "Collections" folder, which really serve as the ViewModels
This is wrong. Your View Model is not your Model. View Models belong to the View, which is separate from your Domain Model (which is what the "M" or "Model" refers to). As mentioned above, I would suggest actually creating a ViewModel namespace to avoid bloating the Views namespace.
So, taking all of this where and how would the repository plug-in?
See a few paragraphs above - the repository should be injected with the DataContext and the controller should be injected with the repository. If you're not using a DI framework, you can get away with having your controller create the DataContext and repositories, but try not to cement the latter design too much, you'll want to clean it up later.
Also, what's the point of the interface?
Primarily it's so that you can change your persistence model if need be. Perhaps you decide that Linq to SQL is too data-oriented and you want to switch to something more flexible like Entity Framework or NHibernate. Perhaps you need to implement support for Oracle, mysql, or some other non-Microsoft database. Or, perhaps you fully intend to continue using Linq to SQL, but want to be able to write unit tests for your controllers; the only way to do that is to inject mock/fake repositories into the controllers, and for that to work, they need to be abstract types.
Moving on, would it be better to have an abstraction object that collects all the information for the real object? For example an IJob object which would have all of the properties of the Job + the additional properties I may want to add such as the Name?
This is more or less what I recommended in the first place, although you've done it with a projection which is going to be harder to debug. Better to just call the SP on a separate line of code and combine the results afterward.
Also, you can't use an interface type for your Domain or View Model. Not only is it the wrong metaphor (models represent the immutable laws of your application, they are not supposed to change unless the real-world requirements change), but it's actually not possible; interfaces can't be databound because there's nothing to instantiate when posting.
So yeah, you've sort of got the right idea here, except (a) instead of an IJob it should be your JobViewModel, (b) instead of an IJobRepository it should be a JobViewModelService, and (c) instead of directly instantiating the DataContext it should accept one through the constructor.
Keep in mind that the purpose of all of this is to keep a clean, maintainable design. If you have a 24-hour deadline to meet then you can still get it to work by just shoving all of this logic directly into the controller. Just don't leave it that way for long, otherwise your controllers will (d)evolve into God-Object abominations.
Replace {SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE} with a stored procedure then have Linq to SQL import that function.
You can then call the function directly from the data context, get the results and pass it to the view model.
I would avoid making a property that calls the data context. You should just get the value from a service or repository layer whenever you need it instead of embedding it into one of the objects created by Linq to SQL.