Questions about Entity Framework Context Lifetime - c#

I have some questions about the desired lifetime of an Entity Framework context in an ASP.NET MVC application. Isn't it best to keep the context alive for the shortest time possible?
Consider the following controller action:
public ActionResult Index()
{
IEnumerable<MyTable> model;
using (var context = new MyEntities())
{
model = context.MyTable;
}
return View(model);
}
The code above won't work because the Entity Framework context has gone out of scope while the view renders the page. How would others structure the code above?

Let's get controversial!
I disagree with the general MVC + EF consensus that keeping a context alive throughout the entire request is a good thing for a number of reasons:
Low performance increase
Do you know how expensive creating a new database context is? Well... "A DataContext is lightweight and is not expensive to create" that's from MSDN
Get the IoC wrong and it'll seem fine.. until you go live
If you set up your IoC container to dispose of your context for you and you get it wrong, you really really get it wrong. I've twice now seen massive memory leaks created from an IoC container not always disposing of a context correctly. You won't realise you've set it up wrong until your servers start crumbling during normal levels of concurrent users. It won't happen in development so do some load tests!
Accidental lazy loading
You return an IQueryable of your most recent articles so that you can list them on your homepage. One day someone else is asked to show the number of comments next to the respective article. So they add a simple bit of code to the View to show the comment count like so...
#foreach(var article in Model.Articles) {
<div>
<b>#article.Title</b> <span>#article.Comments.Count() comments</span>
</div>
}
Looks fine, works fine. But actually you didn't include the comments in your returned data so now this will make a new database call for each article in the loop. SELECT N+1 issue. 10 article = 11 database calls. Okay so the code is wrong but it is an easy mistake to make so it will happen.
You can prevent this by shutting your context down in you data layer. But won't the code break with a NullReferenceException on the article.Comments.Count() ? Yes it will so it will force you to edit the Data layer to get the data needed for the View layer. This is how is should be.
Code smell
There is just something wrong about hitting the database from your View. You know that an IQueryable hasn't actually hit the database yet right so forget that object. Make sure your database is hit before it leaves your data layer.
So the answer
Your code should be (in my opinion) like this
DataLayer:
public List<Article> GetArticles()
{
List<Article> model;
using (var context = new MyEntities())
{
//for an example I've assumed your "MyTable" is a table of news articles
model = (from mt in context.Articles
select mt).ToList();
//data in a List<T> so the database has been hit now and data is final
}
return model;
}
Controller:
public ActionResult Index()
{
var model = new HomeViewModel(); //class with the bits needed for you view
model.Articles = _dataservice.GetArticles(); //irrelevant how _dataService was intialised
return View(model);
}
Once you have done this and understand this then perhaps you can begin experimenting with having an IoC container handle context but definitely not before. Head my warning - I've seen two large scale failures :)
But honestly do what you like, programming is fun and should be a matter of preference. I'm just telling you mine. But whatever you do, don't start using IoC context per controller or per request just because "all the cool kids are doing it." Do it because you really truly care about it's benefits and understand how it's done correctly.

I agree with one context per request, we normally do this by binding the context .InRequestScope using Ninject, which works really well, is:
Bind<MyContext>().ToSelf().InRequestScope();
Also its really good practice to enumerate the set as close to the query as possible ie:
public ActionResult Index()
{
IEnumerable<MyTable> model;
using (var context = new MyEntities())
{
model = (from mt in context.MyTable
select mt).ToArray();
}
return View(model);
}
this will help you avoid augmenting the query unintentionally from your view.

Firstly, you should consider putting your database access to separate classes.
Secondly, my favorite solution to this is to use "one context per request" (if you're using MVC, I believe it's one context per controller).
Requested edit:
Have a look at this answer, maybe it will help you too. Please note I'm using webforms, so can't verify it in MVC at the moment, but it may be helpful for you or at least give you some pointers. https://stackoverflow.com/a/10153406/1289283
Some example usage of this dbcontext:
public class SomeDataAccessClass
{
public static IQueryable<Product> GetAllProducts()
{
var products = from o in ContextPerRequest.Current.Products
select o;
return products;
}
}
Then you can do something like this:
public ActionResult Index()
{
var products = SomeDataAccessClass.GetProducts();
return View(products);
}
Simple, right? You don't have to worry about disposing your context anymore, you write only the code you really need.
Some people like to further spice things up a little bit by adding UnitOfWork pattern, or maybe IoC containers... But I like this approach more because of its simplicity.

