Foreach iteration showing each record several times - asp.net-mvc

I have created Linq-to-SQL for a view of SQL Server, now I'm trying to display record on view, it's done :) but
problem is that it shows each name 26 times, why?
How to put it in gridview kinda thing in MVC?
Controller:
namespace EmployeeAttendance_app.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Employee Attendance";
var DataContext = new EmployeeAtdDataContext();
var EmployeeAtd = from emp in DataContext.EmployeeAtds
select emp;
return View(EmployeeAtd);
}
}
View:
<ul>
#foreach (EmployeeAttendance_app.Models.EmployeeAtd emp in (IEnumerable<Object>)ViewData.Model)
{
<li>#emp.EmplName</li>
}
</ul>
Model contains Linq-to-SQL class named EmployeesAtd.
View has been created via this query:
SELECT
dbo.HrEmployee.EmplID, dbo.HrEmployee.EmplName, dbo.AtdRecord.RecDate,
dbo.AtdRecord.RecTime, dbo.HrDept.DeptName
FROM
dbo.HrDept
RIGHT OUTER JOIN
dbo.HrEmployee ON dbo.HrDept.DeptID = dbo.HrEmployee.DeptID
LEFT OUTER JOIN
dbo.AtdRecord ON dbo.HrEmployee.EmplID = dbo.AtdRecord.EmplID

Other than cleaning up the things Adriano pointed out, I don't see anything wrong with that. You said EmployeeAtds is a SQL View, right? I would guess you have some sort of join in there that is duplicating rows.

Try to move boxing before loop:
var emps = (IEnumerable< Object >)ViewData.Model;
#foreach(EmployeeAttendance_app.Models.EmployeeAtd emp in emps)
To show data in GridView you have to use some javascript lib.
grid controls for ASP.NET MVC?

Related

Getting error when multiple results passing to view in asp.net MVC5

I use asp.net mvc 5 and EF 6 .I have following code in my controller
var resultOne = stats.GetPlayerStatsByParam(year, modeOne); //first
ViewData["more"] = stats.GetTeamStatsID(year); //second
return View("StatsNew", resultOne.ToList());
I am able to display result in view using "resultOne". Now I want to pass another data to same view using ViewData[]. its a stored procedure and the result is paasing to "ViewData["more"]".
I have done following code for "ViewData["more"]" in View page
But I am getting an error saying that 'object reference not set'
#foreach (var item in ViewData["more"] as #List<demo.GetTeamStatsID_Result>)
{
#item.Pld;
}
Use a viewmodel and extend it by the data coming from stats.GetTeamStatsID(year);
Do not use ViewBag or ViewData if not necessary for some reason (which I canĀ“t imagine right now)
As the comments have already pointed out, build a ViewModel class, that wraps everthing you need:
//I am using fake types here, sinceI don't know your model classes
//substitute accordingly!
public class MyViewModel
{
public PlayerStatsType PlayerStats { get; set;}
public List<demo.GetTeamStatsID_Result> Teams { get; set;}
}
Then in your action method:
var vm = new MyViewModel();
vm.PlayerStats = stats.GetPlayerStatsByParam(year, modeOne); //first
vm.TeamId = stats.GetTeamStatsID(year); //second
return View("StatsNew", vm);
Amend the model declaration in your view:
#model Namespace.Models.MyViewModel //again use namespace for your vm class
Now you can access both properties from your model:
#foreach (var item in Model.Teams)
{
#item.Pld;
}

OrderByDescending doesn't exist?

I am not sure this is an error in my code or maybe something else messing with it however I have a function were I am creating a simple list from a MVC model in an ActionResult I have others that use OrderByDescending and work but this is throwing an error for some reason.
[Authorize(Roles = "Administrator, Manager, User")]
[SessionExpire]
public ActionResult PrepareShipment(int id,string sortOrder)
{
//ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
//ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
Order orderResult = (from o in db.Orders.Include("OrderItems").Include("OrderItems.Item")
where o.OrderID == id
select o).First();
orderResult = orderResult.OrderByDescending(o => o.Item.ItemName);
return View(orderResult);
}
That is my complete ActionResult the database has a table Order with another object called Item that object has a column called ItemName. I already have a view with a list in it done exclusively in the view but now I have to order that data by the item name. This is so every time an action is done on the page the list stays in the same order as when it first loaded. Right now every time I reload the page the list reorders.
Ok so I solved this in the foreach which I realize now I should have included in the original post
the orginal for each was this
#foreach (OrderItem item in Model.OrderItems) {
I fixed it by doing this to the foreach
#foreach (OrderItem item in Model.OrderItems.OrderBy(m => m.OrderItemID)) {
I never even knew you could add additional information like that to a foreach in c#
Thank you everyone for you patience with me :D

MVC many to many delete

