Using Include in Entity Framework Core - asp.net-mvc

Question: How and where the extension method "Include", used in the Index() action method, in the following PostController used in the Inxex.cshtml view shown below? As I understand _context.Posts.Include(p => p.Blog) means include all posts that relate to blogs table. But I don't see use of blog class or blogId property in the Index.cshtml view below?
Background: In an ASP.NET MVC Core - Code First project I'm following this ASP.NET official site tutorial where they have following Model classes for Blog (parent) and Post (child). I then created a controller (shown below) using MVC Controller with Views, using Entity Framework wizard where I selected Post model in the Model dialogbox.:
Model:
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFGetStarted.AspNetCore.NewDb.Models
{
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
PostController:
public class PostsController : Controller
{
private readonly BloggingContext _context;
public PostsController(BloggingContext context)
{
_context = context;
}
// GET: Posts
public async Task<IActionResult> Index()
{
var bloggingContext = _context.Posts.Include(p => p.Blog);
return View(await bloggingContext.ToListAsync());
}
}
Index.cshtml view for Index() action in PostController:
#model IEnumerable<ASP_Core_Blogs.Models.Post>
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Content)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.PostId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.PostId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.PostId">Delete</a>
</td>
</tr>
}
</tbody>
</table>

Since you're not accessing the Blog property, it's better not to use Include(p => p.Blog). This will add an extra join that isn't required.
However, if you'll reference it in each table row, then it's preferred to include it to avoid lazy loading issues.

Related

How to Retrieve data from multiple table in a single view in asp.net core 6 mvc code first approach

I have Course and Student model with foreign key. I want to show student details in index view with CourseName and CourseId.
This is Course Model
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace JECRC.Models
{
public class Course
{
[Key]
public int CourseId { get; set; }
[Required]
public string CourseName { get; set; }
public List<Student> Students { get; set; }
public Faculty Faculty { get; set; }
}
}
This is Student Model
using System.ComponentModel.DataAnnotations;
namespace JECRC.Models
{
public class Student
{
[Key]
public int StudentId { get; set; }
[Required]
public string StudentName { get; set; }
[Required]
public string Class { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
}
}
This is my Student Controller
using JECRC.Context;
using JECRC.Models;
using Microsoft.AspNetCore.Mvc;
namespace JECRC.Controllers
{
public class StudentController : Controller
{
private readonly DataContext dc;
public StudentController(DataContext dc)
{
this.dc = dc;
}
public IActionResult Index()
{
IEnumerable<Student> students = dc.Students;
return View(students);
}
}
}
and this is my Index View
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.StudentId)
</th>
<th>
#Html.DisplayNameFor(model => model.StudentName)
</th>
<th>
#Html.DisplayNameFor(model => model.Class)
</th>
#Html.DisplayNameFor(model => model.Course.CourseName)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.StudentId)
</td>
<td>
#Html.DisplayFor(modelItem => item.StudentName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Class)
</td>
<td>
#Html.DisplayFor(modelItem => item.Course.CourseName)
</td>
</tr>
}
</tbody>
</table>
I know I have to join these two table Student and Course in Student controller but i don't know how to do it, please help me to solve this problem,I will be very thank full for this.

Code First Using Entity Framework Core and ViewModel

