C# MVC Dynamically create view model - c#

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.

Related

Entity Framework Core 2.0 How to automatically Insert Update Delete an detached entity

I have found a lot of threads discussing this topic but none of them have a good solution or I'm just not able to use better search tags :|
I have a Angular2 Frontend with a ASP.Net Core WebApi2 Backend. The database is connected via Entity Framework Core 2.
My issue is just focussed on the backend with EF Core.
My aim is to have a simple method which takes a detached entity (coming from the frontend) which should be updated to the database.
The entity itself has some properties with a lot of navigation properties and these navigation properties have also a lot of navigation properties.
The database model could look like this:
public partial class Project
{
public Project()
{
DocumentNavigation = new HashSet<Document>();
}
public string ProjectNr { get; set; }
public string ProjectTitle { get; set; }
public ICollection<Document> DocumentNavigation { get; set; }
}
public partial class Document
{
public Document()
{
UserNavigation = new HashSet<User>();
}
public int DocumentId { get; set; }
public string DocumentName { get; set; }
public ICollection<User> UserNavigation { get; set; }
}
public partial class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
My method looks like this:
[HttpPut]
[Route("{projectNr}")]
public IActionResult UpdateProject(string projectNr, [FromBody]Project project)
{
using (abcContext ctx = new abcContext())
{
DoSomething();
ctx.SaveChanges();
}
return NoContent();
}
How do I have to write the method "DoSomething()" in order to deal with this problem?
Imagine, my new object "project" could have new documents, some documents which are still in the database should be deleted because they are no longer in the parameter object "project" and some documents have just changed its normal propoerties like "DocumentName". This could also has happend to the underlaying UserNavigations ...
I just wanted to keep this sample simple. My original entities and the database is much bigger.
To my mind the EF should have a method like "ctx.Update(project)" which manages all these problems???
I cannot believe that I have to do all this stuff manually.
But just in case of doing it manually, how would it look like?
Thanks very much for your support.

how to add new type to an existing class or object in asp.net mvc

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.

Convert an Entity to a extended class based on original class?

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.

Using AutoMapper and CRUD operations in MVC5

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.

set navigation property from different schema in entity framework

I'm coding in C# using entity framework 5 and I have a model Voucher that is something like this:
public class Voucher
{
public int Id { get; set; }
public int AppId { get; set; }
public virtual App {get; set;}
public int? TradeMemberId { get; set; }
public int FiscalPeriodId { get; set; }
}
I have configured this model as:
ToTable("Voucher", "acc");
So that it is mapped to:
[acc].[voucher]
my App property is from the same database but in another schema:
[prf].[App]
Now when ef tries to query and fill App navigation property it cannot find it in acc schema.how can i mark this property as prf schema as we do for models?any help is appreciated.
If you proper define schema using data annotation. EF should take care of this, I have done this before and never ran into any issues.
[Table("Voucher", Schema = "acc")]
public class Voucher {...}
and
[Table("App", Schema = "prf")]
public class App{...}

Categories

Resources