MVC different models errors - asp.net-mvc

I have trying to use a MetadatType model, but getting an error:
.edmx model/order.cs:
public partial class ORDER
{
public int Order_Number { get; set; }
public string Order_Type { get; set; }
}
metadatatype model:
MetadataType(typeof(ORDERMetadata))]
public partial class ORDER
{
// Note this class has nothing in it. It's just here to add the class-level attribute.
}
public class ORDERMetadata
{
[Display(Name = "Order Number")]
public Nullable<int> Order_Number { get; set; }
[Display(Name = "Order Type")]
public string Order_Type { get; set; }
}
Controller:
List<ORDERMetadata> result = db.ORDERS.
Where(p => p.Order_Number == id).
Select(x => new ORDERMetadata
{
Order_Number = x.Order_Number,
Order_Type = x.Order_Type
}).ToList();
Error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Mvc5_Whitby.Models.ORDERMetadata]', but this dictionary requires a model item of type 'Mvc5_Whitby.Models.ORDERMetadata'

In the top of your view you probably have this:
#model Mvc5_Whitby.Models.ORDERMetadata
When you probably want this, to match what you are passing to the view:
#model IEnumerable<Mvc5_Whitby.Models.ORDERMetadata>

You haven't posted you view but it must have
#model Mvc5_Whitby.Models.ORDERMetadata
but you are passing it a collection (the result of your query). Either change the query to return a single item (e.g. .FirstOrDefault(), not .List()) or change the view to
#model List<Mvc5_Whitby.Models.ORDERMetadata>
depending on what you want

Related

how to add dropdownlistfor(dynamic object)

I have class include the following objects
public class ProductViewer
{
public J_Items Item { get; set; }
public List<J_ItemsImages> lstItemImages { get; set; }
}
how can i add DropDownListFor Item.ItemName
J_Items definition
public int ID { get; set; }
public string ItemName { get; set; }
public string ItemShortDesc { get; set; }
public string ItemLongDesc { get; set; }
#Html.DropdownlistFor(m => m.Item.ItemName)
Where m is your ProductViewer class, of course that should be made in to a viewmodel.
You can use the first argument of the Html.DropDownListFor() helper method to designate which property you want to bind to and then use the second to supply a collection to populate the actual drop down list with :
<!-- This would bind to the ItemName property, but would populate the list with
the contents of your lstItemImages property -->
#Html.DropDownListFor(m => m.Item.Name, new SelectList(Model.lstItemImages, "Name", "Name"))
Likewise, if you had a collection of values on your J_Items class, you could access those in the second parameter as well:
#Html.DropDownListFOr(m => m.Item.Name, new SelectList(Model.Item.SomeCollection,"Value,"Text")
This assumes that your parent ProductViewer class would be passed into the view.

Reference to the enum from model in Index view

I have a trouble with reference to my enum from model in Index view.
Here is my model's code:
public enum UnitOfMeasure {
Item,
Kilogram,
Liter, }
public class Product {
public Product() {
ProductOccurences = new List<ProductOccurence>(); }
[Key]
public int ProductId { get; set; }
public int ProductPhotoId { get; set; }
public UnitOfMeasure? UnitOfMeasure { get; set; }
public string ProductDescription { get; set; }
public virtual ProductPhoto Photo { get; set; }
public virtual ICollection<ProductOccurence> ProductOccurences { get; set; } }
In Index view I have search fields for filtering specific results. You can also search for UnitOfMeasure value (I use #Html.EnumDropDownListFor) - but I can't refer directly to the enum field from my model - because my view is strongly typed:
#model IEnumerable<Models.Product>
To show this field with the values of the selection I use the trick:
#Html.EnumDropDownListFor(model => model.FirstOrDefault().UnitOfMeasure, "Select unit of measure")
but it's terrible and ugly solution - also with unwanted value loaded by default.
What is the most elegant way to solve this issue in my situation?
You can use EnumHelper like this:
#Html.DropDownList("UnitOfMeasure", EnumHelper.GetSelectList(typeof(UnitOfMeasure)))
OR
You can do like this for strongly typed view:
#{ // you can put the following in a back-end method and pass through ViewBag
var selectList = Enum.GetValues(typeof(UnitOfMeasure))
.Cast<UnitOfMeasure>()
.Select(e => new SelectListItem
{
Value = ((int)e).ToString(),
Text = e.ToString()
});
}
#Html.DropDownListFor(m => m.UnitOfMeasure, selectList)