I am new to MVC and Entity Framework and have decided to use the Code First approach using ViewModels.
I have tried many different tutorials but no one that i've tried has used Code First in EF Core with ViewModels.
My Models
public class Intermediary
{
public int IntermediaryID { get; set; }
public string RegisteredName { get; set; }
public string TradingName { get; set; }
public int Registration { get; set; }
public int VATNumber { get; set; }
public int FSPNumber { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public ICollection<Branch> Branches { get; set; }
}
public class Branch
{
public int BranchID { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public Intermediary Intermediary { get; set; }
}
My ViewModel
public class IntermediariesViewModel
{
public int ID { get; set; }
public Intermediary Intermediary { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
}
My Data Context Class
public class BizDevHubContext : DbContext
{
public BizDevHubContext(DbContextOptions<BizDevHubContext> options) : base(options)
{
}
public DbSet<Intermediary> Intermediaries { get; set; }
public DbSet<Branch> Branches { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Intermediary>().ToTable("Intermediary");
modelBuilder.Entity<Branch>().ToTable("Branch");
}
}
My Initializer Class
public static class DbInitializer
{
public static void Initialize(BizDevHubContext context)
{
context.Database.EnsureCreated();
if (context.Intermediaries.Any())
{
return; // DB has been seeded
}
var intermediaries = new Intermediary[]
{
new Intermediary{RegisteredName="Carson",TradingName="Alexander",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Meredith",TradingName="Alonso",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Arturo",TradingName="Anand",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Gytis",TradingName="Barzdukas",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Yan",TradingName="Li",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Peggy",TradingName="Justice",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Laura",TradingName="Norman",CreatedDate=DateTime.Now,CreatedBy="System"},
new Intermediary{RegisteredName="Nino",TradingName="Olivetto",CreatedDate=DateTime.Now}
};
foreach (Intermediary i in intermediaries)
{
context.Intermediaries.Add(i);
}
context.SaveChanges();
var branches = new Branch[]
{
new Branch{Name="Bloemfontein",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Cape Town",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Durban",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Nelspruit",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Johannesburg",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Port Shepstone",CreatedDate=DateTime.Now,CreatedBy="System"},
new Branch{Name="Pretoria",CreatedDate=DateTime.Now,CreatedBy="System"}
};
foreach (Branch b in branches)
{
context.Branches.Add(b);
}
context.SaveChanges();
}
}
This all seems to work fine and the database gets created ok, but I am stuck now trying to create the Controller and Views
I managed to do it with a single model but cannot seem to get it right putting the entire viewmodel.
My Controller
using BizDevHub.ViewModels;
public async Task<IActionResult> Index()
{
return View(await _context.Intermediaries.ToListAsync());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID")] Intermediaries Intermediaries)
{
if (ModelState.IsValid)
{
_context.Add(Intermediaries);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(Intermediaries);
}
The same goes for my views
My View
#model IEnumerable<BizDevHub.Models.Intermediary>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.RegisteredName)
</th>
<th>
#Html.DisplayNameFor(model => model.TradingName)
</th>
<th>
#Html.DisplayNameFor(model => model.Registration)
</th>
<th>
#Html.DisplayNameFor(model => model.VATNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.FSPNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.CreatedDate)
</th>
<th>
#Html.DisplayNameFor(model => model.CreatedBy)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.RegisteredName)
</td>
<td>
#Html.DisplayFor(modelItem => item.TradingName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Registration)
</td>
<td>
#Html.DisplayFor(modelItem => item.VATNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.FSPNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedBy)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.IntermediaryID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.IntermediaryID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.IntermediaryID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
What am I doing wrong?
Thanks in advance.
#Anonymous is correct that you need to redesign the View model. There is no point having a view model if you are just assigning entities as the properties, the purpose of the view model is to separate you controller and view from your datacontext
public class IntermediariesViewModel
{
public int Id { get; set; }
public string RegisteredName { get; set; }
public string TradingName { get; set; }
//other properties
IEnumerable<BranchViewModel> Branches { get; set; }
}
public class BranchViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
View:
#model IEnumerable<BizDevHub.Models.IntermediariesViewModel>
EDIT : but how would you combine both view models in a single controller and view with methods like Index, Edit and Delete?
Controller:
public IActionResult Update([FromBody]IntermediariesViewModel model)
{
var intermediary = _context.Intermediaries.Where(x=> x.IntermediaryID == model.Id).FirstOrDefault();
if(intermediary != null)
{
intermediary.RegisteredName = model.RegisteredName ;
//rest of updates
_context.SaveChanges();
}
}
public IActionResult Delete([FromBody]int IntermediariesId)
{
var intermediary = _context.Intermediaries.Where(x=> x.IntermediaryID == IntermediariesId).FirstOrDefault();
if(intermediary != null)
{
_context.Intermediaries.Remove(intermediary);
_context.SaveChanges();
}
}
View:
#Html.DisplayNameFor(model => model.RegisteredName)
#Html.DisplayNameFor(model => model.BranchViewModel[0].Name)// first branch name, you may want to iterate

Web API en ASP.NET with OData - Model issue

I have a Web API in ASP.NET with OData and I can consume from the service, but the view doesn't print a table. I'm starting with .NET and with MVC.
ERROR:
In View: #foreach (var item in Model)
System.NullReferenceException: Object reference not set to an instance of an object.
I have been seeing other similar doubts, which were solved by passing the model in the ActionResult, but I don't know how to do this with OData. Thanks!
MODEL
namespace exchange_rates
{
using System;
using System.Collections.Generic;
public partial class CurrentValue
{
public int Id { get; set; }
public System.DateTime Date { get; set; }
public string Currency { get; set; }
public double Rate { get; set; }
}
}
CONTROLLER
namespace exchange_rates.Controllers
{
public class CurrentValuesController : ODataController
{
private db_test_bce_Entities db = new db_test_bce_Entities();
// GET: odata/CurrentValues
[EnableQuery]
public IQueryable<CurrentValue> GetCurrentValues()
{
return db.CurrentValues;
}
// GET: odata/CurrentValues(5)
[EnableQuery]
public SingleResult<CurrentValue> GetCurrentValue([FromODataUri] int key)
{
return SingleResult.Create(db.CurrentValues.Where(currentValue => currentValue.Id == key));
}
}
}
WebApiConfig.cs
namespace exchange_rates
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<CurrentValue>("CurrentValues");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
}
}
}
VIEW
#model IEnumerable<exchange_rates.CurrentValue>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>CurrenciesTable</title>
</head>
<body>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Date)
</th>
<th>
#Html.DisplayNameFor(model => model.Currency)
</th>
<th>
#Html.DisplayNameFor(model => model.Rate)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Currency)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rate)
</td>
</tr>
}
</table>
</body>
</html>
EDIT
I was trying return my list to the view from the OData Controller and this didn't work for me. Finally, I solved by returning the list from the MVC Controller:
HomeController
public class HomeController : Controller
{
private db_test_bce_Entitiesdb = new db_test_bce_Entities();
// GET: Home
public ActionResult Index()
{
var currencies = db.CurrentValues.OrderBy(field => field.Acronym).ToList();
return View(currencies);
}
}
namespace exchange_rates
{
using System;
using System.Collections.Generic;
public class MyViewModel
{
public List<CurrentValue> MyListOfCurrentValues {get;set;}
}
public class CurrentValue
{
public int Id { get; set; }
public System.DateTime Date { get; set; }
public string Currency { get; set; }
public double Rate { get; set; }
}
}
then in the view
#foreach (var item in Model.MyListOfCurrentValues)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Currency)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rate)
</td>
</tr>
}
I'm not familiar with OData... but my controller would look like the below.
public ActionResult MyViewName()
{
var model = new MyViewModel
{
MyListOfCurrentValues = //Value from data source
}
return View("MyViewName", model);
}

