MVC 3 Entity Framework Empty Result Set - c#

I am working on an application in which it returns an excel report with each employee having multiple roles and their expected and actual hours for each role. For instance, I may be listed as a developer for one and a BA for another column!. The query it is using is returning an empty result set.
public ActionResult ExpectedVsActual()
{
try
{
ProjectTotalsReportViewModel model = new ProjectTotalsReportViewModel();
Employee currentUser = DataHelper.GetEmployee(User, db);
model.AvailableEmployees = db.Employees.OrderBy(e => e.LastName).ThenBy(e => e.FirstName).ToList();
if (currentUser.SecurityRoleCode == Constants.SECURITY_ROLE_CODE_ADMIN)
{
model.AvailableProjects = (db.Projects.Any() ? db.Projects.Where(p => p.ProjectCategoryCode == Constants.PROJECT_CATEGORY_DIRECT).OrderBy(p => p.ProjectName).Distinct().ToList() : new List<Project>());
model.ProjectRate = (db.EmployeeProjectRates.Any() ? db.EmployeeProjectRates.Where(epr => epr.EmployeeID == epr.EmployeeID).OrderBy(epr => epr.EmployeeID).Distinct().ToList(): new List<EmployeeProjectRate>());
}
else
{
model.AvailableProjects = (db.EmployeeProjectRates.Any(epr => epr.EmployeeID == currentUser.EmployeeID && epr.ProjectRoleCode == Constants.PROJECT_ROLE_PROJECT_MANAGER) ? db.EmployeeProjectRates.Where(epr => epr.EmployeeID == currentUser.EmployeeID && epr.ProjectRoleCode == Constants.PROJECT_ROLE_PROJECT_MANAGER).Select(epr => epr.Project).OrderBy(p => p.ProjectName).Distinct().ToList() : new List<Project>());
}
model.SelectedEmployeesForCheckBox = model.AvailableEmployees;
model.SelectedProjectsForCheckBox = model.AvailableProjects;
ViewBag.InitialLoad = true;
return PartialView("_ExpectedVsActual", model);
}
catch
{
return null;
}
}
[HttpPost]
public ActionResult ExpectedVsActual(ProjectTotalsReportViewModel Model)
{
try
{
if (ModelState.IsValid)
{
ViewBag.InitialLoad = false;
DataHelper.TimeFrame selectedTimeFrame = DataHelper.TimeFrame.Weekly;//Need to remove after adding selection for time frame
SMCContext db = new SMCContext();
ViewBag.TimeFrameSelectList = DataHelper.GetTimeFrameSelectList();
List<ProjectTimeFrame> timeFrames = new List<ProjectTimeFrame>();
ProjectViewModel Project = new ProjectViewModel();
timeFrames = DataHelper.GetProjectTimeFrames(Model.StartDate.Value, Model.EndDate.Value, selectedTimeFrame);
Project.EmployeeProjectRates = Project.EmployeeProjectRates.OrderBy(epr => epr.Employees.Single(e => e.Value == epr.EmployeeID.ToString())).ToList();
resultFile = currentPackage.GetAsByteArray();
return File(resultFile, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Expected Vs Actual.xlsx");
}
#endregion
}
else
{
return PartialView("_ExpectedVsActual", Model);
}
}
catch (Exception e)
{
throw e;
}
}
The bulk of all the formatting and creation of the file I left out, it is not related to the empty result. The result should look like this

It's failing for you on at least one of three points:
Verify the data in your database reflects what you're searching for. The quickest way to do this is through some sort of profiler that can capture your EF query as it is transformed and show you the SQL statement. linqpad is a great tool to do this with.
Verify your mappings. You might not have your relationships mapped correctly, producing no data to yield.
Verify your own constraints. It looks like you have permission-based lookups. Place a breakpoint after the current user is fetched and make sure it has the permission to match the permission you're looking for (Constants.SECURITY_ROLE_CODE_ADMIN) in your conditional.

Related

How can I append mutliple results from context to one list/variable LINQ C#

I'm working on small app for fetching products/articles, and I wrote a method that's getting articles by type. (types are contained in request arg).
What I'm trying to achieve is: append all results (from all if conditions if they are satisfied) to one main list which should be returned to customer..
When I'm debugging and checking query it says its returning type is IQueryable<Article> so basically my question is how can I append multiple IQueryables into one which should be returned to user..
This code below is not working because result is always empty..
I've tried also with var result = new List<Article>(); and later result.AddRange(query); and I've changed also return type to
return await result.AsQueryable().ToListAsync(); but obviously something breaks somewhere and I get an empty array at the end.
public async Task<IEnumerable<Article>> GetArticlesByType(ArticleObject request)
{
var result = new Article[] { }.AsQueryable();
IQueryable<ArticleDTO> query = null;
if (request.Food.HasValue && (bool)request.Food)
{
// Return type of query is IQueryable<Article>
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Food).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Here I just wanted if this condition is satisfied to add values to my result
result.AsQueryable().Union(query);
}
if (request.Drink.HasValue && (bool)request.Drink)
{
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Drink).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Again if there are any values in query add them to existing result values
result.AsQueryable().Union(query);
}
if (request.Candy.HasValue && (bool)request.Candy)
{
// When its candy I want also articles from food category
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Food || x.ArticleType == ArticleType.Candy).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Again if there are values in query add them to existing result
result.AsQueryable().Union(query);
}
//At the end return result and all the values in case all conditions were satisfied
return await result.ToListAsync();
}
Try with result.AsQueryable().Union(query.ToList());. This will fetch the object from database. So far query contains references to objects in database and not in your memory

