InvalidCastException in Entity Framework 7 - entity-framework

I'm using Visual Studio 2015, .Net framework 4.6.00079 to build a simple ASP.NET MVC 6 app:
model:
namespace RimconPensionModel.DataAccessLayer
{
[Table("BaseMortality")]
public class BaseMortality
{
[Key]
public int Id { get; set; }
public string BaseMortalitySet { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public float MortalityFactor { get; set; }
public DateTime EffectiveDate { get; set; }
public DateTime UpdateDate { get; set; }
public string UpdateUser { get; set; }
}
}
controller:
namespace RimconPensionModel.Controllers
{
public class BaseMortalityController : Controller
{
[FromServices]
public RimconPensionModelContext RimconPensionModelContext { get; set; }
[FromServices]
public ILogger<BaseMortalityController> Logger { get; set; }
public IActionResult Index()
{
return View(RimconPensionModelContext.BaseMortality.ToList());
}
}
}
view:
#model IEnumerable<RimconPensionModel.DataAccessLayer.BaseMortality>
#{
ViewBag.Title = "Base Mortality Data";
}
<h2>Base Mortality Data</h2>
<!--
<p>
<a asp-controller="BaseMortalityData" asp-action="Create">Create New</a>
</p> -->
<table class="table">
<tr>
<th>Base Mortality Sets</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.BaseMortalitySet)
</td>
</tr>
}
</table>
The app builds and starts, but when I invoke the controller, I get InvalidCastException on the "return View( . . . )" line of the controller. I've been googling for days (I'm a bit new to MVC and Entity Framework) with no luck. I think it probably has something to do with the datetime attributes. I bulk loaded the database table from a csv file with the datetime fields in YYYYMMDD format and the load went OK; the db table shows 1994-12-31 12:00:00 AM in the datetime fields. They are type datetime2(7), NOT NULL in the db.

Related

How do I load data that has a Many to Many relationship in ASP.NET Core?