Filtering a view with 2 tables with same database tables

I have created a view which contains 2 tables.
What I want is to filter each table data according to their transaction type for example table1 should show only Payables List and table2 should show only Reciveable List.
here is the code
Note When I navigate to the view server shows me The resource cannot be found.other views are fine. here is my code.
My project has BOL(EF Model) BLL(Business object) DAL(Data Access layer) and my main Mvc project
View
#model shinwari_traders.Areas.Shinwari.Models.ADetailsVm
#{
ViewBag.Title = "Index";
}
<h2>AccountDetails</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table id="Payables" class="table">
<tr>
<th>
Date
</th>
<th>
Discription
</th>
<th>
Amount
</th>
</tr>
#foreach (var item in Model.Payables)
{
<tr>
<td>
#item.Date
</td>
<td>
#item.Discription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
<table id="Reciveables" class="table">
<tr>
<th>
Date
</th>
<th>
Discription
</th>
<th>
Amount
</th>
</tr>
#foreach (var item in Model.Reciveables)
{
<tr>
<td>
#item.Date
</td>
<td>
#item.Discription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
Controller
public class AccountDetailsController : Controller
{
private TransictionBs objbs;
public AccountDetailsController()
{
objbs = new TransictionBs(int accountid);
}
// GET: Shinwari/AccountDetails
public ActionResult Index(int accountid)
{ var v= new ADetails();
v.Payable = objbs.GetALL().Where(p => p.AId==accountid&& p.tbl_TransictionType.Type.Contains("Payable"));
v.Reciveable = objbs.GetALL().Where(r => r.AId==accountid && r.tbl_TransictionType.Type.Contains("Reciveable"));
return View(v);
}
}
}
Model Class
public class ADetailsVm
{
public List<BOL.tbl_Transiction> Payables { get; set; }
public List<BOL.tbl_Transiction> Reciveables { get; set; }
}
DatabaseTable
public partial class tbl_Transiction
{
public int TId { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public Nullable<int> AId { get; set; }
public string Discription { get; set; }
public Nullable<double> PKR { get; set; }
public Nullable<double> Rate { get; set; }
public Nullable<double> Amount { get; set; }
public Nullable<int> TTId { get; set; }
public virtual tbl_Accounts tbl_Accounts { get; set; }
public virtual tbl_TransictionType tbl_TransictionType { get; set; }
}
You need a new view model with 2 collection properties one for each collection.
public class AccountDetailsVm
{
public List<BOL.tbl_Transiction> Reciveable {set;get;}
public List<BOL.tbl_Transiction> Payable {set;get;}
}
And in your GET action, create an object of this view model, fill these 2 properties.
public ActionResult Index(int accountid)
{
var v=new AccountDetailsVm();
//Load both the collection properties
v.Payables = objbs.GetALL()
.Where(p => p.AId==accountid && p.tbl_TransictionType.Type.Contains("Payable"));
v.Reciveable = objbs.GetByID(accountid).tbl_TransictionType.Type.Contains("Reciveable");
return View(v);
}
And your view is bound to the new view model. I just added the minimal code here. You can convert the rendering to a table.
#model AccountDetailsVm
<h1>Reciveable</h1>
#foreach(var item in Model.Reciveable)
{
<p>#item.Amount</p>
}
<h1>Payable</h1>
#foreach(var item in Model.Payable)
{
<p>#item.Amount</p>
}

ASP MVC - How use two models in one single view

I have a web page that have two task
1) add new products
2) display existing products in a table (refer below image)
also i have two classes for each above task
for display existing details and save new product
public class VMProduct
{
public List<Product>ProductList { get; set; }
}
public class Product
{
public String ProductID { get; set; }
public String ProductName { get; set; }
public String Uom1 { get; set; }
public String Uom2 { get; set; }
public String ProductCategoryID { get; set; }
}
my problem is i can display data by using VMProduct.ProductList model but how i can save new product items using "product" model ?
how can i use both Models in One view?
if i use "product" model's properties in VMProduct model it is duplication codes right?
can anyone have a Solution for this?
thanks in advance
It looks like VMProduct is already a custom view model (I'm mostly guessing by its name), so just add a property to it of the type you need:
public class VMProduct
{
public List<Product> ProductList { get; set; }
public Product NewProduct { get; set; }
}
Though, unless I'm misunderstanding something about your UX, this might not even be necessary. The model used to render a view doesn't necessarily need to be the same model received from any given form on that view. So you might continue to render the view using the VMProduct object you have now, and the form for adding a product can still post an instance of Product to the controller action which invokes the add operation. Something like:
public ActionResult Add()
{
// create your view model
return View(someVMProduct);
}
[HttpPost]
public ActionResult Add(Product newProduct)
{
// add the product to the backing data store
return RedirectToAction("Add");
}
Here explained how to implement 2 model in 1 view in MVC 4. Sometimes its required to implement a page where 2 forms exist in a single view (page) like Login & Registration in a same view.
You can get complete tutorial here : http://dotnetawesome.blogspot.com/2013/09/2-model-in-1-view-in-mvc-4.html
Here is the sample code :
A ViewModel Created :
public class UsersLoginRegister
{
public User User { get; set; }
public Login Login { get; set; }
}
User Entity
public partial class User
{
public int UserID { get; set; }
[Required]
public string Username { get; set; }
[Required]
[DataType(System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
[Required]
public string FullName { get; set; }
}
Login Entity
public class Login
{
[Required]
public string UserName { get; set; }
[Required]
[DataType( System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
}
In the view (Html) code :
<table>
<tr>
<td><b>Login</b></td>
<td><b>Register</b></td>
</tr>
<tr>
<td>
#using (Html.BeginForm("Login", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.Login.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.Login.Password)</td>
</tr>
<tr>
<td></td>
<td> <input type="submit" value="Submit" /></td>
</tr>
</table>
}
</td>
<td>
#using (Html.BeginForm("Register", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Fullname : </td>
<td>#Html.TextBoxFor(a => a.User.FullName)</td>
</tr>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.User.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.User.Password)</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Submit" />
</td>
</tr>
</table>
}
</td>
</tr>

Resources