I have a Employee class which is an Entity Framework code first class representing an Employee. I would like to create a view model based on the original Employee class and then populate that class from a linq query to my EF context.
public class EmployeeVM : Employee
{
public List<DepartmentSelect> Departments { get; set; }
}
EmployeeVM employee = context.Employees.Find(id);
I get the error "cannot implicitly convert type Employee to EmployeeVM."
Is there a simple way to do this rather then creating a new object and foreaching every parameter into the equivalent in the new class?
be nice if coding had an easy button, but it is what it is.. You could write the code one time and reuse it if you want. You could use AutoMapper and deal with some of the headaches that come with that. Your best bet would just be to write it yourself and maybe catch some errors if your context changes..
Without a mapper you could just add a static func to your viewmodel that will take an Employee object and create an EmployeeVM and use this in your context queries.
public class EmployeeVM
{
public EmployeeVM()
{
Departments = new List<DepartmentSelect>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? Dob { get; set; }
public List<DepartmentSelect> Departments { get; set; }
public static Func<Employee, EmployeeVM> FromEntity = item => new EmployeeVM() {
Id = item.Id,
FirstName = item.FirstName,
LastName = item.LastName,
Dob = item.Dob
};
}
// get single EmployeeVM
var eVm = EmployeeVM.FromEntity(context.Employees.Find(id));
// get List<EmployeeVM
var eVmList = context.Employees.Select(EmployeeVM.FromEntity).ToList();
This isnt recommended but if Employee is a partial class you could always just extend it by adding another partial class in the same namespace.
public partial class Employee
{
//Add Extra Properties
public List<DepartmentSelect> Departments { get; set; }
}
you maybe want to use Automapper. http://automapper.org/
Tools like AutoMapper are designed to ease the burden of having a bunch of property-mapping code. You can also just serialize the first object and deserialize it into the second one.
I should probably mention, though, that this is probably a misuse of inheritance. Is there a reason you can't just put your Employee entity directly on your EmployeeVm as a property? Beyond that, Arash is right in pointing out that ViewModels should generally not be tightly coupled to your data model.
Related
I do project by asp.net core mvc. when I do copy of the model and change its values, the values of the original model is changing too because it made copy of the model by reference, so the value place in data is same.
I need way that I can do copy for values of the model doesn't connect with original model.
Your question could have many answers depending on the encapsulation of the object you are copying. I will assume you are operating on a low level entity object rather than an object that is supposed to encapsulate it. If this assumption is incorrect and it is a higher level object that encapsulates entity operations I will gently remind you of good programming practices: Martin Fowler - TellDontAsk.
For the answer I will use the class below to illustrate:
public class Student
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime EnrollmentDate { get; set; }
}
I assume what is happening is something similar to the following:
Student john = new Student();
Student jane = john;
jane.FirstName = "Jane"; // now john.FirstName == "Jane"
What you are going to need to do is clone the object to a new object instance. There are various ways to do that.
Option #1:
// Create a new entity object manually assigning each value
// from the first object to the value in the new object.
var clonedStudent = new Student
{
Id = john.Id, // Copies value not reference
LastName = john.LastName, // string is immutable this OK
FirstName = john.FirstName, // string is immutable this OK
// DateTime is a struct I think so it should pass value
EnrollmentDate = john.EnrollmentDate // Verify my assumption
};
Option #2:
// Make Student class partial and extend it with clone method.
// This is helpful for generated entities not using the code-first approach.
public partial class Student
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime EnrollmentDate { get; set; }
}
public partial class Student
{
public Student Clone()
{
return new Student
{
Id = Id, // Copies value not reference
LastName = LastName, // string is immutable this OK
FirstName = FirstName, // string is immutable this OK
// DateTime is a struct I think so it should pass value
EnrollmentDate = EnrollmentDate, // Verify my assumption
};
}
}
To use it you would write:
Student clonedStudent = john.Clone();
Option #3: You could use a NuGet package that does the cloning for you. There are various ones that do that. A quick google search pulled up this one for me. DeepCloner
If you are copying objects from one type to another you might want to use AutoMapper.
NOTE: Also, based on your question a good knowledge of how entity framework handles changes might be useful.
Tracking vs. No-Tracking Queries
Hopefully that helps.
Happy coding!!!
option 1 use AutoMapper
option 2 create Copy using Reflection
public class PropertyCopier<TParent, TChild> where TParent : class
where TChild : class
{
public static void Copy(TParent parent, TChild child)
{
var parentProperties = parent.GetType().GetProperties();
var childProperties = child.GetType().GetProperties();
foreach (var parentProperty in parentProperties)
{
foreach (var childProperty in childProperties)
{
if (parentProperty.Name == childProperty.Name && parentProperty.PropertyType == childProperty.PropertyType)
{
childProperty.SetValue(child, parentProperty.GetValue(parent));
break;
}
}
}
}
}
i want to add a new type to an existing class(object?) that fetch from database table (with entity framework class) in Microsoft MVC.
i.e:
my person class {f_name, l_name}
how can i add new type to this objects when i loop throw it?
like:
// Person class stracture is:
public Person()
{
public string f_name { get; set; }
public string l_name { get; set; }
}
i want to add 'age' to it without add this to model
var all_persons = db.Person.toList();
for (var item in all_person)
{
item.age = some_value;
}
return View(all_persons);
Add a [NotMapped] (assuming you dont want this property to be mapped to database) in your Person class:
[NotMapped]
public int Age {get; set;}
Or create a view model instead of using EF model directly
Example using Entity Framework :
If you are using code-first approach then [NotMapped] will work fine for you.
But if you are using model-first approach then it will not work because if you are going to update your model its going to be updated according to .tt template of model and create a class with only properties in tables.
So, what now ? here comes the concept of partial class.
model generated from EF :
namespace EF.Model
{
public partial class Person
{
public string f_name { get; set; }
public string l_name { get; set; }
}
}
So to add additional properties that you don't want EF to map while CRUD operations. Add a new partial class in the same project with same class name and same namespace as of EF model
namespace EF.Model
{
public partial class Person
{
public string fullName { get; set; }
public int age { get; set; }
}
}
So now you can do like this.
var all_persons = db.Person.toList();
for (var item in all_person)
{
item.age = some_value;
item.fullName = item.f_name + item.l_name;
}
return View(all_persons);
I hope this would give you a better understanding. You should read about partial classes.
https://www.dotnetperls.com/partial
You can add the new property in a linq Select as follows:
void AddNewField(int number)
{
var all_persons = new db.Person.Select(x => new { x.f_name, x.l_name, age = number });
return View(all_persons);
}
This will save you having to actually add the new field to the model.
I have 2 simple models:
public class Country
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Region> Region { get; set; }
}
public partial class Region
{
public int ID { get; set; }
public string Name { get; set; }
public int CountryID { get; set; }
public virtual Country Country { get; set; }
}
Is it possible to have a single page to handle the creation of a country whereby the user inputs the country with multiple regions and then only posts to the server?
I've seen an implementation here where you create a custom ViewModel with numbered properties (Region1, Region2, Region3, etc) but it's limiting, any suggestions?
(I know AngularJS can be used to do this however I have no experience in this space as of yet.)
Thanks
Yes its very possible it just depends on how you plan to implement this.
My favourite style of implementing One to Many pages is initially creating the "one" (country) then redirecting to a page with a grid element where users can add the many (regions) to the one. It works well and its a very easy way for both the programmer to create and the user to understand.
As for creating a country with multiple regions in a single post, it could be done but you must think of how the implementation will work.
Sure, this is easy to do. You have defined your data model. Either you use that also as your View Model, or you can create a new model that is a complex object. The methods in your type:
public virtual Country Country { get; set; }
public virtual ICollection<Region> Region { get; set; }
These method being present normally indicates you're using Entity Framework and that these are "related entities" that you can traverse via this "navigation property" at run-time. You can create a Country and populate the Region collection on the fly when you try to use it.
Here is a good example of using a View Model:
What is ViewModel in MVC?
///Example of a Controller method creating a view model to display
[HttpGet]
public ActionResult Index()
{
var user = _userService.Get(User.Identity.Name);
var customerId = GlobalDataManager.GetCustomerId();
if (_error != null)
{
ModelState.AddModelError("", _error);
_error = null;
}
var model = new InboundListModel();
model.Initialize(customerId, user.CompanyId);
foreach (var campaign in model.Campaigns)
{
model.InitializeCallProggress(campaign.Id, _callInfoService.GetCallsCount(campaign.Id));
}
return View(model);
}
This View Model can be anything you want but it does need to be one type. So if you want 2 put 2 types in the ViewModel you just need a new container object:
public class ComplexViewModel
{
public Country Country { get; set; }
public ICollection<Region> Regions { get; set; }
}
Then you just need a way to populate the data like the example above where I call Initialize. This goes out to EF via a DAL project and retrieves the data for the model.
I am having trouble using AutoMapper when doing CRUD operations in MVC. I have scoured the web looking for something related to this but cant find anything related to what I am trying to do. Maybe there is something but I am having trouble understanding the more advanced functions of AutoMapper.
Basically what im trying to do is use AutoMapper on the CREATE method in an MVC application. Now I can map just the basic information perfectly fine but when I need to include another Model I get completely lost in figuring it out. Here is my example below.
This is the model in my AppDomainClasses
public class City
{
public City()
{
this.Name = string.Empty;
this.Cities = new List<City>();
}
public City(string cityName)
{
this.Name = cityName;
this.Cities = new List<City>();
}
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public List<City> Cities { get; set; }
}
This is my viewmodel in which im trying to automap
public class CityForList
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class CityFull : CityForList
{
public CityFull()
{
Cities = new List<CityForList>();
}
public List<CityForList> Cities { get; set; }
}
So basically when I created this Map
Mapper.CreateMap<CityFull, City>();
Then I pass a CityFull object into the mapper
Mapper.Map<CityFull, City>(cf);
So what I am doing is that I have the Create method passing in the CityFull object and a FormCollection of items which contains the ids of the cities. So all I need to have done is map the Id, the Name and the cities that were selected and have them mapped. Now I can map the Id and Name without problem but I do not know how to then add the selected cities ( comes from the form collection of a listbox) into AutoMapper to include them in the mapping.
I thank you ahead of time for any help you can offer!
The reason you don't get the selected cities is because the "Selected" attribute is not part of the "City" Class.
I would advise you to make another map with AutoMapper, that maps the controller's to a class(Lets call it CityController) that you will create , and have that CityController related to CityForList.
Hope this helps.
I am developing a new MVC4 project using Entity Framework for the first time. I really like being able to use code first models and update the database with migrations. I would like to be able to just have one place to change my model (the entity class) and for changes to this such as new properties to be reflected not only in the DB after a migration, but also in my view models.
So, what I would like to do, is to be able to generate a dynamic view model class using my entity class. The view model should copy all the properties and values from my entity class with some special logic defined in my entity class attributes.
For example, for a simple enity framework model like this:
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
I would like to generate a dynamic class that looke like this:
public class UserProfileView
{
[ScaffoldColumn(false)]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
The pseudo code could look something like this but I don't know how I can achieve it:
function dynamic GeneraveViewModel(object entity)
{
Type objectType = entity.GetType();
dynamic viewModel = new System.Dynamic.ExpandoObject();
//loop through the entity properties
foreach (PropertyInfo propertyInfo in objectType.GetProperties())
{
//somehow assign the dynamic properties and values of the viewModel using the property info.
//DO some additional stuff based on the attributes (e.g. if the entity property was [Key] make it [ScaffoldColumn(false)] in the viewModel.
}
return viewModel;
}
Can anyone offer any advice?
I created Dynamic MVC to do this.
http://dynamicmvc.com
Install-package dynamicmvc
The main benefit to this approach is it allows you to focus on your business logic and have the UI logic built automatically for simple scenarios.