asp.net core pass linq lambda to view - entity-framework

I'm using asp.net core, when I pass linq lambda query to view I get this error:
An unhandled exception occurred while processing the request.
InvalidOperationException: The model item passed into
the ViewDataDictionary is of type 'System.Collections.Generic.List`1[<>f__AnonymousType7`1[System.Int64]]',
but this ViewDataDictionary instance
requires a model item of type 'System.Collections.Generic.IEnumerable`1[HRMS.Salaries]'.
This my query:
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries select new { salaries.Id });
return View(await salary.ToListAsync());
}
and in the view I use:
#model IEnumerable<HRMS.Salaries>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
</tr>
}

Is there a reason you create an object in your query? If no, try this instead :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select salaries.Id
);
return View(await salary.ToListAsync());
}
Then in your view :
#model IEnumerable<int>
#foreach (var item in Model)
{
<tr>
<td>#item</td>
</tr>
}
Else, if you need the object, use in your query :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select salaries
);
return View(await salary.ToListAsync());
}
And keep your view the same :
#model IEnumerable<HRMS.Salaries>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
</tr>
}
EDIT : If you want to pass multiple fields to your View, it's better to use a new object. For this, create a class (for exemple, SalaryDetailsViewModel) with the required fields. Then in your controller :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select new SalaryDetailsViewModel {
Id = salaries.Id,
Amount = salaries.Amount,
Date = salaries.Date,
JobTitle = salaries.JobTitle.Name }
);
return View(await salary.ToListAsync());
}
Then adjust your View to call the different fields of your custom object, for display purpose, for example :
#model IEnumerable<SalaryDetailsViewModel>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.Amount</td>
<td>#item.Date</td>
<td>#item.JobTitle</td>
</tr>
}

Related

How can i use Custom query Single field in EFCore?

