I'm trying to pull a list of Ids and Usernames from an Audit table that is populated with Ids from a separate table, and usernames of people who voted on an Idea.
The flow should be:
See an Idea
Click the Vote button
Add the Idea Id, logged in User, and DateTime they clicked the Vote button to the IdeaBoardVote table.
Disable Vote button if after querying the IdeaBoardVote table, the IdeaId and Username match an IdeaBoard records Id and Username.
I'm trying to use foreach to loop through the IdeaBoardVote table to find matches, but I get the following error:
'System.Web.Mvc.SelectListItem' does not contain a definition for 'IdeaId'
Here is my Controller code to populate the list:
[HttpGet]
public ActionResult Index(int page = 1, string message = "")
{
ViewBag.Message = message;
if (!Request.IsAuthenticated)
{
ViewBag.Message = "You must be logged in to vote on or create new ideas.";
}
//Populate list of IdeaIds and Usernames from IdeaBoardVote table
var ideaBoardVotes = db.IdeaBoardVotes.ToList();
ViewBag.IdeaVoters = new SelectList(ideaBoardVotes, "IdeaId", "Username");
var ideaBoards = db.IdeaBoards.OrderByDescending(i => i.VoteCount).Take(100);
int pageSize = 10;
return View(ideaBoards.ToPagedList(page, pageSize));
}
Here is what I have in my View:
#{bool hasVoted = false;}
foreach (var vote in ViewBag.IdeaVoters)
{
if (vote.IdeaId == idea.Id && vote.Username == User.Identity.Name)
{
hasVoted = true;
}
}
if (!hasVoted)
{
<a href="#Url.Action("IncreaseVote", "IdeaBoard", new { id = idea.Id })" class="btn btn-default btn-sm width-100 margin-bottom text-left">
Vote <span class="glyphicon glyphicon-thumbs-up blue"></span>
</a>
}
What I'm missing that I'm getting the error message?
Probably the column name IdeaId There is something else in the IdeaBoardVotes table
ViewBag.IdeaVoters = new SelectList(ideaBoardVotes, "IdeaId", "Username");
Thank you #Sreenath. Your advise is exactly what I was missing. Here is how I solved this simple issue. In my foreach loop, I was using vote.IdeaId and vote.Username. I changed those to vote.Value and Vote.Text.
if (vote.Value == idea.Id.ToString() && vote.Text == User.Identity.Name)
{
hasVoted = true;
}
Also, changed where the bool was declared so it would be local scope instead of page scope.
Those little changes made the difference. So again, thank you #Sreenath.
Related
i will first give a quick rundown of my current code.
My code is a login function which compares and checks for what the user entered and to see whether it is correct in the database, if it is correct the user can log in and different view pages will be display according to what is their role. Currently, i am using temp data to store what they typed in as their StaffNRIC and show it when they are logged in and possibly use the tempdata for further functions. However, how can i get the Staff ID if the tempdata can only store what the user typed in but i want the Staff ID of what their NRIC is. The commented lines are what i have tried to no avail
when i try the commented lines, it shows this error
InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure.DefaultTempDataSerializer' cannot serialize an object of type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Starbucks.Models.StaffModel]'.
This is my code below
'`
[HttpPost]
public ActionResult Verify(Account acc)
{
connectionString();
con.Open();
com.Connection = con;
com.CommandText = "select * from Staff where StaffNRIC='" + acc.StaffNRIC + "' and StaffPassword='" + acc.StaffPassword + "' and StaffAccountStatus = 'Approved'";
dr = com.ExecuteReader();
if (dr.HasRows)
{
TempData["StaffNRIC"] = acc.StaffNRIC;
//var staff = _context.Staff.Where(p => p.StaffNRIC == acc.StaffNRIC);
//var staff = _context.Staff.Any(p => p.StaffNRIC == acc.StaffNRIC);
//if(staff.Any(p => p.StaffNRIC == acc.StaffNRIC)
//TempData["test"] = staff;
while (dr.Read())
{
if (dr["StaffRole"].ToString() == "Manager")
{
con.Close();
return RedirectToAction("ManagerHome", "Manager");//wherever you want to return the user to
}
else if (dr["StaffRole"].ToString() == "Admin")
{
con.Close();
return RedirectToAction("AdminHome", "Admin");
}
else if (dr["StaffRole"].ToString() == "Part-Timer")
{
con.Close();
return RedirectToAction("PartTimerHome", "PartTimer");
}
else
{
con.Close();
return View( "Login");
}
}
}
ViewBag.Message = "Wrong NRIC and Password or Account not approved";
return View("Login");
}`'
Below is my HTML code for what will be displayed after they log in
'`
#{
Layout = "~/Views/Shared/AdminLayout.cshtml";
}
#ViewData["Title"]
<div class="cover-container d-flex h-100 p-3 mx-auto flex-column">
<main role="main" class="inner cover">
<h1 class="cover-heading">Welcome back Admin</h1>
#{
var tempDataEmployeet = TempData["StaffNRIC"] as StaffModel; //need typcasting
TempData.Keep(); // retains all strings values
}
<h2>#TempData["test"]</h2>
</main>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery-slim.min.js"><\/script>')</script>
<script src="../../assets/js/vendor/popper.min.js"></script>
<script src="../../dist/js/bootstrap.min.js"></script>
Log Out
`'
enter image description here
Did you mean to do the following?
var staff = _context.Staff.FirstOrDefault(p => p.StaffNRIC == acc.StaffNRIC);
You were using Where before, which does not execute the query against the database, it merely adds a condition to the yet-to-be-executed query.
When you want to store the result(s) of a query somewhere, you need to make sure the query is executed. These are some of the functions that will execute the query:
ToArray / ToList: returns a list of 0 or more query results
FirstOrDefault: returns either one result or null
First: returns one result or throws an exception
Any: returns a boolean indicating if a result exists, but it won't return the result itself.
I have the following entries in my database:
MeetingID AgendaItem LegistarID Title
48620 3 60710 Comment
48620 5 60615 Extending report date
48620 6 60714 Update on Additional meeting dates
48620 7 59909 Budget Rules & Procedures
48620 8 60703 Update Director name
That I need to update with these values:
MeetingID AgendaItem LegistarID Title
48620 3 60710 Public Comment
48620 5 60769 Briefing by Victor
48620 6 60615 Extending report dates
48620 7 60714 Update on Additional meeting dates
48620 8 60703 Update from Director on new processes
The way I am trying doing this in C#, is as follows:
if (ModelState.IsValid)
{
var errors = new List<string>();
var rowCounter = 1;
using (Entities db = new Entities())
{
foreach (var i in meeting)
{
if (i.MeetingID == 0)
{
// Let the user know this row is bad
errors.Add($"Row {rowCounter}: Missing Meeting ID value. " +
"Verify that the data you are trying to upload meets the required criteria, " +
"and then try to upload your file again." );
break;
}
// Check if LegistarID is missing
if (i.LegistarID == 0)
{
// Check if Agenda Item is present
if (i.AgendaItem == 0)
{
errors.Add($"Row {rowCounter}: Meeting has no LegistarID and no Agenda Item. Please check data.");
break;
}
else
{
i.LegistarID = i.AgendaItem;
}
}
var compositeKey = db.Meeting.Find(i.MeetingID, i.AgendaItem);
if (compositeKey == null)
{
// Add new
db.Meeting.Add(i);
}
else
{
// Serves as an update, or addition of a previously imported dataset
db.Entry(compositeKey).CurrentValues.SetValues(i.MeetingID);
db.Entry(compositeKey).CurrentValues.SetValues(i.AgendaItem);
db.Entry(compositeKey).CurrentValues.SetValues(i.LegistarID);
db.Entry(compositeKey).CurrentValues.SetValues(i.Title);
db.Entry(compositeKey).State = EntityState.Modified;
}
rowCounter++;
}
// If there are errors do not save and return error message
if (errors.Count > 0)
{
return new JsonResult { Data = new { status = false, message = string.Join("\n", errors) } };
}
db.SaveChanges();
status = true;
}
}
else
{
message = string.Format(#"Please, verify that the file you are trying to upload is correctly formatted,
and that the data it contains, meets the expected criteria,
then click the upload button again. \n Thank you!");
return new JsonResult { Data = new { status = status, message = message } };
}
The code for the Add part works well, but the part that updates the record if the composite key is found does not work, the update is not working.
I am not sure if I am doing this the best way, but if there is a better way I am open to change the code, or if I have an error on how I am doing the process, please let me know
Any help is appreciated.
Thank you,
Erasmo
Remove all your calls to SetValues and replace them with single one:
db.Entry(compositeKey).CurrentValues.SetValues(i);
SetValues which accepts object as parameter copies data to entity based on object properties names:
Any property on the object with a name that matches a property name in the entity type and can be read will be copied. Other properties will be ignored.
Currently trying to build a bulletin in my application where the logged in user simply types in something in a text box and the results are then displayed with a list of other bulletins.
My problem is that I don't want to display the dropdown box of names, I just want the admins' ID who is logged in to post. FYI, I messed up my admin in this app, their ID is different to their userID but their usernames are the same and that is how I get their ID.
I want to store the result of a linq query in the HiddenFor in my razor page. I've been trying with ViewBags but I just get cannot implicitly convert type 'int' to 'system.collections.ienumerable'
Here is my Create part of my controller:
// GET: Bulletins/Create
public ActionResult Create()
{
string username = Membership.GetUser().UserName;
var getAdmin = (from a in db.Admins
where username == a.AdminUsername
select a.AdministrationId).SingleOrDefault();
ViewBag.AdministrationId = new SelectList(db.Admins, "AdministrationId", "AdministratorName");
return View();
}
// POST: Bulletins/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "BulletinsID,DetailsOfBulletin,AdministrationId")] Bulletins bulletins)
{
if (ModelState.IsValid)
{
string username = Membership.GetUser().UserName;
var getAdmin = (from a in db.Admins
where username == a.AdminUsername
select a.AdministrationId).SingleOrDefault();
db.Bulletins.Add(bulletins);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AdministrationId = new SelectList(db.Admins, "AdministrationId", "AdministratorName", bulletins.AdministrationId);
return View(bulletins);
}
And my Razor View:
#Html.HiddenFor(model => model.AdministrationId)
Honestly couldn't find anything so any help would be appreciated. x
First, you should materialize your query to get all admin object from your db:
var adminIds = db.admins.Select(a => a.Id).ToList();
ViewBag.AdministrationIds = adminIds;
Then, if you are using ViewBag to access those admin ids in the view, you will need to foreach over them and render a hidden input with the ID as the value:
#{
foreach (var item in ViewBag.AdministrationIds)
{
<input type ="hidden" value="#item" />
}
}
I have a fictional website in ASP.NET MVC4 that's designed to simulate a private jet hire company ticket booking system. However, I am struggling a bit when it comes to implementing the features I want to have, one of which is using a dropdown menu to store data into another database
To give you a better idea of what I'm really aiming towards
Users to log in to the website
Go to the flights page
Have a look at the flights
Eventually go on to the make a booking page
Then
Select their desired flight from a dropdown menu
Input the number of tickets they want to purchase. (The dropdown is working but the reset isn't implemented)
The user database should then check for the user's age (which is already
stored in the database) is between 18 and 64
If they're outside of that range, an error message should appear
and prevent them from booking a ticket.
If they're within that range, the amount of seats left should decrement by the number of tickets "purchased"
Also
The booking page should prompt the user to log in if they haven't already done so.
This is where it gets really confusing for me.
I have two pages related to the flights:
Page 1 (Flights.cshtml - shows a table of the available flights): http://gyazo.com/2ab67e35bdd1967e4a24706e398ba759
Page 2 (BookFlight shows a dropdown menu, allowing the user to select the flight they want): http://gyazo.com/67948e5e8be82c72f7ee0914dfa9b5f6
(Screenshot of the project files in solution explorer)
Here are my relevant files related to the flights table (on page 1)
https://gist.github.com/anonymous/144ed06e1d4f2011161e
Page 2 reads from the list on page 1 and here's how it's done:
View:
#model List<Project_v3.Models.FlightsTable>
#{
ViewBag.Title = "Book Flight | Open Airlines";
Layout = "~/Views/Shared/_MyLayout.cshtml";
}
<h2>Book A Flight</h2>
<select id='SelectedFlight' name='SelectedFlight'>
#foreach (var flight in Model)
{
<option value='#flight.FlightID'>#String.Format("{0} to {1}", flight.Departure, flight.Arrival)</option>
}
</select>
Controller:
public ActionResult BookFlight()
{
using (var context = new FlightsDBEntities())
{
// Get all of the flights within your table
var flights = context.FlightsTables.ToList();
// Pass the flights to your View
return View(flights);
}
}
My Question is
How do I make the data from the dropdown menu a field in another database table named 'Booking' for example? (I have not made this table yet). If that makes sense?
How do I take the information (from the dropdown) that the user has selected and store it with a press of a button? Is this even possible? Would anyone be able to show me a working example of this based on the code I listed above?
First you have to create a model where you will store the item that will be selected.
public class BookingModel
{
public string SelectedFlightId {get;set;}
public List<SelectListItem> Flights {get;set;}
}
You need to modify the Action that make use of the new model.
public ActionResult BookFlight()
{
using (var context = new FlightsDBEntities())
{
// Get all of the flights within your table
var flights = context.FlightsTables.ToList();
var booking = new BookingModel();
booking.Flights = flights.Select(f => new SelectListItem
{
Text = String.Format("{0} to {1}", f.Departure, f.Arrival),
Value = f.FlightID.ToString()
}).ToList();
return View(booking);
}
}
Modify the View to make use of our new Model
#model Project_v3.Models.BookingModel
#{
ViewBag.Title = "Book Flight | Open Airlines";
Layout = "~/Views/Shared/_MyLayout.cshtml";
}
<h2>Book A Flight</h2>
#using(Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedFlightId, Model.Flights)
<input type="submit" value="Submit" />
}
Create a new Action that have the same name as the first action, but put HttpPost attribute. In this action you will get SelectedFlightId after the form was submited
[HttpPost]
public ActionResult BookFlight(BookingModel booking)
{
using (var context = new FlightsDBEntities())
{
if(ModelState.IsValid)
{
var flightId = Int32.Parse(booking.SelectedFlightId);
var flight = context.FlightsTables.First(f => f.FlightID == flightId);
var user = context.UsersTables.First(u => u.UserId == User.Identity.GetUserId());
user.Flights.Add(flight)
context.SaveChanges();
}
// repopulate again the flights (this can be cached and/or be refactored a under method)
var flights = context.FlightsTables.ToList();
booking.Flights = flights.Select(f => new SelectListItem
{
Text = String.Format("{0} to {1}", f.Departure, f.Arrival),
Value = f.FlightID.ToString()
}).ToList();
}
return View(booking);
}
I'll explain a quiet better here. I've this method wich returns me some lines of ma table according to a searchstring I informed in my textbox.
public ActionResult Index(string site, string searchString)
{
var user = from m in db.OrderDetails
select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Order.ClientID.Contains(searchString));
}
if (!String.IsNullOrEmpty(site))
{
user = user.Where(c => c.Order.SiteNumber.Contains(site));
}
return View(user);
}
In the same class, I've an other method which generate a pdf file (all the backend process is set up in a second project include in the first).
public ActionResult PrintOrders()
{
var user = from m in db.OrderDetails
select m;
return this.ViewPdf("Facture", "PrintView", user);
}
This second method, when it generate my pdf file, displays all the entries of my table. I would like that, when I click on my link (on the same page view wich display my table entries) for generate my pdf file, if I did a search before, I juste have fields that match my searchstring (or site string).
How can I implement it ? There is a way do to it ?
Thanks for your help, and sorry for the title which is maybe not too relevant. Also sorry for my english, hope you'll understand my aim.
EDIT INFORMATIONS
After looking, when I set up my PrintOrders() method like my Index() method as follow :
public ActionResult PrintOrders(string searchString, string username)
{
var user = from m in db.OrderDetails select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Order.ClientID.Contains(searchString));
}
if (!String.IsNullOrEmpty(site))
{
user = user.Where(c => c.Order.SiteNumber.Contains(site));
}
return this.ViewPdf("Facture Krys-Group", "PrintView", user);
}
and set my view like this :
#using (Html.BeginForm("PrintOrders", "Historic", FormMethod.Get))
{
Seach by ID : #Html.TextBox("searchString")
Search by Site : #Html.TextBox("site")
<input type="submit" value="Search" /></p>
}
then it works. But I've already the same form in my view for "Index" instead of "PrintOrders". How can I combine both ?
I am not sure I follow you completely but I think you achieve what you are looking for with the use of partial views. The form you mention can be a partial view that gets rendered into the pdf view and like that you really have one form but displayed in both pages. Hopefully I understood what you were after and this helps you.