I'm working on a many to many relationship in my ASP.NET Core application. From reading sources online I understand that this isn't officially supported yet and so an intermediary class is needed to make it all work.
The problem that I have is that once I have created my 'many to many' relationship, I don't know how best to display the data in my view and I'm struggling to traverse everything with this particular setup.
In my example there are two tables Part and Supplier, one Part can have many Supplier just as one Supplier can have many Part.
The first thing I did was create my two entity classes Part and Supplier
Part.cs
public class Part
{
public int PartId { get; set; }
public string PartName { get; set; }
public string PartNumber { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
public string Category { get; set; }
//Intermediate entity
public IList<PartSupplier> PartSupplier { get; set; }
}
Supplier.cs
public class Supplier
{
public int SupplierId { get; set; }
public string SupplierName { get; set; }
public string Website { get; set; }
public int? Telephone { get; set; }
public string Email { get; set; }
//Intermediate entity
public IList<PartSupplier> PartSupplier { get; set; }
}
You'll see from the above code that I've placed an intermediate table that creates this many to many relationship called PartSupplier
PartSupplier.cs
public class PartSupplier
{
public int PartId { get; set; }
public Part Part { get; set; }
public int SupplierId { get; set; }
public Supplier Supplier { get; set; }
}
At this point, I move to my data context and override the model building portion of the code to utilise the Fluent API.
Context.cs
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PartSupplier>().HasKey(ps => new { ps.PartId, ps.SupplierId });
base.OnModelCreating(builder);
}
public DbSet<Part> Parts { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<PartSupplier> PartSuppliers { get; set; }
Ok, so far so good. Now I need to display this information in a view, in this view specifically, I'd like to show all the parts and next to them all the available suppliers that part can be bought from.
I load the data in the following manner although, this is where I'm a little unsure how I should be structuring the query. Should I call the intermediary table or call Part and then include Supplier? I'm not sure
PartController.cs
public IActionResult Index()
{
var data = _context.Part.Include(p => p.Supplier);
return View(data);
}
Index.cshtml
#model IEnumerable<Part>
<div class="container">
<div class="row">
<div class="col">
<h2>Parts</h2>
<a asp-action="Create" asp-controller="Parts">Add Part</a>
<table class="table">
#foreach (var part in Model)
{
<tr>
<td>
<a asp-action="Edit" asp-route-id="#part.PartId" asp-controller="Part">#part.PartName</a>
</td>
<td>
#part.PartNumber
</td>
<td>
#part.ShortDescription
</td>
<td>
...I'd like to show the suppliers here...
</td>
</tr>
}
</table>
</div>
</div>
</div>
I think I've almost got it but really would like some assistance getting over this final hurdle. Many thanks
A cascade relationship is missing in Index.cshtml, you need to add ThenInclude.
public IActionResult Index()
{
var data = _context.Parts.Include(x => x.PartSupplier)
.ThenInclude(y=>y.Supplier);
return View(data);
}
Then in Index.cshtml.
<table class="table">
#foreach (var part in Model)
{
<tr>
<td>
<a asp-action="Edit" asp-route-id="#part.PartId" asp-controller="Part">#part.PartName</a>
</td>
<td>
#part.PartNumber
</td>
<td>
#part.ShortDescription
</td>
<td>
<ul>
#* Here has been changed. *#
#foreach(var supplier in part.PartSupplier)
{
<li>#supplier.Supplier.SupplierName #supplier.Supplier.Website</li>
}
</ul>
</td>
</tr>
}
</table>
In database, I insert some data, such as Part and PartSupplier.
Result.

Eager Loading EF

I'm an absolute beginner on EF, and I am stuck at what probably is very simple.
I have 2 tables/classes:
Toys and Brands
public class Toys
{
public int Id { get; set; }
public string Name { get; set; }
public int BrandId { get; set; }
}
public class Brands
{
public int BrandId { get; set; }
public string BrandName { get; set; }
}
My DBContext file:
public class SOT : DbContext
{ public SOT(): base("name=SOT")
{
public virtual DbSet<Brands> brands; set; }
public virtual DbSet<Toys> toys { get; set; }
}
When I add a record, the BrandId goes to the BrandId field in the Toys table.
I want to display in the view the Name of the toy, and the Brand Name. Now I get toy name and Brand Id
In my controller, on the Index Action:
public ViewResult Index()
{
/// this is where I am sooo stuck.....
var toy = _context.Toys.Include(c => c.Brands).ToList();
return View(toy);
}
The view:
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.BrandName)
</td>
What am I doing wrong?
maybe this will helps you, If you make a relation between Toy and Brand Table
var q = _context.Toys
.Select(q_toys =>
new
{
q_toys.Name,
q_toys.Brand.BrandName
}).ToList();

asp.net mvc 5 one model with different format in view

I'm a newbie in MVC. Sorry all professionals for this question.
I have a model like:
public class Student
{
public int ID { get; set; }
public int Number{ get; set; }
public string Name{ get; set; }
public string Surname{ get; set; }
public bool IsStudentNow { get; set; }
}
In my "paged" index.cshtml page, i call this model like this;
#model PagedList.IPagedList<WebProj.Models.Student>
It's ok for the paging or foreach statement but I can't access the model property in HTML helper.
For example;
I can't access this property;
#Html.DisplayNameFor(model=> model.Number)
#Html.DisplayNameFor(model=> model.Name)
But I can access this;
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
So, I want to access model properties in HTML helper. Don't prefer to use view model.

How do I specify which field should be displayed with MVC Scaffolding

