How to execute stored procedure using blazor - stored-procedures

I have been looking for some sample which show that the execution of stored procedure using blazor.
So far i haven't seen anything related to execution of stored procedure using blazor.
Here is the parameter with SP
MSKCIS.UpdateDischargeBoardData
#ClientVisitGuid ,
#CurrentLocationGuid ,
#DischargeDateExp ,
#DischargeTimeExp ,
#DischargeDtmExp ,
#userId

In EF Core 3.0 , you need to use the FromSqlRaw extension method to execute a stored procedure.
Here is a simple working demo on getting the user data from the database by stored procedures .
User model
public partial class Users
{
[Key]
public int PkId { get; set; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Supervisor { get; set; }
public DateTime CreationDate { get; set; }
public string CreationUser { get; set; }
}
UserManagementContext.cs
public partial class UserManagementContext : DbContext
{
public UserManagementContext(DbContextOptions<UserManagementContext> options): base(options)
{}
public virtual DbSet<Users> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=UserManagementDb;Trusted_Connection=True;ConnectRetryCount=0");
}
}
}
UserService.cs
public class UserService
{
private readonly UserManagementContext _context;
public UserService(UserManagementContext context)
{
_context = context;
}
public async Task<Users[]> GetUsersAsync()
{
Users[] u;
u = _context.Users
.FromSqlRaw("EXECUTE GetUserByUserId {0}", "User1")
.ToArray();
return u;
}
}
ConfigureServices method in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UserManagementContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddTransient<UserService>();
}
Index.razor
#page "/"
#using Models
#using Data
#inject UserService us
<form method="post">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>UserID</th>
<th>Name</th>
<th>Supervisor</th>
<th>Ersteller</th>
<th>Erstelldatum</th>
<th>Optionen</th>
</tr>
</thead>
<tbody>
#foreach (var user in users)
{
<tr>
<td>#user.PkId</td>
<td>#user.UserId</td>
<td>#user.FirstName #user.LastName</td>
<td>#user.Supervisor</td>
<td>#user.CreationUser</td>
<td>#user.CreationDate</td>
<td>
<a>Delete Account</a><br />
<a asp-page="/Edit"> Edit Account</a>
</td>
</tr>
}
</tbody>
</table>
</form>
#code {
Users[] users;
protected override async Task OnInitializedAsync()
{
users = await us.GetUsersAsync();
}
}

Related

"InvalidOperationException" error showing values from model in ASP.NET Core MVC and Entity Framework Core

I am trying to show values in table from controller to view using model but it shows an error. I have debugged and checked values are returned OK, but the code shows an error. I don't know where is problem please let me know how can I resolve/fix this issue?
Here is my code:
Model:
public class RoomsStatus
{
[Key]
public int Id { get; set; }
public DateTime CheckInDateTime { get; set; }
public DateTime CheckOutDateTime { get; set; }
public decimal DailyPricePerBed { get; set; }
public int AmountOfBeds { get; set; }
public string PriceType { get; set; }
public bool Paid { get; set; }
public string Name { get; set; }
public int RoomNumber { get; set; }
}
ApplicationDbConext:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<RoomsStatus> RSN { get; set; }
}
RoomsController:
//view booking details and rooms status
public async Task<IActionResult> RoomsStatus(int PartnerID,int BuldingID)
{
try
{
return this.View("RoomsStatus", await _context.RSN.FromSqlRaw("EXECUTE dbo.GetRoomsStatusByID {0},{1}", PartnerID, BuldingID).ToListAsync());
}
catch (Exception e)
{
//Logger.LogError(e, "Error while displaying booking.");
return this.RedirectToAction("Error", "Base");
}
}
RoomStatus view:
#model IEnumerable<FewoVerwaltung.Models.RoomsStatus>
<h1>RoomsStatus</h1>
<table class="table">
<thead>
<tr>
<th>
Name
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
</tbody>
</table>
And this is the error I get:
Stack InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List1[FewoVerwaltung.Models.RoomsStatus]', but this ViewDataDictionary instance requires a model item of type 'FewoVerwaltung.Models.Base.BaseModel'
The error is complaining unexpected type of View Model has been passed to the View.
It's expecting FewoVerwaltung.Models.Base.BaseModel,
but got List<FewoVerwaltung.Models.RoomsStatus>
Check List
Model Type
I see model type has been declared in the view
#model IEnumerable<FewoVerwaltung.Models.RoomsStatus>
But the error shows that it's not picking up the model type declared, so I would try recompiling the project, make sure it's running the latest project code.
View file location
Make sure the View file RoomsStatus.cshtml is in folder ~/Views/Rooms/
~/Views/Rooms/RoomsStatus.cshtml
Controller route
Make sure the URL, assuming it's
http://localhost:{int}/Rooms/RoomsStatus?PartnerID={int}&BuldingID={int}
is handled by the RoomsController Controller