I have many to many relationship some tables. I am using entity framework.
Reservations >> ApartsToReservations << Aparts
ApartsToReservations include ReservationID and ApartID.
and my delete action below:
public ActionResult DeleteReservation(string resultId)
{
var result = Convert.ToInt32(resultId.Trim());
//just I have reservationID
return View();
}
How can delete reservation?
How can delete reservation?
For example:
[HttpPost] // <- should be a POST action because it's modifying data
public ActionResult DeleteReservation(string resultId)
{
var result = Convert.ToInt32(resultId.Trim());
//just I have reservationID
using (var context = new MyContext())
{
var reservation = new Reservation { ReservationID = result };
context.Reservations.Attach(reservation);
context.Reservations.Remove(reservation);
context.SaveChanges();
}
// ... redirect to Index or something, for example:
// return RedirectToAction("Index");
}
If you already have a context instance as a member of your controller class use this instead of creating a new one in the using block.
The code will also delete the related records in the ApartsToReservations link table because by default the relationships to this table are configured with cascading delete.
I'm not quite sure if this is what you are looking for because it actually doesn't matter if Reservation is involved in the many-to-many relationship you mentioned. It is just the (or one) standard way to delete an entity with DbContext.
If you are looking for something different please try to clarify your question or ask a new one which is clearer.

How to move data access code from Controller to Repository

I have a Controller which returns a ViewModel to a View and it works just fine. I want to migrate to a Repository pattern but am having trouble getting the correct syntax in the repository. I have created the repository and the interface to it.
public interface IShippingRepository
{
IQueryable<ShippingCommHdr> All { get; }
IQueryable<ShippingCommHdr> AllIncluding(params Expression<Func<ShippingCommHdr, object>>[] includeProperties);
void InsertOrUpdate(ShippingCommHdr shippingcommhdr);
void Delete(int id);
void Save();
}
Here is the code form my Controller that I want to move to the repository:
public ViewResult ShippingSummary()
{
CPLinkEntities context = new CPLinkEntities();
var shipments =
from h in context.ShippingCommHdrs
where (h.CompletedDate == null)
join
e in context.vHr_Employees on h.CreatedBy equals e.ID
join
s in context.Shippers on h.ShipperID equals s.ShipperID
join
r in context.vAaiomsSites on h.ShipToSiteID equals r.SiteID
join
c in context.vHr_Employees on h.CreatedBy equals c.ID
join
p in context.vHr_Employees on h.FromSitePOC equals p.ID
select new
{
h.ID,
ShippedToSite = r.SiteName,
h.DateShipped,
h.EstDeliveryDate,
h.TrackingNo,
h.HeaderComments,
h.ShippingCommLI.Count,
s.Shipper,
CreatedBy = c.LastName,
FromSitePoc = p.LastName
};
var model = new List<ShippingSummaryVM>();
foreach (var h in shipments)
{
var viewModel = new ShippingSummaryVM
{
ID = h.ID,
ShippedToSite = h.ShippedToSite,
DateShipped = h.DateShipped,
EstDeliveryDate = h.EstDeliveryDate,
TrackingNo = h.TrackingNo,
FromSitePOC = h.FromSitePoc,
Shipper = h.Shipper,
HeaderComments = h.HeaderComments,
NumOrders = h.Count,
CreatedBy = h.CreatedBy,
};
model.Add(viewModel);
}
return View(model);
}
If I could get this one Controller/Repository to work, I can then migrate all the others over fairly quickly. thanks for any assistance
I'd start by adding a method definition to the repository interface for the query you need to execute. The repository can give this query a meaningful name:
public interface IShippingRepository
{
IQueryable<Shipment> GetShipments()
// ...
}
In the controller you'll need an instance of the repository. You can inject it into a constructor, or create one in a constructor, but either way the repository will need to talk to the CPLinkEntities context behind the scenes. You'll need to pass a context into the repository for the repository to work with.
public class SomeController : Controller
{
IShippingRepository _shippingRepository;
public SomeController()
{
_shippingRepository = new ShippingRepository(new CPLinkEntities());
}
public ViewResult ShippingSummary()
{
var shipments = _shippingRepository.GetShipments();
// ....
}
}
A concrete repository definition might look like the following.
public class ShippingRepository : IShippingRepository
{
CPLinkEntities _entities;
ShippingRepository (CPLinkEntities entities)
{
_entites = entities;
}
public IQueryable<Shipment> GetShipments()
{
return from ship in _entities.Ships join ... join ... select
}
}
Your controller method basically has 2 responsibilities
Run a Query
Map the results of the query into a view model
You can put that query into a repository, and then you could use an auto-mapper tool like AutoMapper or ValueInjecter to help you map the results of your query to a view model.
Your resulting controller method would simply call the repository to get a list of CPLinkEntities. Your controller method could then take those entities and then call the automapper to give you a list of ShippingSummaryVM's. I've left some implementation details, but this should give you a high level understanding of how to achieve what you are asking.
Option A: Have a stronger domain model. Your repository would responsible for loading root level domain objects and you let the underlying OR/M handle object traversal. Your controller would call a method on shipment to find shipments that are not yet completed. You'd get back a shipment object and could traverse to the related entities to get site name and other details you need for your VM
Option B: Have repositories that return all for each entity, and then do the join in a business or service layer. Entity Framework won't load all even if you say ShippingRepository.All. It only loads at the last responsible moment (when you need a materialized result). So you could have a business method that joins the "All" on each entity and filters based on completed date then returns back the result.
Option A is better but might be a lot more work.