In EF6, there is context.Database.sqlquery that I can use. Why does EF Core cancel this?
I try to find the answer but the context.user.FromInterpolated doesn't allow select Single field. (Or am I using the wrong method of this?)
Here is my code. Please give me some advice that I can solve this problem.
[HttpPost]
[Obsolete]
public async Task<IActionResult> SendEmail()
{
Email email = new Email();
var ID = HttpContext.Request.Form["ID"].ToString();
var Title = HttpContext.Request.Form["Title"].ToString();
var Body = HttpContext.Request.Form["Body"].ToString();
var Emails = context.user.FromSqlInterpolated($"select email from user where UserId in({ID})");
foreach (var item in Emails)
{
if (!string.IsNullOrEmpty(item.Email))
{
email.Send(item.Email, Title, Body);
}
}
await HttpResponseWritingExtensions.WriteAsync(this.Response, "success");
return RedirectToAction(nameof(Index));
}
You can do something like this:
public class StringReturn
{
public string Value { get; set; }
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StringReturn>().HasNoKey();
}
using (var db = new NorthwindContext())
{
var result = db.Set<IntReturn>()
.FromSqlRaw("exec dbo.Scalar")
.AsEnumerable()
.First().Value;
Console.WriteLine(result);
}
See my blog post here for more info: https://erikej.github.io/efcore/2020/05/26/ef-core-fromsql-scalar.html
Ok first of all you have sql injection in your code. So if user pass in field id smth like 1 ) or ( 1=1 . It will allow it and that is basic not very harmfull in your case but
What you should really do is
var ids= HttpContext.Request.Form["ID"].ToString().Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();
if(ids.Any()){
var Emails = await context.user.Where(u=>ids.Contains(u.UserId)).Select(u=>u.email).ToListAsync();
}

Html.DropDownListFor default selected value does not work

I have read hundreds of posts about this problem and I still can't find a solution.
Please help with this horrible mistery;
I would like to have different default values in my DropDownListFor. The "PartialViewList1 exists out of 4 items.
I want the DropDownListFor to select the id of the current item. (item.id)
But because of testing purposes I just filled in "3". And even that doesn't work.
The Models are filled correctly, I am able to add more code of the controller but that wouldn't add much. But please ask if you want me to.
And yes I know that it is better to make the SelectList in the controller, but first I want to make it work.
View:
#foreach (var item in Model.PartialViewList1)
{
<tr>
<td>Plaats: </td>
<td>#item.PlaceNumber</td>
<td>
#Html.DropDownListFor(x => x.PartialView.Id, new SelectList(Model.PartialViewList2, "Id", "Name", 3),
new { onchange = "this.form.submit();" })</td>
</tr>
}
Screen shot of the users view
I hope that maybe someone can use this for his or her problem.
With Stephen Mueke I have found the solution. The problem is that if "x => x.PartialView.Id" already has a value then the default value : "3" will be overriden by the Id.
And you can't generate multiple DropDownlistFor's while binding them to the same property.
My solution on my problem:
View:
#using (Html.BeginForm("_PartialSettingsDropDownList1", "Home")){
<table>
#for (int i = 0; i < Model.maxNumberOfViews; i++)
{
<tr>
<td>
Plaats #(i+1)
</td>
<td>
#Html.DropDownListFor(x => Model.PartialViewList[i].ID, new SelectList(Model.PartialViewList, "Id", "Name", Model.PartialViewList[i].ID), "select")
</td>
</tr>
}
</table>
#Html.HiddenFor(x => x.maxNumberOfViews)
<input class="submit" type="submit" value="Submit" />}
Controller:
[HttpGet]
public PartialViewResult _PartialSettingsDropDownList1()
{
PartialScreenViewModel viewModel = new PartialScreenViewModel();
viewModel.PartialViewList = homeModel.AllBoxViews(databaseRepository.PartialViews);
viewModel.maxNumberOfViews = viewModel.PartialViewList.Count();
return PartialView(viewModel);
}
[HttpPost]
public RedirectResult _PartialSettingsDropDownList1(PartialScreenViewModel viewModel)
{
for (int i = 0; i < viewModel.maxNumberOfViews; i++)
{
PartialView viewOnScreen = databaseRepository.PartialViews.FirstOrDefault(x => x.ID == viewModel.PartialViewList[i].ID);
databaseRepository.UpdatePartialView(viewOnScreen, i+1);
}
return new RedirectResult("Settings");
}
Model:
public List<PartialView> AllBoxViews(IEnumerable<PartialView> allViews)
{
List<PartialView> OnlyBoxViews = new List<PartialView>();
foreach (var item in allViews.Where(item => item.Type.Equals("box")))
{
OnlyBoxViews.Add(item);
}
return OnlyBoxViews;
}
ViewModel:
public class PartialScreenViewModel
{
public List<PartialView> PartialViewList { get; set; }
public int maxNumberOfViews { get; set; }
}
Result on screen: screenshot

single page with multiple partials and forms

What is the best practice for this:
I have a list of partials on one page. Each page has a form on it to save the data of the partial.
I do this like this on the main page:
#foreach (var taak in Model)
{
#Html.Action("DetailTaak", "Checklist", new { trouwTaakId = taak.Id })
}
Then the controller is this (where the data is filled):
public ActionResult DetailTaak(int trouwTaakId)
{
DTO.Trouw.TrouwTaak viewModel;
viewModel = _themaService.GetTrouwTaakByTrouwTaakId(trouwTaakId);
return View(viewModel);
}
The page gets build and the list is completed. Now when I want to save a partial using this code:
#using (Html.BeginForm("DetailTaak", "Checklist", FormMethod.Post, new { #class = "form-horizontal col-md-12", role = "form", id = #Model.Id }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
...
}
It works but what do I do so the mainpage doesn't have to be reloaded ? This is the post code:
[HttpPost]
public ActionResult DetailTaak(DTO.Trouw.TrouwTaak model)
{
if (ModelState.IsValid)
{
ViewBag.SaveSuccess = "Je instellingen zijn opgeslagen";
}
return View("DetailTaak", model);
}
With this post code I go to the DetailTaak page instead of staying on the main page and just updating the partial.
I am doing something wrong but I don't know which way to go.
kind regards