Include query result to List

I have a list of Hospitals
Hospital model:
public class Hospital
{
[Key]
public int HospitalID { get; set; }
public string Name { get; set; }
public virtual ICollection<HospitalSpeciality> HospitalSpecialities { get; set; }
public virtual ICollection<UserHospital> UserHospitals { get; set; }
}
and I have users associated to hospital. Model:
public class UserHospital
{
[Key]
public int UserHospitalID { get; set; }
public int HospitalID { get; set; }
public Hospital Hospitals { get; set; }
public string Id { get; set; }
public ApplicationUser Users { get; set; }
}
I need, on my list, return also the number of the user's that are associated to the Hospital.
This query is easy if I have only 1 hospital, but in my scenario, I have a list of hospitals
Controller:
public ActionResult Index()
{
var result = db.Hospitals.ToList();
return View(result);
}
I really don't know how to include the result of the query (number of users) on my list.
My view:
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.HospitalID }) |
#Html.ActionLink("Details", "Details", new { id=item.HospitalID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.HospitalID })
</td>
</tr>
}
It looks like you need to ensure the users are being returned in the query... Like so:
public ActionResult Index()
{
var result = db.Hospitals
.Include("UserHospitals")
.Include("UserHospitals.Users")
.ToList();
return View(result);
}
Even if they are virtual, lazy loading won't occur because you are accessing the property in your razor view. The Include is forcing Eager Loading.
Alternatively, expose another Dbset...
public DbSet<User> Users { get; set; }
Now you can select the following:
db.Users.Where(x => !x.active).ToList();
Let me know how you get on :)

MVC: best way to display data from 2 tables in 1 view