Can you utilize LINQ's .ToList() extension method as such:
public ActionResult Index()
{
IEnumerable<MyTable> model;
using (var context = new MyEntities())
{
model = (from mt in context.MyTable
select mt).ToList();
}
return View(model);
}

Related

c# Make use of ApplicationDbContext in my Classe's static Method to reuse in View

I'm diving into ASP.Net MVC Core 2.0 and having a little trouble with the DbContext as a lot people seem to have because the documentation by MS is frustrating as I think.
I've got a running MVC-App with a DevicesController that serves a ViewModel into my Index.cshtml View. Iterating over the Model-Data works fine and a list is generated.
Now there are some column which contain different manufacturers-ids.
To get The Manufaturer-Objects i my plan was to create a Helper-Class with a static method GetManufacturer(int id) that returns an Object of Type Manufacturer.
And here's the problem: how do I get contact to the DbContext? Because I'm using the identity-Methods I need an instance of ApplicationDbContext.
I've tried a lot from MSDN-Posts or here on SO but none of theese tipps helped me solving my problem.
Look, this is what I've done so far:
Helper Class
public class Helper
{
ApplicationDbContext _context;
public Helper(ApplicationDbContext context)
{
_context = context;
}
public Manufacturer GetManufacturer(int id)
{
var manufacturer = _context.Manufacturers.Where(m => m.Id == id).SingleOrDefault();
return manufacturer;
}
}
Now, I would like to make use of this method in my view. I've shortend it a little bit:
#{
ViewData["Title"] = "Devices Overview";
Layout = "~/Views/Shared/_Layout.cshtml";
var helper = new Helper();
<span>The Manufacturers Name is:
#helper.GetManufacturer(1).ManufacturerName</span>}
helper-instance is now awaiting an argument of type ApplicationDbContext this is not my intention.
I know in recent threads I've read about the dependency injection and I think here's my problem the ApplicationDbContext is not injected into my class. But how to do so?
It would be very helpful, if you could help me get rid of this or also I'm open for a different solution.
Thanks in advance,
monsee
I think that you're trying to apply a concept which is violating the MVC principle an the whole idea behind it. In MVC, the Data Access happens through the Controller. Also, you see having a class called Helper is not helpful at all, get rid of it. What you probably trying to establish is similar to a pattern called the "Repository" pattern.
Have a ViewModel for your View, have the Manufacturer Data placed in the ViewModel, and in View, display what's in the ViewModel only. Don't try to gather Data from somewhere from the View, it will end up in a mess.
MVC will work best if base rules are applied. I think you should follow the ASP.NET MVC Tutorials to learn the basic principles.
If you're interested in optimising your data access, this documentation about "writing Clean Code in ASP.NET Core with Dependency Injection" is just right - but only once you have a higher understanding of the whole architecture.

Bad practice to declare your DBContext outside of functions in your controller?