ModelState.IsValid with DTO and Entity Framework code first

ASP.NET 4.5, MVC 5, EF6 code first
I'm a newbie and probably asking something long-known but I couldn't find solution on the web, probably because I don't know correct terminology to formulate this question.
To simplify things, let's say I have two model classes Teacher and Kid; One kid can be assigned only to one teacher, but one teacher can have many kids. As I'm using code first, my database is constructed from these model classes:
public class Kid
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Teacher { get; set; }
}
public class Teacher
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual ICollection<Kid> Kids { get; set; }
}
Now, I need to have a view for adding new kid with:
Textbox for Kid's name;
Dropdown with list of Teachers
So, I'm creating a data transfer object, specifically for that view:
public class AddNewKidViewDTO
{
public IEnumerable<SelectListItem> Teachers { get; set; }
public int SelectedTeacherId { get; set; }
public Kid Kid { get; set; }
}
I also have a method for populating IEnumerable Teachers:
public AddNewKidViewDTO LoadTeachersForDropDownList()
{
... //get the list of Teachers
AddNewKidViewDTO addNewKidViewDTO = new AddNewKidViewDTO();
List<SelectListItem> selectListItems = new List<SelectListItem>();
foreach (teacher in Teachers)
{
selectListItems.Add (new SelectListItem
{
Text = teacher.Name.ToString(),
Value = teacher.Id.ToString()
});
}
addNewKidViewDTO.Teachers = selectListItems;
return addNewKidViewDTO;
}
and in the view AddNewKid.cshtml
<form>
#Html.LabelFor(model => model.Kid.Name)
#Html.TextBoxFor(model => model.Kid.Name, new {id ="Name"}
<br/>
#Html.LabelFor(model => model.Kid.Teacher)
#Html.DropDownListFor(model => model.SelectedTeacherId, Model.Teachers)
</form>
Form gets submitted and in the controller I get my populated AddNewKidViewDTO model:
[HttpPost]
public ActionResult SaveNewKid (AddNewKidViewDTO addNewKidViewDTO)
{
if (ModelState.IsValid)
{
//here is where the problem comes
}
}
ModelState.IsValid in my case will always return false.
Because when it starts validating AddNewKidViewDTO.Kid, Teacher is compulsory field but in my addNewKidViewDTO model it's null. I have the necessary teacher Id contained in addNewKidViewDTO.SelectedTeacherId only.
My question is, what is an elegant way to validate my model before passing to my inner business logic methods?
Any help is appreciated.
There are multiple possible solutions:
Changing your AddNewKidViewDTO and decorating it with the DataAnnotaions for validation:
public class AddNewKidViewDTO
{
public IEnumerable<SelectListItem> Teachers { get; set; }
[Range(1, 2147483647)] //Int32 max value but you may change it
public int SelectedTeacherId { get; set; }
[Required]
public string KidName { get; set; }
}
Then you can create Kid object manually in case that your model valid.
UPDATE (to address your comment)
If you use this approach your action will look like this:
[HttpPost]
public ActionResult SaveNewKid (AddNewKidViewDTO addNewKidViewDTO)
{
if (ModelState.IsValid)
{
using (var dbContext = new yourContext())
{
var teacher = dbContext.Teachers.FirstOrDefault(t=>t.id == addNewKidViewDTO.SelectedTeacherId );
if(teacher == default(Teacher))
{
//return an error message or add validation error to model state
}
//It is also common pattern to create a factory for models
//if you have some logic involved, but in this case I simply
//want to demonstrate the approach
var kid = new Kid
{
Name = addNewKidViewDTO.KidName,
Teacher = teacher
};
dbContext.SaveChanges();
}
}
}
Write a custom model binder for AddNewKidViewDTO that will initialize Teacher property in Kid object so once you actually use Model.IsValid the property will be initialized.