I am creating an MVC4 application using EF Code First database. I am working with some foreign key declarations. I wish to use define the field to display in the dropdown in the scaffolding in the model declarations. For instance:
My simplified model declaration is as follows:
public class Contact
{
public int ID { get; set; }
public string Prefix { get; set; }
public string First { get; set; }
public string Middle { get; set; }
public string Last { get; set; }
public string FullName
{
get { return (Last + ", " + First + " " + Middle).Trim(); }
}
}
public class Role
{
public int ID { get; set; }
public string RoleName { get; set; }
public string RoleDescription { get; set; }
}
public class RoleAssignment
{
[Key]
public int ID { get; set; }
[ForeignKey("Contact")]
public int Contact_ID { get; set; }
public virtual Contact Contact { get; set; }
[ForeignKey("Role")]
public int Role_ID { get; set; }
public virtual Role Role { get; set; }
}
I generate the standard scaffolding and the edit .cshtml looks like this:
<fieldset>
<legend>RoleAssignment</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Contact_ID, "Contact")
</div>
<div class="editor-field">
#Html.DropDownList("Contact_ID", String.Empty)
#Html.ValidationMessageFor(model => model.Contact_ID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Role_ID, "Role")
</div>
<div class="editor-field">
#Html.DropDownList("Role_ID", String.Empty)
#Html.ValidationMessageFor(model => model.Role_ID)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
However, the dropdown uses the "Prefix" field for the drop down and display. I want it to use the "FullName" field. How do I designate this in the Contact model declaration? (I know how to do this my modifying the .cshtml code, but I want it to work with pure generated code.)
OK. Figured it all out. To specify a custom naming field for your table for drop-downs, use the "DisplayColumn" on the model class, and then use the "NotMapped" attribute to prevent the custom display field from being mapped to the database, and give it a setter that does nothing:
[DisplayColumn("FullName")]
public class Contact
{
public int ID { get; set; }
[NotMapped]
[Display(Name = "Full Name")]
public string FullName
{
get { return (Last + ", " + First + " " + Middle).Trim(); }
}
public string Prefix { get; set; }
public string First { get; set; }
public string Middle { get; set; }
public string Last { get; set; } }
I have a partial answer to my question:
Adding the "DisplayColumn" attribute to the model class allows you to change the display field for the scaffolding as follows:
[DisplayColumn("First")]
public class Contact
{
public int ID { get; set; }
[Display(Name = "Full Name")]
public string FullName
{
get { return (Last + ", " + First + " " + Middle).Trim(); }
}
public string Prefix { get; set; }
public string First { get; set; }
}
However, it does not work with the read only field "FullName". Still trying to figure that one out...

MVC4 Entity Framework 5 Many-To-Many Save Entity to Database

Hi I've been stuck to long on this problem. I've looked at a lot of examples but i cant find what im looking for. Any help is appreciated.
I use the Code-First approach.
I've enabled migration and the database is fine [Student] - [StudentCourse] - [Course].
Scenario: I have two entites -> Student
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Course> Courses { get; set; }
}
And Course
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual List<Student> Students { get; set; }
}
Nothing fancy about that... Ive created a ViewModel ->
public class StudentCourseViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; }
}
View:
#model Project.Web.Models.StudentCourseViewModel #{
ViewBag.Title = "Edit"; }
Edit
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Student</legend>
#Html.HiddenFor(model => model.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Courses)
</div>
<div class="editor-field">
#for (int i = 0; i < Model.Students.Count(); i++)
{
<div style="border: dotted 1px; padding: 5px; margin: 10px;">
#Html.HiddenFor(s => s.Students[i].Id)
#Html.LabelFor(s => s.Students[i].Name[i + 1])
#Html.EditorFor(s => s.Students[i].Name)
</div>
}
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset> }
Controller Action:
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
var course = db.Courses.Find(model.CourseId);
course.Name = model.CourseName;
course.Description = model.CourseDescription;
course.Students = model.Students;
if (ModelState.IsValid)
{
db.Entry(course).State = System.Data.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
(Maby this is were i go wrong...)
Anyway, I want to create a new Student with optional many courses (textboxes -> courseName)
How should i do this?
The main issue is that i always get null values (student is fine, List of courses = NULL) back from my view [httpPost]Create -action.
I'm in need of guidance how to make this approach possible.
Thx J!
Your entities are not setup correctly for a many-to-many relationship. You need another entity to handle the many-to-many mapping. It would look something like this.
public class StudentsToCourses
{
public int StudentId {get; set;}
public int CourseId {get; set;}
public virtual Student Student {get; set;}
public virtual Course Course {get; set;}
}
Then your student model should be changed to this.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<StudentsToCourses> Courses { get; set; }
}
And your coursed model changed to this.
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual List<StudentsToCourses> Students { get; set; }
}
You also need to setup the foreign key relationship using the Fluent API. It would look something like this.
public class StudentsToCoursesConfiguration : EntityTypeConfiguration<StudentsToCourses>
{
internal StudentsToCoursesConfiguration ()
{
this.HasKey(p => new {p.StudentId, p.CourseId});
this.HasRequired(p => p.Student)
.WithMany(p => p.Courses)
.HasForeignKey(p => p.StudentId);
this.HasRequired(p => p.Course)
.WithMany(r => r.Students)
.HasForeignKey(p => p.CourseId);
}
}