I'm trying to make a view that has data from 2 tables in my database. I have looked up a couple things and I tried to use a ViewModel but I can't get it to work. Then I was thinking about using a view and a partial view to display data from the 2 tables. What is the best way using the ViewModel or using a view and a partial view?
Also if someone knows what I am doing wrong with my ViewModel and wants to help that would be awesome.
my 2 models:
public partial class prospect
{
public prospect()
{
this.result = new HashSet<result>();
}
public int id { get; set; }
public int testid { get; set; }
public string name { get; set; }
public string surname { get; set; }
public string email { get; set; }
public string cellnumber { get; set; }
public System.DateTime timestampstart { get; set; }
public Nullable<System.DateTime> timestampend { get; set; }
public Nullable<int> totalresult { get; set; }
public string birthdate { get; set; }
public string school { get; set; }
public Nullable<int> grade { get; set; }
public string address { get; set; }
public string cityandcode { get; set; }
public virtual ICollection<result> result { get; set; }
public virtual resultpersection resultpersection { get; set; }
}
public partial class resultpersection
{
public int id { get; set; }
public int prospectid { get; set; }
public int sectionid { get; set; }
public Nullable<int> result { get; set; }
public virtual prospect prospect { get; set; }
public virtual section section { get; set; }
}
The things I want to display are:
prospect.name , prospect.surname, prospect.totalresult and all the results per section of this prospect(this comes from the resultpersection table)
my viewmodel:
namespace testAptitude.Models
{
public class ResultsPerProspect
{
public List<prospect> prospect { get; set; }
public List<resultpersection> resultPerSection { get; set; }
}
}
my controller
public ActionResult Index()
{
ResultsPerProspect vm = new ResultsPerProspect();
vm.prospect = (from p in db.prospect select p).ToList();
vm.resultPerSection = (from rps in db.resultpersection select rps).ToList(); ;
List<ResultsPerProspect> viewModelList = new List<ResultsPerProspect>();
viewModelList.Add(vm);
return View(viewModelList.AsEnumerable());
}
my view
#model IEnumerable<testAptitude.Models.ResultsPerProspect>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<table>
<thead>
<tr>
<th class="col-sm-3">
#Html.DisplayNameFor(model => model.prospect)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(model => item.prospect)
</td>
</tr>
}
</tbody>
</table>
I can't do item.prospect.name because it say's that is doesn't contain a definition for name
and what is dispalys now is this:
prospect
System.Collections.Generic.HashSet`1[testAptitude.Models.result]
Thanks in advance!
With your current code you can access it using
#Html.DisplayNameFor(model => model.FirstOrDefault().prospect)
You are passing IEnumerable<testAptitude.Models.ResultsPerProspect> to your view i.e multiple objects of class ResultsPerProspect. You would need to iterate throught this List. Each items in this list will contain definition for prospect and resultPerSection.
Or you can pass single object of class ResultsPerProspect as you are just adding single element in list.
UPDATE
You have List Of ResultsPerProspect. and each item of ResultsPerProspect has List of prospect and List of resultPerSection. So you would need to first iterate for loop over List Of ResultsPerProspect. and inside that for loop , for loop for List of prospect List of and resultPerSection
CODE
#foreach (var item in Model)
{
foreach (var pros in item.prospect)
{
<tr>
<td>
#Html.DisplayFor(model => pros.Name)
</td>
</tr>
}
}
Why don't you create a class ("Container") that consists of your two (sub)classes (let's say A and B)? You can then create a Container object and put the needed objects in Container.A and Container.B. You can then easly pass "Container" to your view and access your objects.

Checking if the data being retrieved from the database Eager loading OR lazy is loading

I have the following two models; AccountDefinition & SDOrganization where the relation is one-to-one.
public partial class AccountDefinition
{
public AccountDefinition()
{
this.AccountSiteMappings = new HashSet<AccountSiteMapping>();
}
public long ORG_ID { get; set; }
public virtual SDOrganization SDOrganization { get; set; }
public virtual ICollection<AccountSiteMapping> AccountSiteMappings { get; set; }}
&
public partial class SDOrganization
{
public SDOrganization()
{
this.AccountAttachments = new HashSet<AccountAttachment>();
this.SDOrgUsers = new HashSet<SDOrgUser>();
this.AaaContactInfoes = new HashSet<AaaContactInfo>();
this.AaaUsers = new HashSet<AaaUser>();
this.AaaPostalAddresses = new HashSet<AaaPostalAddress>();
}
public long ORG_ID { get; set; }
public string NAME { get; set; }
public virtual AccountDefinition AccountDefinition { get; set; }
public virtual SDOrgDetail SDOrgDetail { get; set; }
public virtual SDOrgStatu SDOrgStatu { get; set; }
public virtual ICollection<SDOrgUser> SDOrgUsers { get; set; }
public virtual ICollection<AaaContactInfo> AaaContactInfoes { get; set; }
public virtual ICollection<AaaUser> AaaUsers { get; set; }
public virtual ICollection<AaaPostalAddress> AaaPostalAddresses { get; set; }
}
On the Action method I have the following call to the repository:-
public ActionResult Index(string searchTerm=null)
{
var accountdefinition = repository.FindAccountDefinition(searchTerm).ToList();
if (Request.IsAjaxRequest())
{
ViewBag.FromSearch = true;
return PartialView("_CustomerTable",accountdefinition);
}
return View(accountdefinition);
}
And the repository the method looks as :-
public IQueryable<AccountDefinition> FindAccountDefinition(string q)
{
return from ad in entities.AccountDefinitions.Include(a => a.SDOrganization)
where (q == null || ad.ORG_NAME.ToUpper().StartsWith(q.ToUpper()) )
select ad;
}
Finally on the view I got the following code (only part of the code):-
#model IEnumerable<TMS.Models.AccountDefinition>
//code goes here
<th>
#Html.DisplayNameFor(model => model.SUPPORT_EMAIL)
</th>
<th>
#Html.DisplayNameFor(model => model.Single().SDOrganization.DESCRIPTION)
</th>
<th></th>
</tr>
//code goes here
#foreach (var item in Model)
{
<td class="center">
#Html.DisplayFor(modelItem => item.SDOrganization.DESCRIPTION)
</td>
I am assuming that since on the repository method I added the .include
return from ad in
entities.AccountDefinitions.Include(a => a.SDOrganization)
So all the data regarding the accountdefinition and the SDorganization will be retrieved at once (eager loading).
so I have the following two questions:-
Will in my case the data retrieved by a single query to the database (Eager Loading).
I am using SQL server 2008 r2. So how I can check the database queries to check how many query actually hit the database.
When you are using .Include() method you are initiating eager loading. So yes your data will be returned by single query.
For checking it consider to use SQL Server Profiler or paid utility Entity Framework profiler. Also such utility as LinqPad could help you in query tracing
Also you need to be careful with repositories returning IQueryable because usage like this will execute several queries in a loop:
foreach(var accDef in repository.FindAccountDefinition(searchTerm))
{
//get info from accDef
}

dropdown value null when using, viewmodel & modelbinder in asp.net mvc

I am using asp.net's modelbinder functionality to bind form values to my entity when posting from a view.
The html renders correctly in the initial view with correct option and value items.
When completing the form and posting, all values are populated correctly into the entity except the value from the dropdown list. not sure what I am doing wrong.
code attached below:
Customer Entity:
public class Customer : EntityBase
{
public virtual string Name { get; set; }
public virtual string Email { get; set; }
public virtual string Mobile { get; set; }
public virtual Store LocalStore { get; set; }
public virtual DateTime? DateOfBirth { get; set; }
public Customer(){}
public Customer(string name, string email, string mobile, Store localStore):this(name, email, mobile, localStore, null)
{
}
public Customer(string name, string email, string mobile, Store localStore, DateTime? dateOfBirth)
{
Name = name;
Email = email;
Mobile = mobile;
LocalStore = localStore;
DateOfBirth = dateOfBirth;
}
}
ViewModel:
public class CustomerViewModel {
// Properties
private IStoreRepository _StoreRepository;
public Customer Customer { get; private set; }
public SelectList Stores { get; private set; }
// Constructor
public CustomerViewModel(IStoreRepository storeRepository, Customer customer)
{
_StoreRepository = storeRepository;
Customer = customer;
Stores = new SelectList(_StoreRepository.GetAllStores(), "Id", "Name", Customer.LocalStore.Id);
}
}
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Prefix="")]Customer customer)
{
return View(new CustomerViewModel(_StoreRepository, customer));
}
View:
<%# Import Namespace="BlackDiamond.Buzz.MVCWeb.Controllers"%>
<%# Import Namespace="BlackDiamond.Buzz.Core"%>
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CustomerViewModel>" %>
<%
Customer customer = ViewData.Model.Customer;
using (Html.BeginForm())
{
%>
<table>
<tr>
<td>Local Store:</td>
<td><%= Html.DropDownList("LocalStore", ViewData.Model.Stores)%></td>
</tr>
<tr>
<td>Name:</td><td><%= Html.TextBox("Name", customer.Name)%></td>
</tr>
<tr>
<td>Email:</td><td><%= Html.TextBox("Email", customer.Email)%></td>
</tr>
<tr>
<td>Mobile:</td><td><%= Html.TextBox("Mobile", customer.Mobile)%></td>
</tr>
</table>
<input type="submit" value="Create" />
<%}%>
Maybe because you declare LocalStore as Store type?
public virtual Store LocalStore { get; set; }
I think it should be int (if "id" property is int) or string. Not sure though.
public virtual int LocalStore { get; set; }
Had to create a custom modelbinder to retrieve the Store entity based on the guid from the dropdown list:
public class CustomerModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(Customer))
{
// get values
string name = bindingContext.ValueProvider["Name"].AttemptedValue;
string email = bindingContext.ValueProvider["Email"].AttemptedValue;
string mobile = bindingContext.ValueProvider["Mobile"].AttemptedValue;
Guid storeId = new Guid(bindingContext.ValueProvider["LocalStore"].AttemptedValue);
Store localStore = IoC.Container.Resolve<IStoreRepository>().GetStore(storeId);
// hydrate
return new Customer(name, email, mobile, localStore);
}
else
{
return null;
}
}
}

Resources