You've got a lot of moving parts in your question, touching on a lot of concepts, but here's my basic advice when it comes to how to think about a mid-to-large scale MVC application:
Presentation <---> Business Logic <---> Data Access
Firstly, it's best to not think of the the app as "an MVC application". It's an application that uses the MVC pattern as its presentation component. Thinking about it this way will help you separate out your business logic concerns from your presentation concerns. Perhaps it's ok for small applications to pile everything down to database access into the MVC structure, but it'll quickly become untenable for a mid-to-large application.
MVC (Presentation)
In your app, the ASP.NET MVC component should deal with transforming business data for display purposes (Models), displaying the user interface (Views), and communication issues such as routing, authentication, authorization, request validation, response handling, and the like (Controllers). If you have code that does something else, then it doesn't belong in the MVC component.
Repository/ORM (Data Access)
Also in your app, the data access layer should be concerned with retrieving and storing persistent data. Commonly that's in the form of a relational database, but there are many other ways data can be persisted. If you have code that isn't reading or storing persistent data, then it doesn't belong in the data layer. I shared my thoughts on the ORM/Repository discussion previously on SO, but to recap, I don't consider an ORM to be the same thing as a Repository, for several reasons.
Business Logic
So now you have your presentation layer (MVC), and your data layer (repository or ORM) ... Everything else is your business logic layer (BLL). All of your code that decides which data to retrieve, or performs complicated calculations, or makes business decisions, should be here. I usually organize my business logic in the form of 'services', which my presentation layer can call upon to do the work requested. All of my domain models exist here.
Your Approach
This is where your approach breaks down a little for me. You describe your MVC controller as the place you would get data from the repository, and call upon the MPGCalculator to do some work, etc. I would not have my controller do any of this, but instead would delegate all of this off to a service in the BLL.
In other words, I would not inject a repository and MPGCalculator into the controller, that's giving the controller too much responsibility (it's already handling all of the controller stuff I mentioned above). Instead, I would have a service in the BLL handle all of that, and pass the results back to the controller. The controller can then transform the results to the correct model, and pass that on to the correct view. The controller doesn't have any business logic in it, and the only things injected into the controller would be the appropriate BLL services.
Doing it this way means your business logic (for example, given a set of vehicles, calculate the MPG and sort best to worst) is independent from presentation and persistence concerns. It'll usually be in a library that doesn't know or care about the data persistence strategy nor the presentation strategy.
I see two distinct subjects in your question:
- How to manage circular references when serializing to JSON?
- How safe is it to use EF entities as model entities in you views?
Concerning circular references I'm sorry to say that there is no simple solution. First because JSON cannot be used to represent circular references, the following code:
var aParent = {Children : []}, aChild = {Parent : aParent};
aParent.Children.push(aChild);
JSON.stringify(aParent);
Results in: TypeError: Converting circular structure to JSON
The only choice you have is to keep only the composite --> component part of the composition and discard the "back navigation" component --> composite, thus in you example:
class parent
{
public List<child> Children{get;set;}
public int Id{get;set;}
}
class child
{
public int ParentId{get;set;}
[ForeignKey("ParentId"), ScriptIgnore]
public parent MyParent{get;set;}
public string name{get;set;}
}
Nothing prevents you from recomposing this navigation property on your client side, here using jQuery:
$.each(parent.Children, function(i, child) {
child.Parent = parent;
})
But then you will need to discard it again before sending it back to the server, for JSON.stringify won't be able to serialize the circular reference:
$.each(parent.Children, function(i, child) {
delete child.Parent;
})
Now there is the issue of using EF entities as your view model entities.
First EF is likely to using Dynamic Proxies of your class to implement behaviors such as change detection or lazy loading, you have to disable those if you want to serialize the EF entities.
Moreover using EF entities in the UI can be at risk since all the default binder will mapping every field from the request to entities fields including those you did not want the user to set.
Thus, if you want you MVC app to be properly designed I would recommended to use a dedicated view model to prevent the "guts" of your internal business model from being exposed to the client, thus I would recommend you a specific view model.
Best Answer
In general, you don't need to use
Using
statements with Entity Framework data contexts. Lazy collections is one of the reasons why. So your code would simply be:Data contexts in Entity Framework are designed to open and close connections as needed, and they dispose of themselves automatically when the data context object is no longer required.
The only time you would have to be careful about
IDisposable
is if youOverride
the data context's default behaviors.Further Reading
Do I always have to call Dispose on DBContext? Nope.
Managing DbContext the right way with Entity Framework 6: an in-depth guide