I asked myself if there is a alternative to insert each modelpart of a model to declare a content from my modelview to my model individually.
For example I have a model class:
public partial class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public string Serial { get; set; }
public string Version { get; set; }
}
and my ViewModel looks like this:
public class ViewModel
{
public List<Data.Models.Product> Products { get; set; }
}
Now in my controller I don't want to do this:
//...
Product newProducts = new Product
{
ProductName= ViewModel.Product.ProductName,
//and so on
}
//...
With this I mean to add every part of the model individually... it's quite time consuming if you have a large database table. It should also be possible to use this shortcut if the database tables aren't quite similar. For example if the ViewModel has an additional column.
I hope you will understand my problem and I am looking forward to your answers.
Related
I have a project written in C# MVC 5. There are several Controllers/Views that perform a similar set of functions based on <input ... fields in the Razor View.
There's currently logic in each controller to save input field values to a database table and later allow these saved input values to be retrieved and the View's input fields are populated by them.
These Views have many similarities and so several of their fields are duplicated across these Models.
It's become difficult to maintain code in each controller that saves its own fields and I want to use generics to create a single, common routine that saves the values for any of these controllers.
For example, 2 simple ViewModels:
public class ViewModel1
{
public string Name { get; set; }
public int Unique1 { get; set; }
...
}
public class ViewModel2
{
public string Name { get; set; }
public int Unique2 { get; set; }
...
}
Database model used:
public class SavedInputs
{
[Key] public int Id { get; set; }
public string Name { get; set; }
public int? Unique1 { get; set; }
public int? Unique2 { get; set; }
}
Now I want to create a function that can save either ViewModel's fields. Something like:
public bool SaveToDb(T model)
{
var inputs = new SavedInputs()
{
Name = model.Name,
Unique1 = model.Unique1,
Unique2 = model.Unique2
}
_db.SavedInputs.Add(inputs);
...
}
Then from each controller's Save action:
public ActionResult SaveInputs(ViewModel1 model)
{
var success = SaveToDb(model);
}
Of course ... SaveToDb() above isn't going to work but hopefully it shows what I'm wanting to accomplish.
There's many ways to do this.
Either you could have a common interface or abstract class that all your view models share which have the properties you want to save. Then SaveToDb just takes the interface instead of the generic type. Then in SaveToDb you can access all the properties of the interface properties from the model passed in and do whatever you want with them. I guess if you want to just have some properties null then abstract class makes sense, since you can override whatever you want to use
e.g.
public abstract class SavedInputsBase
{
public virtual string Name { get; set; }
public virtual int Unique1 { get; set; }
public virtual int Unique2 { get; set; }
}
public class ViewModel1 : SavedInputsBase
{
public override string Name { get; set; }
public override int Unique1 { get; set; }
...
}
public class ViewModel2 : SavedInputsBase
{
public override string Name { get; set; }
public override int Unique2 { get; set; }
...
}
public bool SaveToDb(SavedInputsBase model)
{
var inputs = new SavedInputs()
{
Name = model.Name,
Unique1 = model.Unique1,
Unique2 = model.Unique2
}
_db.SavedInputs.Add(inputs);
}
Alternatively you could use something like Automapper nuget package and have SaveToDb take SavedInputs and then just map your viewmodel to SavedInputs. Or just manually map it everywhere you want to call SaveToDb.
As my domain classes I have Person and FavoritePerson classes as follows.
public class CompanyPerson : ICompanyPerson
{
[Key]
public Guid PersonId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
public class CompanyFavoritePerson : IFavoritePerson
{
[Key]
public Guid FavoritePersonId { get; set; }
[Column(TypeName = "datetime2")]
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
[StringLength(128)]
public string CompanyUser_UserId { get; set; }
public virtual CompanyPerson CompanyPerson { get; set; }
public virtual CompanyUser CompanyUser { get; set; }
}
In my web application I will need to show List of Favorite Person. So my view model is like this;
public class FavoritePersonViewModel
{
public Guid FavoritePersonId { get; set; }
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
public string CompanyUser_UserId { get; set; }
//Option1: PersonViewModel PersonViewModel {get; set; }
//Option2: public string Title {get;set;}
}
Since I need to show Title of the favorite user in the list (where title belongs to Person class) which way will match with best practices?
Referencing a viewModel from another viewModel or extend viewModel with required extra attributes and fill them in business layer?
After some more research on this topic; I found out at this question
What is ViewModel in MVC?
it is clearly stated that:
View models can combine values from different database entities.
As like below;
So now you have data from the Employees and Departments tables in one
view model. You will just then need to add the following two
properties to your view model and populate it with data:
public int DepartmentId { get; set; }
public IEnumerable<Department> Departments { get; set; }
So I am going with Option 2.
The ViewModel pattern is just one of many patterns that fall into the 'Separated Presentation Pattern' bucket.
It's very important that you think about the requirements of your view before designing the ViewModel. For instance, if you have two widgets in your view and every widget has its own ViewModel, composite ViewModel is suitable in the situation, but if the view is just one that uses multiple domain classes, whether you have View model for each one, composite ViewModel is not suitable because it increases the complexity and every change in one ViewModel can break your code.
Thus, based upon your question
As my domain classes I have Person and FavoritePerson classes.
Since I need to show Title of the favorite user in the list (where title belongs to Person class).
It seems to me that composite ViewModel is not a good choice and you should design a new ViewModel.
It is also worth to read the ViewModel Best Practices
I really can't get my head around how to use ViewModel's in MVC. Say I have two simple domain models:
public class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int Id { get; set; }
public string ProductName { get; set; }
}
And now my goal would be to create a ViewModel that displays (combines) the CustomerName and ProductName to display to a view. I'm confused what to include in the ViewModel to accomplish this. Do I use the same property names as my domain models like so?
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
}
How does the ViewModel know that the properties come from two different classes? Or am I forming my ViewModel incorrectly?
As i can see it you have a bigger design problem here.
Lets say you need to show on the UI only the CustomerName and ProductName. Well then just add those two on to your ViewModel class and you`re good to go, exactly how you described it.
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
}
Getting the data in two variables is not a problem:
Customer customer = service.GetCustomer();
Product product = service.GetProduct()
And now that you have everything you need you can just set the data and pass it to the view.
MyViewModel viewModel = new MyViewModel();
viewModel.CustomerName = customer.CustomerName;
viewModel.ProductName = product.ProductName;
It always depends on what you need to show on the UI and only send what you need and nothing more.
You do not need to have exactly one Model that you pass all over the place in your application, Business, DataAccess, UI. You can have something custom if you really need it.
You would have to set this up yourself in the ViewModel, as a template it could look something like:
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
public void GetCustomerName(int customerId)
{
CustomerName = CustomerServiceLayer.GetCustomerName(customerId);
// CustomerService Layer (I.e. a repository that contains this info;
}
public void GetProductName(int productId)
{
ProductName = ProductServiceLayer.GetProductName(productId);
// ProductService Layer (I.e. a repository that contains this info;
}
}
You would then have two other Service Layers (ProductServiceLayer and CustomerServiceLayer) that speak to the database/repository to obtain the information you want. That information is then returned to the view (via your ViewModel) and displayed to the user.
Alternatively you could pass a Customer and a Product object directly into your ViewModel (via a constructor).
public class MyViewModel
{
public Customer MyCustomer { get; set; }
public Product MyProduct { get; set; }
public MyViewModel(ICustomer customer, IProduct product)
{
MyCustomer = customer;
MyProduct = product;
}
}
The downfall here would be that you expose your entire Customer and Product classes in the View.
You can do it like that but you generally build the viewmodel up on render in the get action and then post parts of that view model back and handle it on a post action. The MVC binding does the magic once getting the values posted back from a form.
I wouldn't put business logic inside the viewmodel but rather build the viewmodel up in your controller using managers/services.
You could also make it so the viewmodel has your complex model types as the properties like so..
public class MyViewModel
{
public Customer Customer { get; set; }
public Product Product { get; set; }
}
ViewModel rapresents a model you use to go to your view. In your controller you'll retrieve data and pass them to your ViewModel.
Imagine you have a checkbox in you view that rapresent a Gold Customer: it's not suitable to change your domain model to add this information and it's not a good practice to make your code dirty with Viewbag and Viewdata (imho).
So you create a model or template that has all the information you need. In our case:
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
public boolean IsGoldCustomer { get; set; }
}
Ofter you'll have to convert your model into a ViewModel and viceversa in order to pass data from a "DOMAIN model" to a "VIEW model".
I have a model and a partial model which contains only the properties that I need to expose in JSON.
But the properties between the model and his partial model are redundant.
How can I avoid that or improve my approach?
namespace Dashboard.Models.UserModels
{
public class UserModel
{
public int id { get; set; }
public string dbName { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public int idExternal { get; set; }
public int idInstance { get; set; }
public string login { get; set; }
public string password { get; set; }
public DateTime? dtContractStart { get; set; }
public DateTime? dtContractEnd { get; set; }
public string emailPro { get; set; }
public string emailPerso { get; set; }
public LuccaUserModel()
{
idInstance = -1;
}
// partial model for json result
// not sure is the best way or have to be here
public class PartialUserModel
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string emailPro { get; set; }
public string emailPerso { get; set; }
public DateTime? dtContractStart { get; set; }
public DateTime? dtContractEnd { get; set; }
public string url { get; set; }
}
// UserModel Methods
}
}
You can rename PartialUserModel UserModelBase class (or leave it as is... it just makes better logical sense to do so) and make UserModel to inherit from it:
public class UserModel : UserModelBase
{
...
}
Of course you'll need to remove all duplicate properties from UserModel in this case.
It's a thin line between doing a proper design and building an overkill design. Answer depends on many inputs, among which I chose to have project and model breadth most important.
In hope to have my answer clearer, I have to say I use different terminology. Data which is adopted for use in UI is usually called ViewModel. In your case, you would build UserViewModel which contains necessary subset of information.
If I'm working on a one-off project, I'll reuse model as a ViewModel. I'll do this by having helper method which removes sensitive information, loads up or cuts off data which is lazy loaded from database and does other preparation on data. All this is done with same model class.
If it's not a short term project, I look to create separate ViewModel classes which I map from model data. Then, if I'm working with mostly flat data I use AutoMapper tool to have data automatically copied, instead of writing my own mappers.
As another answer here states, you write a basic class with data you need in UI and extend it with other model data, however this is not a good approach for several reasons.
If violates separation of concerns. Project dealing with model and persistance should not know about your ViewModel
You may need to flatten data from related objects into ViewModel objects. In that case, your model objects would have fields which should not be there, or would be redundant.
You may need calculated fields and helper methods in ViewModel which would again end up in model, confusing everyone that is not updated about design.
You could want to adopt several unrelated model classes to same ViewModel class
To try and put it shortly, either reuse model class or create ViewModels. There is unfortunately no clever solution. If you find one, please post a comment as I'd like to hear about it :)
I've created an MVC 3 Razor application that manages Projects, and should manage Sections within those Projects.
So, I've made a model Projects.cs, controller ProjectsController, and got myself a Projects.sdf data table. Works just fine
Then I've added same for Sections, but Sections should have a field named projectID (made it of course) that is connected (joined) with ID in Projects.sdf; also, I need it to be able to be sorted by projectID, and from a DropDown
For example: Using DropDown to alter the table data. If lets say I select project1 from Project list, I want the list to show all Sections within that Project along with CRUD.
I've tried several things but none worked so far, I know how to do this in regular application but not in MVC so I beg for some assistance. Also tried to add DropDown in Sections view and getting it to populate from Project model data, but no good at all.
So I need help on how to do this :(
Please, and thank you.
Addition
Project has many Sections, and yes I'm using EF, but as I said not too experienced with it.
as for data context
this is Project
namespace MyProject.Models
{
public class Projects
{
public int ID { get; set; }
public string projectName { get; set; }
public string shortDesc { get; set; }
}
public class ProjectsDBContext : DbContext
{
public DbSet<Projects> Projects { get; set; }
}
}
this is Section
namespace MyProject.Models
{
public class Sections
{
public int ID { get; set; }
public int projectID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class SectionsDBContext : DbContext
{
public DbSet<Sections> Sections { get; set; }
}
}
Addition 2
So I made a model named MyProjectModels.cs
namespace MyProject.Models
{
public class Project
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Section
{
public int ID { get; set; }
public int projectID { {get; set;}
public string Name { get; set; }
public string Description { get; set;}
}
}
So basically I'm kinda figuring it out. Please let me know if this is ok for models or do I need to put them in separate files? Also, How should i declare context from this point, a hint would be enough :)
Thank you
This is the way I have done it. It displays properly but i have NO idea how to utilize it, for example to show different values in a table...
<select id="select1" name="select1">
#foreach (var item in Model.Enrollments)
{
<option value=#Html.DisplayFor(modelItem => item.Course.Title)>#Html.DisplayFor(modelItem => item.Course.Title)</option>
}
</select>
by different values in table i meant, when i select different enrollment in this case. i would like to show different values in table.
Do you really need to have different dbcontexts? If it is one sdf file then I'm guessing not and your dbcontext should look like
namespace MyProject.Models
{
public class DatabaseContext: DbContext
{
public DbSet<Projects> Projects { get; set; }
public DbSet<Sections> Sections{ get; set; }
}
}
then in your projects model you would have a property for sections
namespace MyProject.Models
{
public class Projects
{
public int ID { get; set; }
public string projectName { get; set; }
public string shortDesc { get; set; }
public Sections section { get; set; }
}
}
and your sections would just need an id field
namespace MyProject.Models
{
public class Sections
{
public int ID { get; set; }
public int projectID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
As long as your sections class has a primary key field called ID or the id property flagged as the primary key then EF will make the logical leap that Projects has a foreign key of section in the table structure. your projects model will then have access to the section object. Biggest hurdle I had with EF was overthinking the database side of things.
For the dropdown list here is the way I have done it
public class ChangeUserNameViewModel
{
public ChangeUserNameViewModel()
{
var user = User.GetAllButBuiltIn();
Users = new SelectList(user, "UserName", "UserName");
}
public User User
{
get;
set;
}
[DisplayName("User Name")]
public SelectList Users
{
get;
set;
}
public string UserName
{
get;
set;
}
}
then in the view I reference the viewmodel
#model ChangeUserNameViewModel
#Html.DropDownList("UserName", Model.Users, "Choose")
the first parameter is the name of the drop down in the html. the second the select list to populate it and the third the selected value. I'm sure there are better ways to do it. For example you could have an IList in your model and then do a foreach loop in your view. It all depends on what works best in your case.