Remove certain properties from object upon query EF Core 2.1

I'm trying to null or remove the ID entirely of all the queried IsoDataTables before returning them to frontend. The idea is that it should behave (in this case) as a template and I don't want it returning the id's back to me, nor do I want them to be removed in the frontend.
var applicationType = await _context.ApplicationType
.Include(m => m.IsoTableData)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.Id == id);
if (applicationType == null)
{
return NotFound();
}
if (applicationType.IsoTableData != null)
{
foreach (IsoTableData isoTableData in applicationType.IsoTableData)
{
// error since it a not nullable primary key
isoTableData.Id = null;
}
}
return Ok(applicationType);
I have found a workaround in which I duplicate the objects and return them (without saving to DB) but I'm looking for a more elegant solution.
The way I did it was create a copy constructor (or basically, a new instance of an object) with the desired fields; I chose a copy constructor as this logic is recurent in other places as well. Another similar solution is creating a DTO object, but I don't need it here. Any improvements?
//in IsoFileApplicationType.cs
public IsoFileApplicationType(IsoFileApplicationType isoFileApplicationType)
{
Id = null
FullName = isoFileApplicationType.FullName;
Name = isoFileApplicationType.Name;
(...)
foreach (IsoTableData isoTableData in isoFileApplicationType.IsoTableData)
{
IsoTableData.Add(IsoTableData(isoTableData));
}
}
//in IsoTableData.cs
public IsoTableData(IsoTableData isoTableData)
{
Id = null;
Data = isoTableData.Name;
Age = isoTableData.Age;
(...)
}
// in CRUD controller
var applicationType = await _context.ApplicationType
.Include(m => m.IsoTableData)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.Id == id);
if (applicationType == null)
{
return NotFound();
}
IsoFileApplicationType newIsoFileApplicationType = IsoFileApplicationType(applicationType);
return Ok(newIsoFileApplicationType);

InvalidOperationException: An operation is already in progress

I am using Asp.net core Razor engine Entity Framework. I keep getting the error above and it from what I have read, it refers to the the db already being used for an operation. I am not sure why this would be happening. Is is because it is in a foreach loop? What would the workaround be? Here is my code
[HttpGet]
[Route("currentSession")]
public IActionResult CurrentSession()
{
var id = HttpContext.Session.GetInt32("Id");
if(id != null)
{
var user = _context.User.FirstOrDefault(x => x.Id == id);
ViewBag.User = user;
ViewBag.User_Id = id;
ViewBag.Auction = _context.Auction.AsEnumerable();
foreach(var item in ViewBag.Auction)
{
if(item.End_Date < DateTime.Now)
{
var seller_id = (int)item.Id_Of_Seller;
var seller = _context.User.FirstOrDefault(x => x.Id == seller_id); //this is the line that causes the error in the title
var bidder_id = (int)item.Id_Highest_Bid;
var buyer = _context.User.FirstOrDefault(x => x.Id == bidder_id); //this line also causes the same error
buyer.Wallet -= item.Bid;
seller.Wallet += item.Bid;
_context.Auction.Remove(item);
_context.SaveChanges();
}
}
return View("Home");
}
return RedirectToAction("LoginPage");
}
Can you try replacing AsEnumerable with ToList?
ViewBag.Auction = _context.Auction.ToList();
I added MultipleActiveResultSets=True to my sql server connection strings and this fixed the exception. No other changes were needed.
This fixed the async methods, the background tasks and IQueryable loops for me.

Linq - Excluding users from list in IQueryable expression - What is the correct way?

