I have a viewmodel which needs data from two models person and address:
Models:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Gender { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public int Zip { get; set; }
public int PersonId {get; set; }
}
The Viewmodel is as such
public class PersonAddViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Street { get; set; }
}
I have tried several ways to get data into the viewmodel and pass it to the view. There will be multiple records returned to display.
My latest method is populating the view model as such:
private AppContexts db = new AppContexts();
public ActionResult ListPeople()
{
var model = new PersonAddViewModel();
var people = db.Persons;
foreach(Person p in people)
{
Address address = db.Addresses.SingleOrDefault(a => a.PersonId == p.Id)
model.Id = p.Id;
model.Name = p.Name;
model.Street = address.Street;
}
return View(model.ToList());
}
I get an error on the Address address = db... line of "EntityCommandExecutionException was unhandled by user code.
How can you populate a view model with multiple records and pass to a view?
Final Solution:
private AppContexts db = new AppContexts();
private AppContexts dbt = new AppContexts();
public ActionResult ListPeople()
{
List<PersonAddViewModel> list = new List<PersonAddViewModel>();
var people = db.Persons;
foreach(Person p in people)
{
PersonAddViewModel model = new PersonAddViewModel();
Address address = dbt.Addresses.SingleOrDefault(a => a.PersonId == p.Id)
model.Id = p.Id;
model.Name = p.Name;
model.Street = address.Street;
}
return View(list);
}
First, EntityCommandExecutionException errors indicates an error in the definition of your entity context, or the entities themselves. This is throwing an exception because it's found the database to be different from the way you told it that it should be. You need to figure out that problem.
Second, regarding the proper way to do this, the code you've shown should work if your context were correctly configured. But, a better way would be to use Navigational properties, so long as you want to get all related records and not specify other Where clause parameters. A navigational property might look like this:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Gender { get; set; }
public virtual Address Address { get; set; }
// or possibly, if you want more than one address per person
public virtual ICollection<Address> Addresses { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public int Zip { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
Then you would simply say:
public ActionResult ListPeople()
{
var model = (from p in db.Persons // .Includes("Addresses") here?
select new PersonAddViewModel() {
Id = p.Id,
Name = p.Name,
Street = p.Address.Street,
// or if collection
Street2 = p.Addresses.Select(a => a.Street).FirstOrDefault()
});
return View(model.ToList());
}
For displaying lists of objects, you could use a generic view model that has a generic list:
public class GenericViewModel<T>
{
public List<T> Results { get; set; }
public GenericViewModel()
{
this.Results = new List<T>();
}
}
Have a controller action that returns, say all people from your database:
[HttpGet]
public ActionResult GetAllPeople(GenericViewModel<People> viewModel)
{
var query = (from x in db.People select x); // Select all people
viewModel.Results = query.ToList();
return View("_MyView", viewModel);
}
Then make your view strongly typed, taking in your generic view model:
#model NameSpace.ViewModels.GenericViewModel<NameSpace.Models.People>
Related
I'm using ASP.NET Core 2.2. I have 2 models and a viewmodel which injects data to a view. I want to order results based on their productType. Let's make it clear
This is Product model
public class Product
{
public int ProductID { get; set; }
public int ProductName { get; set; }
public string ProductImage { get; set; }
public int ProductTypeID { get; set; }
[ForeignKey("ProductTypeID")]
public virtual ProductType ProductType{ get; set; }
}
This is ProductType model
public class ProductType
{
public int ProductTypeID { get; set; }
public int ProductTypeName { get; set; }
public string ProductTypeImage { get; set; }
public string ProductTypeDescription { get; set;
}
And finally this is DishesViewModel
public class DishesVM
{
public IEnumerable<ProductType> ProductType { get; set; }
public IEnumerable<Product> Product { get; set; }
}
In MyController I get data from DB then with automapper, map them to DishViewModel
public class HomeController : Controller
{
public IActionResult Dishes()
{
var productTypes= _context.ProductType.OrderBy(p =>p.ProductTypeID).ToList();
var products= _context.Products.OrderBy(p => p.ProductID).ToList();
var DishesVM = new DishesVM();
DishesVM.ProductType = _mapper.Map<IEnumerable<ProductType>>(productTypes);
DishesVM.Product = _mapper.Map<IEnumerable<Product>>(products);
}
}
Now in Dishes View I can have nested foreach
#model DishesViewModel
<div>
foreach(var pt in Model.ProductType)
{
<h1>pt.ProductTypeName</h1>
foreach(var p in Model.Product)
{
p.ProductName
}
}
</div>
This works fine but the only problem it has, is it returns all products. but I want each Product Category has its Products In front of its header. This is visual representation of what I want and what I have now.
This is what I want
But this is what I have
You have to filter your products by product type in each iteration. At the moment you just display all products for each product type:
<div>
foreach(var type in Model.ProductType)
{
//products which belong to the particular type
var productsForType = Model.Product.Where(x => x.ProductTypeID == type.ProductTypeID);
<h1>pt.ProductTypeName</h1>
foreach(var product in productsForType)
{
product.ProductName
}
}
</div>
This will give you a jump on the linq statement:
var list = productTypes.Where(x => x.ProductTypeID == 1).Select(x => new Product()
{
ProductImage = x.ProductTypeImage,
}).ToList();
You will need to decide on what to put into the where clause, I'm using ProductTypeID
I have the following model;
public class Object
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<double> Price { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public Nullable<int> Type { get; set; }
}
and i create a view model;
public class PlanBaseTypedObjects
{
public int? Id { get; set; }
public IEnumerable<Object> ObjectDetails { get; set; }
}
in my controller i did grouping as follows;
var model = model1.GroupBy(t => t.Type).Select(g => new PlanBaseTypedObjects
{
Id = g.Key,
ObjectDetails = g
});
How can i get the number of records that belong to a particular "Type"??
for an example for type 1 how many records under ObjectDetails??
and can i access the "objectDetails" directly??
for an example if i want to know the "Name" of Id=3 of Type 2.how can i get it??
You need to iterate on the grouping result to find the count for each one.
foreach(var group in model)
{
int groupCount = group.ObjectDetails.Count();
}
If you want to access the items in ObjectDetails you need another foreach:
foreach(var group in model
{
int groupCount = group.ObjectDetails.Count();
foreach(var item in group.ObjectDetails))
{
//do something with item
}
}
Title says it all, right now I have a single table that is populated from a linq query and I want to add more tables with different linq queries. I'm kinda lost on how would I do that..
I could probably do it if I create different views for each table but I want to have just one view for all. :D
Here's my code: (It's a table for "on going" projects)
Controller:
public ActionResult Index()
{
var project = from x in db.Projects
where x.Project_Status == "Ongoing"
select x;
return View(project);
}
Model:
public class Project
{
[Key]
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
}
View Model:
public class AdminHomeViewModel
{
public Project Ongoing { get; set; } //table for ongoing projects
public Project NYA { get; set; } //another table for Not Yet Assigned projects
public Employee Free { get; set; } //another table for free employees
public List<Project> OngoingList { get; set; }
public List<Employee> NYAList { get; set; }
public List<Employee> FreeList { get; set; }
}
You are confusing yourself with the different types of models. You should have a clear understanding between View-Model and Data-Model. You should always return View-Model to the View, and not the Data-Model. Data-Model are just the POCO classes which represents your data framework (in this case, each tables). There should be different Data Models for each of your table, which you must be having already based on your entity-framework approach (Code first, Model first or Database first). Then, prepare a single model for your view (as we can bind only one model to one view). Keep all the fields from different Data-Models that you need in that View and pass it along. See the approach below:
Data-Models
public class Project
{
[Key]
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
}
public class Employee
{
[Key]
public int Employee_Id { get; set; }
public string Employee_Name { get; set; }
public string Employee_Detail { get; set; }
}
View-Model
public class MyViewModel
{
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
public string Employee_Name { get; set; }
public string Employee_Detail { get; set; }
}
Or
public class MyViewModel
{
public Project proj { get; set; }
public Employee emp { get; set; }
}
Pass it to view as:
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
// You linq query to populate model goes here
return View(model);
}
Update:
From my understanding, you need something like this:
View-Model:
public class AdminHomeViewModel
{
public AdminHomeViewModel()
{
Ongoing = new List<Project>();
NYA = new List<Project>();
Free = new List<Employee>();
}
public List<Project> Ongoing { get; set; } //table for ongoing projects
public List<Project> NYA { get; set; } //another table for Not Yet Assigned projects
public List<Employee> Free { get; set; } //another table for free employees
}
Controller:
public ActionResult Index()
{
AdminHomeViewModel model = new AdminHomeViewModel();
var result1 = (from x in db.Projects
where x.Project_Status == "Ongoing"
select new Project(){
Project_Id = x.Project_Id ,
Project_Name = x.Project_Name,
... //all other assignments goes here
}).ToList();
var result2 = (from x in db.Projects
where x.Project_Status == "blah blah"
select new Project(){
Project_Id = x.Project_Id ,
Project_Name = x.Project_Name,
... //all other assignments goes here
}).ToList();
var result3 = (from x in db.Employee
where x.AnyCondition == "blah blah"
select new Employee(){
Employee_Id = x.Employee_Id ,
Employee_Name = x.Employee_Name,
... //all other assignments goes here
}).ToList();
model.Ongoing = result1;
model.NYA = result2;
model.Free = result3;
return View(model);
}
Developed MVC applciation and Code first approach, had three different class like
First Class
public class Users
{
[Key]
public int UserID { get; set; }
[DisplayName("User Name")]
public string UserName { get; set; }
...
public virtual ICollection<UserDetails> UserDetail { get; set; }
}
Second Class
public class UserDetails
{
[Key]
public int UserDetailsID { get; set; }
[ForeignKey("Users")]
public int UserID { get; set; }
[Required(ErrorMessage = "Please enter the first name")]
[DisplayName("First Name")]
public string FirstName { get; set; }
...
public virtual Users User { get; set; }
public virtual ICollection<UserAddress> UAddress { get; set; }
}
Three Class
public class UserAddress
{
[Key]
public int UserAddressID { get; set; }
[ForeignKey("UserDetailsID")]
public int UserDetailsID { get; set; }
[DisplayName("Address")]
public string Address { get; set; }
...
public virtual UserDetails UserDetail{ get; set; }
}
Need linq result like:
var _result = (from users in objDBMVCSamp.User
join details in objDBMVCSamp.UserDetail
on users.UserID equals details.UserID
select new
{
users.UserName,
users.Password,
details.FirstName,...
}).ToList();
and also need another result like:
var _result = (from users in objDBMVCSamp.User
join details in objDBMVCSamp.UserDetail
on users.UserID equals details.UserID
join address in objDBMVCSamp.UserAddress
on address.UserDetailsID equals details.UserDetailsID
select new
{
users.UserName,
details.FirstName,...
details.UserID,
address.Address,...
}).ToList();
Need to show those result in in view. it's really possible or any other way to show without create a class.
NOTE:
Above result are dynamic, so i though we not able to create a static class for those result. For this scenario what is best method to do this.
If you want to pass the value to view I'd rather suggest to create a ViewModel based upon what you want to show in view.
For example,
ViewModel
public class MyViewModel
{
public var MyValue1{get;set;}
public var MyValue2{get;set;}
public var MyValue3{get;set;}
...
...
}
in controller
public ActionResult MyControllerMethod(someType MyType)
{
// setViewmodels value here
}
then in view
#model MyViewModel
<h1>Model.MyValue1</h1> #*this will display value of MyValue1*#
Define a view model that represents what you want to display
public class UserVM
{
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailID{ get; set; }
public int UserID { get; set; }
}
In your controller
var _result = (from users in objDBMVCSamp.User
join details in objDBMVCSamp.UserDetail
on users.UserID equals details.UserID
select new UserVM
{
UserName = users.UserName,
Password = users.Password,
FirstName = details.FirstName,
LastName = details.LastName,
EmailID = details.EmailID,
UserID = details.UserID
}).ToList();
return View(_result)
View
#model List<UserVM>
#for(int i = 0; i < Model.Count; i++)
{
#Html.DisplayFor(m => m[i].UserName)
....
These are the ways of passing data from controller to view
1) You can use the dynamic object ViewBag to pass data from Controllers to Views.
Add the following to your controller:
ViewBag.MyList = myList;
Then you can acces it from your view:
#ViewBag.MyList
// e.g.#foreach (var item in ViewBag.MyList) { ... }
2) Using ajax service call
$.ajax(
{
type: "GET",
url: "../Home/GetData",
data: { function_param: values}
});
3) Use strongly typed classes
#model MyViewModel
//e.g.#foreach (var item in MyViewModel) { ... }
For more information, kindly refer this link
http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/various-ways-to-pass-data-from-controller-to-view-in-mvc/
When mapping a DAL object to DTO object I get an unexpected query.
I have some DAL objects:
public class MainDalObject
{
public Guid Id { get; set;}
public string Description { get; set; }
public ICollection<SubDalObject> Subs { get; set; }
}
public class SubDalObject
{
public Guid Id { get; set;}
public string Description { get; set; }
public MainDalObject Main { get; set; }
}
And my DTO classes:
public class MainObject
{
public Guid Id { get; set;}
public string Name { get; set; }
public IEnumerable<SubObject> Subs { get; set; }
}
public class SubObject
{
public Guid Id { get; set;}
public string Name { get; set; }
public MainDalObject Main { get; set; }
}
My MainObject controller contains a IQueryable method:
public IQueryable<MainObject> Get()
{
return (from m in Context.Get<MainDalObject>()
select new MainObject
{
Id = m.Id,
Name = m.Description,
Subs = m.Subs.Select(s => new SubObject
{
Id = s.Id,
Name = s.Name
}
});
}
This works fine, however the query is not optimal. When i trigger the query on /api/MainObject , I am not selecting the subitems at all. But when i look at the query it is selecting the subItems anyway.
However when I change the query to /api/MainObject?$select=Id,Name , the query is not selecting the SubObjects.
So what I am expecting is that somewhere in the WebApi framework, when no SelectExpandFilter is used, the responsewriter is doing a ToList(), without specifying the Select statement.
I am looking for the best place to fix this problem, I could probably set a select expand ODataQueryOption that could fake an select or expand call, but I am not sure if that is the way to go.
If someone else runs in this problem, this is what I have done to fix it. The select expand query should be derived from the edmmodel in the request context, but this is basically how it works.
public virtual IQueryable<TDTO> Get(ODataQueryOptions queryOptions)
{
if (queryOptions.SelectExpand == null)
{
var selectOption = new SelectExpandQueryOption("Id,Name", string.Empty, queryOptions.Context);
Request.SetSelectExpandClause(selectOption.SelectExpandClause);
}
return (from m in Context.Get<MainDalObject>()
select new MainObject
{
Id = m.Id,
Name = m.Description,
Subs = m.Subs.Select(s => new SubObject
{
Id = s.Id,
Name = s.Name
}
});
}