MVC, UpdateModel OR delete depending on form field value?

I'm very new to this, so any help is appreciated.
I'll use the Dinners/RSVPs relationship for detailing my problem. One Dinner has many RSVPs.
On my Dinner edit page/view I want to be able to edit the Dinner information AND the RSVPs information.
I have that part working, based on the answer given here by James S:
int i = 0;
foreach (var r in Dinner.RSVPs) {
UpdateModel(r, "Dinner.RSVPs[" + i++ + "]");
}
But what if I want to Delete an RSVP based on the user clicking a checkbox next to the RSVP on the edit view? Something like this on the edit view:
<% int i = 0;
foreach (var rsvp in Model.RSVPs){%>
<%=Html.CheckBox("RemoveRSVP[" + i + "]") %>
<%= Html.TextBox("Dinner.RSVPs[" + i + "].Name", rsvp.Name) %>
<% i++;
}%>
I tried this, but it's not working, obviously:
Dinner dinner = dinnerRepository.GetDinner(id);
int i = 0;
foreach (var r in dinner.RSVPs) {
if (Boolean.Equals(RemoveRSVP[i], true){
dinner.RSVPs.Remove(r);
else
UpdateModel(r, "Dinner.RSVPs[" + i+ + "]");
i++;
}
I can't delete/remove an RSVP using UpdateModel can I?
Let me know if anything isn't clear.
Thanks.
I tried this, but it's not working, obviously:
Is your difficulty in actually making the delete go through? Or is it in processing the form to detect which ones should be deleted? e.g. which line doesn't work:
dinner.RSVPs.Remove(r);
or
if (Boolean.Equals(RemoveRSVP[i], true)
?
For #1
If your repository is backed by Linq 2 Sql and RSVP is an entity, you will usually have to cause DeleteOnSubmit() to be called in order for the record to be deleted from the database--just calling Remove() on the association will not be enough. You probably will add one of the following to your DinnerRepository to do this:
DinnerRepository.DeleteRsvp(RSVP item)
DinnerRepository.DeleteRsvp(Dinner dinner, RSVP rsvp)
Alternately, if you want LINQ to perform the delete automatically, you can edit the DBML as XML (right click, open with, XML Editor) and add the following attribute to the entity association:
<Association Name="..." ... DeleteOnNull="true" />
For #2
I usually construct this type of "repeating entity-delete checkbox" form so that the posted values are a list of the entity IDs I want to delete. To facilitate this I use an alternate CheckBox helper:
public static class HtmlExtensions
{
/// <summary>
/// Alternate CheckBox helper allowing direct specification of "name", "value" and "checked" attributes.
/// </summary>
public static string CheckBox(this HtmlHelper html, string name, string value, bool isChecked)
{
string tag = String.Format("<input type=\"checkbox\" name=\"{0}\" value=\"{1}\" {2}/>",
html.AttributeEncode(name),
html.AttributeEncode(value),
isChecked ? "checked=\"checked\" " : ""
);
return tag;
}
}
and create the checkboxes like so:
<%= Html.CheckBox("RemoveRsvpIds", rsvp.RsvpId.ToString(), false) %>
and consume the list like so:
public ActionResult TheFormInQuestion(int dinnerId, int[] removeRsvpIds)
{
var dinner = DinnerRepository.GetDinner(dinnerId);
foreach (var rsvp in dinner.RSVPs)
{
if (removeRsvpIds.Contains(rsvp.RsvpId))
{
// Perform Delete
}
else
{
// Perform Update
}
}
// The rest
}
I can't delete/remove an RSVP using UpdateModel can I?
The purpose of UpdateModel() is to automagically copy property values from the posted form onto an already-existing object--not to create new or destroy existing entities. So no, not really. It wouldn't be the expected behavior.
I am not totally familiar with the NerdDinner code but don't they use Linq to SQL for their backend? If that is the case I would think you could tackle this in a traditional web approach and append the record ID to the value of each check box in a list of items to be deleted. Then you could catch the collection of IDs on the server side and do a DeleteAllOnSubmit by passing a selection query of entities to the delete call? Let me know if you need more detail.

Resources