MVC View Page not showing Value

My Model class is below:
I have three classes two of them are partial class and one is simple class.......
[MetadataType(typeof(RegistrationMetaData))]
public partial class Registration
{
}
public class RegistrationMetaData
{
public string Id { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public virtual ICollection<Images> Images { get; set; }
}
[MetadataType(typeof(ImagesMetaData))]
public partial class Images
{
}
public class ImagesMetaData
{
public string id { get; set; }
public string stuid { get; set; }
public string stuimg1 { get; set; }
public virtual ICollection<Registration> Registrations { get; set; }
}
public class EmployeeViewModel
{
public string Name { get; set; }
public string stuimg1 { get; set; }
}
public class NotificationViewModel
{
public Registration registration { get; set; }
public Notification notification { get; set; }
public IEnumerable<EmployeeViewModel> EmployeeViewModel { get; set; }
public Images images { get; set; }
}
Then I have used the below code in controller class to fetch Images record with foreign key in registration table.
IEnumerable<EmployeeViewModel> model1 = null;
model1 = (from e in db.Registrations
join j in db.Images on e.Id equals j.stuid
where e.Email == Email
select new EmployeeViewModel
{
Name = e.Name,
stuimg1 = j.stuimg1
}).ToList();
var mixmodel = new NotificationViewModel
{
EmployeeViewModel = model1
};
return View(mixmodel);
Atlast my view page is like this:-
#model IEnumerable<Amar.Models.NotificationViewModel>
#foreach (var item in Model)
{
#item.EmployeeViewModel.stuimg1
}
But I am getting an error
System.Collections.Generic.IEnumerable' does not contain a definition for 'stuimg1' and no extension method 'stuimg1' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
I have gone through debugging my code is fine till controller page...but from view page the values are not showing.I think there is some little mistake i have made...
Please someone help me..I am trying to solve this problem since 2 weeks....
I want to fetch data from one more class on the same view page thats why I am using NotificationViewModel class.
return View(mixmodel);
Your view is expecting a type of IEnumerable<NotificationViewModel> but mixmodel is just a NotificationViewModel
I'm not seeing what you are achieving by having this additional class 'NotificationViewModel'. If your view were to be changed to expect an IEnumerable<EmployeeViewModal> you could pass in model1 directly.
You could then change your view to:
#foreach (var item in Model)
{
#item.stuimg1
}
If you do indeed need this extra layer of abstraction for some other part of your view then you need to sit and think about what is a a single instance and what is a list. Try drawing it if you're having trouble.

How can I get a property as an Entity in Action of Asp.Net Mvc?

i'd like to know how can I get a property like an entity, for example:
My Model:
public class Product {
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
View:
Name: <%=Html.TextBoxFor(x => x.Name) %>
Category: <%= Html.DropDownList("Category", IEnumerable<SelectListItem>)ViewData["Categories"]) %>
Controller:
public ActionResult Save(Product product)
{
/// produtct.Category ???
}
and how is the category property ? It's fill by the view ? ASP.Net MVC know how to fill this object by ID ?
Thanks!
This is one of the reasons why it's bad to bind directly to entities. Consider
public class ProductForm {
public int Id { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
}
public ActionResult Save(ProductForm form)
{
var product = new Product
{
Id = form.Id,
Name = form.Name,
Category = database.GetCategory(form.CategoryId)
};
}
In case of view models as above, it may be OK to use custom model binders to automatically get entities by Id from database. See here for sample implementation (in S#arp Architecture) that binds IDs to entities from database. But I think for now you better go with simpler implementation like above.
You can also use AutoMapper to simplify form->entity mapping.

Resources