In order to ease up a number of things, I have created a base class for user "management". This is not the same as account management, which is already provided.
This is my base class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using Microsoft.AspNet.Identity.EntityFramework;
namespace ARSoftwareV2.UserLibrary
{
// This is a base class for all user needs. If you want to implement your own set of checks,
// you can simply inherit from this class and you get pretty much everything you need already set up.
public class UserClassBase
{
private Models.ApplicationDbContext DefaultContextInstance;
// We only want to show the "final results" here, not what should be hidden.
protected Models.ApplicationDbContext CreateNewContext()
{
return new Models.ApplicationDbContext();
}
protected Models.ApplicationDbContext DefaultContext
{
get
{
if ( DefaultContextInstance == null)
{
DefaultContextInstance = CreateNewContext();
}
return DefaultContextInstance;
}
}
// This lists users based on a number of criteria.
// Called without arguments, the query lists all users which are:
// - Enabled
// - Not deleted
// - Not employees (this isn't done yet)
public IQueryable<Models.ApplicationUser> GetUserListQuery(bool IncludeDisabled = false, bool IncludeDeleted = false,bool IncludeEmployees = false )
{
IQueryable<Models.ApplicationUser> result;
using (DefaultContext)
{
IQueryable<Models.ApplicationUser> UserQueryIncludeAll = (from user in DefaultContext.Users select user);
result = UserQueryIncludeAll;
if (!(IncludeEmployees == true))
{
// I need to make a join here to exclude employees by the user list.
}
if ((IncludeDisabled == false) && (IncludeDeleted == false))
{
result.Where(u => u.Enabled == true && u.Deleted == false);
}
else if (IncludeDisabled == true)
{
result.Where(u => u.Deleted == true);
}
else if (IncludeDeleted == true)
{
result.Where(u => u.Enabled == true);
}
}
return result;
}
public bool UserEmailExists( string EmailToCheck )
{
IQueryable<Models.ApplicationUser> Query = GetUserListQuery().Where(u => u.Email == EmailToCheck && u.Roles.Contains();
IList<Models.ApplicationUser> resultList = Query.ToList<Models.ApplicationUser>();
return (resultList.Count >0);
}
public Models.ApplicationUser FindUserByID( string ID)
{
IQueryable<Models.ApplicationUser> Query = GetUserListQuery().Where(u => u.Id == ID);
Models.ApplicationUser result = Query.FirstOrDefault();
return result;
}
public string[] UserRoles( string UserID )
{
Models.ApplicationUser User;
User = FindUserByID(UserID);
IList<string> result = new List<string>;
foreach( var r in User.Roles )
{
result.Add(r.ToString());
}
return result.ToArray<string>();
}
}
}
The idea behind this is that I can then use it both from the registration/login infrastructure and from a web service.
So, the problem I have is that - if employees have to be excluded - I need a way to identify the role. This, I would think, has to be done via a join. Unless you know of a better way to do it, of course :)
Sooo, my question is: what is the best way to exclude users which have an employee role? If - as I think - that has to be a join, can you please suggest a syntax that works for my case? I have googled and VS2015 seems intent on marking any attempt with a squiggly red mark :)
So far, I have tried the following way:
if (!(IncludeEmployees == true))
{
// I need to make a join here to exclude employees by the user list.
result.Join(DefaultContext.Roles, r => Roles, Users => Users, Users.ID = r.UserID);
}
And I also tried this way:
if (!(IncludeEmployees == true))
{
innerResult = (from u in UserQueryIncludeAll select u).Join(DefaultContext.Roles, r => Roles, u.Id = r.UserID);
}
Looking at the similar questions, there's an answer that implies I need multiple contexts to do this. Is that correct?
Can you please point me at what I am doing wrong?
Use navigation properties instead of manual joins, like this
result = result.Where(user => !user.Roles.Any(role => role.Id == "Employee"));
Btw, your code is missing the result assignments like above, so it does not do any filtering at all. The other thing that is wrong is the using (DefaultContext) statement because you are disposing a cached instance member. The whole procedure can be simplified like this
public IQueryable<Models.ApplicationUser> GetUserListQuery(bool IncludeDisabled = false, bool IncludeDeleted = false, bool IncludeEmployees = false )
{
IQueryable<Models.ApplicationUser> result = DefaultContext.Users;
if (!IncludeDisabled)
result = result.Where(user => user.Enabled);
if (!IncludeDeleted)
result = result.Where(user => !user.Deleted);
if (!IncludeEmployees)
result = result.Where(user => !user.Roles.Any(role => role.Id == "Employee"));
return result;
}

WHERE IN clause

I'm working in MVC3 project. I was browsing for a while and trying several examples but I could not get it working.
I need to get a list of record from OrderForm table whose DeptID are in another list I already have got.
I'm aware that I need to use Contains() replacing IN SQL clause, but every example that I could read are doing this in the same way
.Where(ListOfDepartments.Contains(q.DeptID))
This is my method at the controller, which obviously is not working:
public ActionResult ValidOrders(string installation, string orderpriority, string stockclass, string validity)
{
int instID = System.Convert.ToInt32(installation);
int orderpriorityID = System.Convert.ToInt32(orderpriority);
int stockclassID = System.Convert.ToInt32(stockclass);
string period = validity;
try
{
var departments = dba.Department
.Where (a => a.InstID == instID);
var valid = dba.OrderForm
.Where(q => q.FormType == 3
&& q.FormStatus == 2
&& q.OrderPriority.OrderPriorityID == orderpriorityID
&& q.StockClassID == stockclassID
&& departments.Contains(q.DeptID));
return View(valid.ToList());
}
catch (Exception)
{
return View("Error");
}
}
What I'm doing wrong?
you need a list of int, not Department.
var departments = dba.Department
.Where (a => a.InstID == instID)
.Select(d => d.Id);//Id is a guess, it maybe another property name
//.ToList();

Categories