I am writing an application in MVC2 using Entity Framework
As I know ViewModel has to contain only data without any logic to database. Suppose I have Product class that is ADO.NET entity that has EntityCollection<ProductToStatus> when ProductToStatus is many-to-many table. I have ProductModel (that takes Product in its .ctor) which is passed to View.
public class ProductModel
{
....
public Product Item {get; private set;}
...
public ProductModel(Product item)
{
...
this.Item = item;
...
}
}
In View I need to render all statuses of the product, so to do it I need to query the DB by item.ProductToStatus.Select(s=>s.ProductStatus).ToList(); in the ProductModel, but this sends request to the DB and thus does it violates the MVC principle?
Is this OK or I need to do something?
you shouldn't do this. Your controller should collect the data required for your view and should package it up and pass it to the view for it to render.
So your ProductModel should either take the details of the Product it needs in its constructor or through properties (my preference) or should, at a push, use the Product it is given to do all the querying in the constructor to set all of its internal fields but not keep a reference to the Product around. I don't like the using the Product in the constructor particularly as its doing work in the constructor which is not great, but depending on what it is doing exactly it might be ok.
Its probably better to make your ProductModel have a load of properties, then you can create it like so:
var model = new ProductModel()
{
Statuses=product.ProductToStatus.Select(s=>s.ProductStatus).ToList(),
Name=product.Name,
OtherProperty=GetPropertyValue(product),
//etc
}
Yes its violating the pattern. You should fill your ViewModel in the Controller and then pass it to your view.
Off course it will work, but thats not the idea of model-view-controller.
Related
I am using the Repository pattern with.NETCORE and am trying to return data back from an HttpGet request. The data I want back is from multiple un-related tables in SQL. I am trying to wrap my head around being able to retrieve the data from each respective repository and return an object with all data. I hope this makes sense, I am stuck and started to go down "Unit of Work" but can't find a good example that does what I would like, query multiples in un-related tables from one get request. Thanks in advance.
Step 1. Create model classes (domain model layer) for each table / view or the dataset that comes from the SQL database. Shown below:
public class DataFromTable1
{
// properties mapped with the sql table columns
}
public class DataFromTable2
{
// properties mapped with the sql table columns
}
public class DataFromTable3
{
// properties mapped with the sql table columns
}
Step 2. Write data access classes that will call the SQL database (stored proc or direct SQLstatement – I don’t recommend direct table access from .net though) to populate your model classes created in step 1. You can use any repository pattern in this step.
Step 3. Create a view model class that will wrap the model classes with its properties and hydrate them by calling the data access class create in step 2. Generally view model classes are created under the MVC project.
public class MyViewModelClass
{
public DataFromTable1 DataFromTable1 { get; set; }
public DataFromTable2 DataFromTable2 { get; set; }
public DataFromTable3 DataFromTable3 { get; set; }
}
Step 4. Use this view model to display the data in the view.
Hope this helps.
The way I am doing this at the moment (which works) feels a bit hacky. When I am editing an entity I don't want the user to change key auditing fields behind, for example when the entity is initially created it automatically populates DateAdded, AddedBy, EditedBy.
To stop people editing these values I don't bind them in the include when editing:
public ActionResult Edit([Bind(Include = "Id,AccountName")] Account account)
This means I have to do this to get the original values back otherwise they get set to null
account.DateAdded = db.Accounts.Where(c => c.Id == account.Id).Select(d => d.DateAdded).FirstOrDefault();
account.AddedBy = db.Accounts.Where(c => c.Id == account.Id).Select(a => a.AddedBy).FirstOrDefault();
account.EditedBy = User.Identity.Name;
Is there a better way to fix this, the way below works but doesn't feel efficient.
The recommend approach is to use a view model containing only the proeprties you need to display/edit say
public class AccountVM
{
public int ID { get; set; }
public string Name { get; set; }
}
which then then use in the view and post back to your controller, get the data model based on the ID property and map the view model properties to you data model and save. Note the [Bind] attribute is not required.
Using view models has numerous advantages including application of view specific attributes and prevention of overposting attacks. For more information refer the answers to What is ViewModel in MVC?
Tools such as automapper make it easier to map ata between you data and view models.
My project has several models, some with 1:many relationships with other models. A user has a profile page, this is split up into several partial views - each grouping/representing specific attributes of the given model.
If for example, I want to display 5 of the 10 properties of a given model in a partial view, and want to persist the properties that aren't shown to the user I'm using Html.HiddenFor like so
#Html.HiddenFor(x => x.IsInGroup)
This works for single entry properties as above. Of the 5 hidden member attributes, one of these may be a list. I understand that a list cannot be persisted using HiddenFor. I've come across the Mvc Futures package and the Html.Serialize helper extension, but I'm not totally sure how to use it and havn't been able to find much good information on it.
Once a model is passed to a view everything associated with it (properties, collections) is available for us to access e.g. Model.Username. If for example we don't use HiddenFor with Username, does that mean it will be reset to a default value, or null? Is this the same for collections?
Is using HiddenFor the only/best way to persist a model's properties that are not shown to the user?
Is using Html.Serialize the only way persist a model's collection that is not shown to the user? Other options?
Could someone provide/link to a simple example of how to persist a collection in a situation similar to what I've described?
If I was to use Html.Serialize, does the whole model need to be serialised or can I just serialise the collection?
Feedback appreciated.
You don't need to "persist" any data from your model by creating all the fields (hidden or not) from the model. In controller, when updating the record in the database you will just update what you need, the rest will not be affected.
Let's say this is your Product model
class Product {
public int ID {get; set;}
public string Name {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public virtual ICollection<Category> Categories { get; set; }
}
If you only want to edit Name and Description in your view, then you can only put those fields, and skip the rest (the ID would be in a hidden field). When the form is submitted, in your controller you would reference the Product record by the ID that got passed in and then you can update Name and Description to what you received from the form. Categories and the price will not be affected.
Somewhat more straight forward way to do this is to use a ViewModel specific to the view without non-editable properties. I found this post that gives more details how to do this:
Successful Model Editing without a bunch of hidden fields
On a smaller project you don't have use any kind of library (AutoMapper, InjectValues, ...), but you can do it yourself in places where you need to copy the values from a ViewModel into an actual record from DB.
I have created a repository that is returning data from my database using Entity Framework and I need to provide this data to my view, but before I do that I need to convert those objects into my domain model.
My schema looks like this:
TABLE Project
Id INT PRIMARY KEY
Name NVARCHAR(100)
TABLE Resource
Id INT PRIMARY KEY
FirstName NVARCHAR(100)
LastName NVARCHAR(100)
TABLE ProjectResources
Project_Id INT PRIMARY KEY -- links to the Project table
Resource_Id INT PRIMARY KEY -- links to the Resource table
I generated an entity model which ended up looking like this:
Project
|
---->ProjectResources
|
---->Resource
I have a repository that returns a Project:
public interface IProjectRepository
{
Project GetProject(int id);
}
And a controller action:
public ActionResult Edit(int id)
{
Project project = projectRepository.GetProject(id);
return View(project);
}
This doesn't seem to work very well when I try and POST this data. I was getting an EntityCollection already initialized error when it was trying to reconstruct the ProjectResources collection.
I think it is smarter to create a domain model that is a little simpler:
public class ProjectEdit
{
public string ProjectName { get; set; }
public List<ProjectResource> Resources { get; set; }
}
public class ProjectResource
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
This seems to be a little nicer since I also don't have the intermediate ProjectResources -> Resource jump. The ProjectResource would have the fields I need. Instead of doing something like:
#foreach( var resource in Model.ProjectResources ) {
#Html.DisplayFor(m => m.Resource.FirstName)
}
I can do:
#foreach( var resoure in Model.Resources ) {
#Html.DisplayFor(m => resource.FirstName);
}
My question is as follows
Should I be returning my domain model from my repository or should that be handled by the controller or some other class in the middle? If it's handled in the controller by something that maps my Project to a ProjectEdit, what would that look like?
My own view is that you shouldn't return anything to your controller or a view that is dependant on the implementation of your repository.
If you're using EF with the POCO Generator, it's reasonable to use those classes for your domain model because they're independent of the EF implementation (you could replace EF and retain the POCO's).
But if you're using EF with its EntityObjects, I believe you should convert to your domain model. If your Data Access was encapsulated in a WCF service which used a repository pattern internally, I wouldn't worry so much about returning EntityObjects from the Repository. But if you're using a Repository directly from MVC, use the Domain Model as the interface to the Repository.
We tend to always use a ViewModel as "the class in the middle" and map to and from the actual Model using...
Automapper
...or...
ValueInjecter
Your ViewModel can then be fairly independent of your Model in terms of structure if you want it to be.
What you describe is exactly what I've been doing for years, tying to follow n-tier application design.
Because you data will not always be organized the same way as your domain. What makes since in SQL is not always the same in your domain, as you've come across here.
Typically my domain knows what the repository looks like and has methods for converting to and from. My UI/views know what the domain looks like and have methods for retrieving that data (that goes in the controller).
So short answer, I would say, something in the middle (your business layer) and have that expose methods usable by your controllers to receive that data.
I have an entity in my EDMX that I've extended with a few fields in a partial class like this:
public partial class Employee
{
public string JobName {get;set;}
}
These properties are for display only. In the above example say the entity has a JobTypeID property. I wish JobName to be populated w/ the name that belongs to that JobTypeID.
Is there anyway to query the employee record in EF including the value for the JobName property w/o explicity assigning each field using select()?
The reason I ask is that there are a lot of fields in the Employee entity so I'd like to be able to take advantage of something like:
ctx.Employees.Where(e=>e.EmployeeID==employeeID).Single()
...add somehow fill in JobName too
Is this possible?
How about: public string JobName { get { return this.JobType.Name; } }?
Not a solution, but a different approach to what you are trying to achieve...
Why not use the power of EF! use "Include" to load the relation based records from related tables?
You can do that in a single place as well, say if you want a JobType record per Employee record, you may consider using a repository pattern and add all possible includes for your entities which depend on each other!
Some thoughts further on what I mentioned, not exactly as I said but...
http://mosesofegypt.net/post/Introducing-DataLoadOptions-for-Entity-Framework-ObjectContext.aspx