Stuffing an anonymous type in ViewBag causing model binder issues

can someone tell me what I'm doing wrong? :-)
I have this simple query:
var sample = from training in _db.Trainings
where training.InstructorID == 10
select new { Something = training.Instructor.UserName };
And I pass this to ViewBag.
ViewBag.Sample = sample;
Then I want to access it in my view like this:
#foreach (var item in ViewBag.Sample) {
#item.Something
}
And I get error message 'object' does not contain a definition for 'Something'. If I put there just #item, I get result { Something = SomeUserName }
Thanks for help.
This cannot be done. ViewBag is dynamic and the problem is that the anonymous type is generated as internal. I would recommend you using a view model:
public class Instructor
{
public string Name { get; set; }
}
and then:
public ActionResult Index()
{
var mdoel = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
return View(model);
}
and in the view:
#model IEnumerable<Instructor>
#foreach (var item in ViewBag.Sample) {
#item.Something
}
If you want to send in ViewData For example and don't want to send in model
you could use the same could as in the upper answer
and in the Controller
enter code here
ViewData[Instractor] = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
and in the view you need to cast this to
`IEnumerable<Instructor>`
but to do this you should use
#model IEnumerable<Instructor>
Then you could do something like this
IEnumerable<instructors> Instructors =(IEnumerable<Instructor>)ViewData[Instractor];
then go with foreach
#foreach (var item in Instructors ) {
#item.Something
}

SelectList Object selectedValue issue

I'm having troubles with the selectedValue option for SelectedItems, for some reason it won't select the item despite it being in the list...
My Controller:
public ActionResult CreateTransformer(string edit)
{
var equipment = GenIDQueries.FindEquipment(edit);
ViewData["Feeder"] = new SelectList(GenIDQueries.GetFeeders(equipment.OpsCentre.ToString()),
"CircuitID",
"CircuitDescription",
equipment.Feeder);
return View(equipment);
}
equipment.Feeder is of type Integer.
My View:
<p>
<b><%=Html.LabelFor(m=>m.Feeder) %>:</b><font color="red">*</font>
<%=Html.DropDownListFor(m=>m.Feeder, ViewData["Feeder"] as SelectList, "") %>
<%= Html.ValidationMessageFor(m => m.Feeder)%>
</p>
My GenIDQueries.GetFeeders:
public static IEnumerable<Circuit> GetFeeders(string distNo)
{
int distNoNumber;
if ( int.TryParse(distNo, out distNoNumber))
{
return ActiveRecordLinq.AsQueryable<Circuit>()
.Where(x => x.DistrictCircuitRelations
.Any(y => y.District.DistrictNo == distNoNumber))
.OrderBy(x => x.CircuitDescription)
.Select(x => new Circuit
{
CircuitID = x.CircuitID,
CircuitDescription = x.CircuitDescription
});
}
return new List<Circuit>();
}
I have verified that the element I wanted to select is indeed returned by GenIDQueries, however when the page loads it never selects that option, in the HTML source code, the item is not selected either.
Thanks for the help!
When setting the selected value you should set it to the selected CircuitID and not the Feeder object.
Why are you using this Plague of ViewData? I consider ViewData as a virus started at Microsoft open space laboratories and spread through internet blog posts and articles.
View models are the way to go in ASP.NET MVC:
Model:
public class MyViewModel
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Controller:
public ActionResult CreateTransformer(string edit)
{
var equipment = GenIDQueries.FindEquipment(edit);
var items = GenIDQueries.GetFeeders(equipment.OpsCentre.ToString());
var model = new MyViewModel
{
SelectedValue = equipement.CircuitID,
Items = new SelectList(items, "CircuitID", "CircuitDescription")
};
return View(model);
}
View:
<%= Html.DropDownListFor(m => m.CircuitID, Model.Items, "") %>
<%= Html.ValidationMessageFor(m => m.CircuitID) %>