Say I have a controller like below:
public class MyController : Controller
{
private MyDBContext db = new MyDBContext();
public ActionResult Index()
{
return View(db.Items.ToList());
}
...
Typically when I need to make EF calls I will instantiate the DBContext in the function I am using it in and wrap it in a using statement like so:
public ActionResult Index()
{
using(MyDBContext db = new MyDBContext())
{
return View(db.Items.ToList());
}
}
I found the first example on the www.asp.net website which seems like a reputable source(right?), but I'm concerned about the context not being manually disposed of after each use.
Is having a context that is defined outside of the function scope without a using statement a bad practice?
Not if you have something like this:
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
Since Controller is Disposable, it's ok
But generally I try to have a better separation between my controllers and my model.
The first way is the "recommended" way because the context will be disposed when the controller is disposed. Since the controller survives the life of the request, you're ensured that your context will hang around the entire time as well. Using using with contexts is dangerous as the context is disposed at a different point in the request and could result in problems if it's accessed after it's been disposed. You're probably okay here since the return is inside the using block, but assuming you did something like the following, instead:
List<Item> items;
using(MyDBContext db = new MyDBContext())
{
items = db.Items.ToList();
}
return View(items);
You'd be in a world of hurt the first time you accessed a navigation property that happened to be lazy-loaded. While, you didn't make that mistake in your code, it's far to easy to make it in general. If you avoid using altogether with your contexts, then you're always good.
That said, the best way is to actually use dependency injection. For all intents and purposes your context should be treated as a singleton - you don't want multiple instances floating around as that's a recipe for disaster. Using a DI container is a good way to ensure that you achieve that no matter where and in how many different way your context is used. Which DI container to use is a highly personal choice. I prefer Ninject, but there's quite a few other choices that may work better for your personal style. Regardless of which you go with, there should be some sort of option for using "request scope". That is what you'll want to use with your context as it ensures that there's only one instance per request, but every request gets its own instance.

Fluent NHibernate ISessionManager or equivilent

I am quite new to the FNH and NH world, so be gentle :P
I have created an application using FNH for data access which works good while not using lazy-loading, however once I enable lazy-loading everything goes pear shaped (as in, no sessions are open when I attempt to access the lazy-loaded properties etc).
The application layout I have created thus-far has a "Database" singleton which has various methods such as Save(), Refer() and List().
When calling Refer() a session is opened, the data is retrieved and the session is disposed; meaning there is no session available when attempting to access a lazy-loaded property from the returned object. Example: Database.Refer("username").Person since Person is lazy-loaded and the session has already closed.
I have read that Castle has a SessionManager that could be used for this very scenario but, either it's the late nights or lack of coffee, I can't seem to work out how to hook up FNH to use this manager as, in the spirit of castle, everything is defined in config files.
Am I missing something, or can this not be done? Are there any other session managers (or even more appropriate conventions) that I should look at?
Thanks for any help on this matter.
I don't think that your particular problem is connected with the SessionManager as you've already mentioned that you are capable of starting a new session and disposing it whenever needed.
From what I can understand of your post is that you are trying to expose an entity to your view (with some lazy-loaded properties) - which is already a bad idea because it leads to nasty LazyInitializationException(s).
You should consider making a distinguishion between your data-model and your domain model. The key concept has been described on this blog:
Ayende # Rahien
http://ayende.com/blog/4054/nhibernate-query-only-properties
If you say that you are writing a very simple 2-tier application then it probably will not harm if you will micro-manage your session in the data-layer (but keep in mind that this is not the best solution).
I would also look into the query that fetches your entity, as it seems to me that your are trying to obtain data that is just a part of your model - in this case Person. This can lead into serious problems like n+1 selects:
What is SELECT N+1?
So in general I think you should focus more on how things are structured in your application instead of searching for a SessionManager as it will not resolve all of your problems.
For any of you who are still looking for answers on this, I will share with you what I have so far.
This is only a very simple overview of the framework that I have decided to use, and is by far not the only solution for this problem.
The basic layout of my code is as follows:
NHibernate Repository
(references my model assembly and the UoW assembly)
Based on the HibernatingRhino's Repository implementation modified to suit my needs. Found here: http://ayende.com/Wiki/Rhino+Commons.ashx
public T Get(Guid Id)
{
return WrapUOW(() =>
{
using (Audit.LockAudit())
return (T)Session.Get(typeof(T), Id);
});
}
public void LoadFullObject(T partial)
{
if (partial == null)
throw new ArgumentNullException("partial");
if (partial.Id == Guid.Empty)
return;
WrapUOW(() =>
{
using (Audit.LockAudit())
{
LazyInitialiser.InitialiseCompletely(partial, Session);
}
});
}
public T SaveOrUpdate(T entity)
{
using (Audit.LockAudit())
{
With.Transaction(() =>
{
Enlist(entity);
Session.SaveOrUpdate(entity);
entity.HasChanged = false;
});
}
return entity;
}
protected void Enlist(T instance)
{
if (instance != null && instance.Id != Guid.Empty && !Session.Contains(instance))
using (Audit.LockAudit())
{
Session.Update(instance);
}
}
References a neat little helper class called 'Lazy Initializer for NHibernate' found here: http://www.codeproject.com/KB/cs/NHibernateLazyInitializer.aspx
This also contains Extension methods for Save, Delete and LoadFullObject
Have broken standards a little in this assembly by also creating a WrapUOW method to help simplify some of my code
protected static T WrapUOW(Func action)
{
IUnitOfWork uow = null;
if (!UnitOfWork.IsStarted)
uow = UnitOfWork.Start();
T result = action();
if (uow != null)
uow.Dispose();
return result;
}
NHibernate Unit of work
(references my model assembly)
Also based on the HibernatingRhino's UoW implementation and modified to suit
View - not important, just requried for MVVM implementation
Binds the values from the ViewModel
Model
Contains my entity classes and hibernate mapping files
ViewModel
Contains two main view base classes, ListPage and MaintenancePage
The ListPage base class just calls the Repository List method based on the object type we are listing. This loads a dehydrated list of entities.
The MaintenancePage takes an entity instance from the ListPage and calls the Repository.LoadFullObject method to rehydrate the entity for use on the screen.
This allows for the use of binding on the screen.
We can also safely call the Repository.SaveOrUpdate method from this page

Preparing models for ASP.NET MVC views

When returning strongly typed models for views such as Create and Edit (when validation of the object we are editing fails) I usually prepare the models like this:
//
// GET: /Invoice/Create
public virtual ActionResult Create()
{
// prepare the empty model
Invoice model = new Invoice();
model.Client = new Client();
model.Client.PostCode = new PostCode();
return View(model);
}
//
// POST: /Invoice/Create
[HttpPost]
public virtual ActionResult Create(Invoice document,
FormCollection collection)
{
// check for errors
if (!ViewData.ModelState.IsValid)
{
document.Client = new Client();
document.Client.PostCode = new PostCode();
return View(document);
}
Now I know that this is how others do it too, in fact you can see this same approach in MVC Music Store sample and others. However, this is very error prone because one might accidentally left out a referenced entity which is required in the view. It also requires too much thinking about view/model interaction. What I would want is some sort of automatism. Value typed properties in models usually aren't the problem because they default either to zero or empty strings. Reference types however should be initialized with new..but sooner or later we end up with code blocks that are being repeated, reference type properties being left out, etc..And I don't think it's good coding practice either.
What are other options we could take?
UPDATE:
Because replies kinda missed the point (they do not relief us of thinking about models in any way and require additional code in model classes), I was thinking if this option would work:
Use custom Action filter,
override OnActionExecuted()
use Reflection inside this method to take out the object from the Model and enumerate its public properties and try to initialize them.
I have steps 1, 2 and 3 partially implemented but I cannot figure out how to do "... = new Client();" programatically with Reflection.
Make the properties of your model return a new instance if it is null
private Client client;
public Client Client
{
get
{
if (client == null)
client = new Client();
return client;
}
}
I suggest that you use a Strongly typed view bound to a ViewModel that is distinct from the Domain Model you're trying to create, and put whatever necessary logic into the constructor of the ViewModel
I'm not sure I fully understand your question. You want what automated? ViewModels and Views? Are you creating strongly typed views?
I have created a T4 template that I point to a database and it generates a ViewModel for every table. Foreign keys become drop down lists, long strings get a TextArea instead of TextBox, etc. I then delete the ones I don't need and modify the ones I want to keep. It's not a totally automated process, but it does 80 to 90 percent of the work, depending upon the project.
Then I generate strongly typed Views from those ViewModels.
It also sounds like you might be interested in AutoMapper.

MVC 3 - How is this ever going to work?

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.

Categories

Resources