WHERE IN clause - c#

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();

Related

Cannot implicitly convert type to System.Collections.Generic.List to System.DateTime

I need to add 2 columns(LastTaskCreatedDate & LastTaskUpdatedDate) for a table. I have the query for that 2coulums and I just need to call that query into my repo function.
My repo function already has a query inside it which get the other columns inside it. As i cant add another query inside, I creayed a function in it and added that query inside it.
Please look into the Screenshots for better clarity.
enter image description herepic- The query which gets those two columns inside.
This is the repo funtion which gets the table data inside that and here i need to add those 2 columns also
public WebStationResponse Filter(ProjectsFilter objFilter)
{
try
{
// Taking common project ids
var projectIds = _currentUser.AccessInfo.UserProjects.Select(up => up.ProjectID).ToList();
if (objFilter.ProjectID == null || objFilter.ProjectID.Count == 0)
{
objFilter.ProjectID = projectIds;
}
objFilter.ProjectID = objFilter.ProjectID.Intersect(projectIds).ToList();
objFilter.SetSqlPagingValues();
objFilter.CompanyID = _currentUser.AccessInfo.CompanyID;
objFilter.UserID = _currentUser.AccessInfo.UserID;
objFilter.ServerTimezone = DefaultRepository.ServerTimezoneOffset();
objFilter.UserTimezone = _currentUser.TimeZoneDetails.BaseUTCOffset;
string strQuery = Project.GetProjects(objFilter);
IList<ProjectDetails> lstProjectDetails = _dbContext.Database.Query<ProjectDetails>(strQuery,objFilter).ToList();
if (lstProjectDetails.Count == 0)
{
base.ResponseObject.ResponseId = (int)ResponseCode.RecordDoesnotExist;
return base.ResponseObject;
}
//
int intRecordCount = lstProjectDetails.Count;
if(objFilter.Pagination)
{
intRecordCount = _dbContext.Database.ExecuteScalar<int>(Common.RecordCount());
}
FillPermissions(ref lstProjectDetails);
FillProjectCompetencies(ref lstProjectDetails);
**FillLastDates(ref lstProjectDetails); **
base.FillResponseDetails(null,lstProjectDetails,null);
base.ResponseObject.RecordCount = intRecordCount;
}
catch (Exception ex)
{
base.FillResponseDetails(ex, null, null);
}
return base.ResponseObject;
}`your text`
This is the function I added and inside it has the query- GetLastTaskUpdateDates.
private void FillLastDates(ref IList<ProjectDetails> lstProjects)
{
if (lstProjects == null || lstProjects.Count == 0)
{
return;
}
//
var projectIds = lstProjects.Select(p => p.ProjectID).ToList();
string strQuery = Project.GetLastTaskUpdatedDates();
IList<ProjectDetails> lstDates = _dbContext.Database.Query<ProjectDetails>(strQuery, new { ProjectID = projectIds }).ToList();
//
ProjectDetails objProject = null;
for (int intIndex = 0; intIndex < lstProjects.Count; intIndex++)
{
objProject = lstProjects[intIndex];
lstProjects[intIndex].LastTaskCreated = lstDates.Where(c => c.ProjectID == objProject.ProjectID).ToList();
lstProjects[intIndex].LastTaskUpdated= lstDates.Where(c =>c.ProjectID == objProject.ProjectID).ToList();
}
}`your text`
If we look at last two lines, I am getting this error- Cannot implicitly convert type to System.Collections.Generic.List to System.DateTime
Need help!!, Please reply for any other clarity on the problem
Gave everything in the details of the problem
LastTaskCreate and LastTaskUpdated are DateTime and you try to put lists instead of DateTimes, it's normal.
You must get only one date from the list you have. I think what you're looking for is something like that (assuming that lstDates is a list of dates):
var projectDates = lstDates.Where(c => c.ProjectID == objProject.ProjectID).OrderBy(e => e); // Ordered IEnumerable (it's a list but a bit different) of dates from the oldest to the newest
lstProjects[intIndex].LastTaskCreated = projectDates.First(); // Gives the first elem of the enumerable, should be the date of creation
lstProjects[intIndex].LastTaskUpdated = projectDates.Last(); // Gives the last elem of the enumerable, should be the last update date
I didn't put the null checkers but you might want to add some to be sure that projectDates is not empty.
If lstDates is a list of projects, the code could be this:
var project = lstDates.FirstOrDefault(c => c.ProjectID == objProject.ProjectID);
if (project != null)
{
lstProjects[intIndex].LastTaskCreated = project.LastTaskCreated
lstProjects[intIndex].LastTaskUpdated = project.LastTaskUpdated
}
but it depends on what's inside ProjectDetails.
Hope it helped
Although I don't fully understand what's going on in your scenario, the error seems to be fairly explainatory?
lstProjects[intIndex].LastTaskCreated
expects a Datetime, whereas
lstDates.Where(c => c.ProjectID == objProject.ProjectID).ToList();
is a list of ProjectDetails.
I suspect you want something like:
lstProjects[intIndex].LastTaskCreated = lstDates.First(c => c.ProjectID == objProject.ProjectID).LastTaskCreated;

The LINQ expression could not be translated - EF Core

In summary, I'm guessing I can't add any more complex calculations to the LINQ expression. Any tips are greatly appreciated!
This blazor project is using a messy employee table which contains two types of employees, both on the same table
Domestic employees, uses NRG number to identify them, but their NRG numbers are stored as string at NRG column, like "0356".
Foreign employees, also uses NRG to identify them, but their NRG column contains all NULL, their NRG numbers are inside their emails at AzureEmail column, like "johndoe.0356#aaa-bbb.com"
When domestic employee or foreign employee enter their sales records, they are the "Closer", it is required to enter the "Setter" NRG.
By using the "Setter" NRG number "closer" entered, I want to locate the "Setter" info from the same employee table:
public async Task Save_to_SalesForm()
{
await using var context3 = await DBContextFactory.CreateDbContextAsync();
{
if (salesForm.SetterNrg != null && salesForm.CsTransferCategory == "Local Team")
{
setterEmployee = context3.Employees.Where(
e => e.AzureAccountEnabled == 1
&&
(int?)(object?)e.Nrg == salesForm.SetterNrg
).OrderByDescending(e => e.EmployeeId).FirstOrDefault();
salesForm.SetterAgentFullName = setterEmployee.AzureFullName;
salesForm.SetterJobTitle = setterEmployee.AzureRole;
salesForm.SetterEmail = setterEmployee.AzureEmail;
salesForm.SetterTeam = setterEmployee.AzureTeam;
}
if (salesForm.SetterNrg != null && salesForm.CsTransferCategory == "CSR Team (Philippines)")
{
setterEmployee = context3.Employees.Where(
e => e.Nrg == null
&&
e.AzureAccountEnabled == 1
&&
e.AzureEmail.Contains("#aaa-bbb.com")
&&
(int?)(object?)e.AzureEmail.Split(new char[] { '.', '#' }, StringSplitOptions.RemoveEmptyEntries)[1] == salesForm.SetterNrg
).OrderByDescending(e => e.EmployeeId).FirstOrDefault();
salesForm.SetterAgentFullName = setterEmployee.AzureFullName;
salesForm.SetterJobTitle = setterEmployee.AzureRole;
salesForm.SetterEmail = setterEmployee.AzureEmail;
salesForm.SetterTeam = setterEmployee.AzureTeam;
}
}
context3.SalesForms.Add(salesForm);
await context3.SaveChangesAsync();
}
If the "Setter" is a domestic employee (Local Team), the above query works fine and be able to save the setter info to the table
If the "Setter" is a foreign employee (CSR Team (Philippines)), the above query won't work due to the .Split make the query too complex for LINQ expression. Error screenshot
I tried multiple ways to resolve the issue, but none seemed ideal.
I have rewritten your query to use EndsWith, which is translatable to the SQL:
public async Task Save_to_SalesForm()
{
await using var context3 = await DBContextFactory.CreateDbContextAsync();
if (salesForm.SetterNrg != null)
{
Employee? setterEmployee = null;
if (salesForm.CsTransferCategory == "Local Team")
{
setterEmployee = await context3.Employees
.Where(e => e.AzureAccountEnabled == 1
&& (int?)(object?)e.Nrg == salesForm.SetterNrg)
.OrderByDescending(e => e.EmployeeId)
.FirstOrDefaultAsync();
}
else if (salesForm.CsTransferCategory == "CSR Team (Philippines)")
{
var toCheck = $".{salesForm.SetterNrg}#aaa-bbb.com";
setterEmployee = await context3.Employees
.Where(e => e.Nrg == null && e.AzureAccountEnabled == 1
&& e.AzureEmail.EndsWith(toCheck))
.OrderByDescending(e => e.EmployeeId)
.FirstOrDefaultAsync();
}
if (setterEmployee != null)
{
salesForm.SetterAgentFullName = setterEmployee.AzureFullName;
salesForm.SetterJobTitle = setterEmployee.AzureRole;
salesForm.SetterEmail = setterEmployee.AzureEmail;
salesForm.SetterTeam = setterEmployee.AzureTeam;
}
}
context3.SalesForms.Add(salesForm);
await context3.SaveChangesAsync();
}
The problem is in e.AzureEmail.Contains("#aaa-bbb.com"), there is no equivalent in sql to this. Try EF.Functions.Like(e.AzureEmail, "%#aaa-bbb.com%"). Everything from your expression will work if you materialize your data with .ToList() or something and perform it on the client, but it is extremely inefficient.

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

MongoDB projection toListAsync() method not supported

I am trying to use projection in my query and get the following error:
"The result operation MongoDB.Driver.Linq.Expressions.ResultOperators.ListResultOperator is not supported."
Here is the code:
public async Task<IEnumerable<Listing>> LoadAllUserListings(string userId)
{
var result = _context.Listing.Aggregate().Match(l => l.OwnerId == userId || l.Sales.Any(a => a.Owner.Id == userId)).
Project(l => new Listing
{
Id = l.Id,
Reference = l.Reference,
OwnerId = l.OwnerId,
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId).ToList(),
Products = l.Products,
Status = l.Status,
DueDate = l.DueDate
}).ToListAsync();
return await result;
}
It does not appear to like the ToListAsync call. I got this code snippet from the following answer:
https://stackoverflow.com/questions/50904811/mongodb-c-sharp-filter-and-get-all-subdocuments
There reason I am using projection is to omit some fields which the user should not see (depending on the role). Any help on this would be appreciated.
Thanks in advance.
The problem occurs in that line:
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId).ToList()
What happens here ? MongoDB driver takes this expression and tries to translate it to aggregation framework syntax. There's a $filter operator which can be run on nested collection and driver is able to translate .Where() to that operator however there's nothing corresponding for .ToList() at the end of that expression and that's why it fails.
So the fix is fairly easy: you just need to use IEnumerable<T> instead of List<T> for Sales property and then get rid of that .ToList() so your code will look like this:
public async Task<IEnumerable<Listing>> LoadAllUserListings(string userId)
{
var result = _context.Listing.Aggregate().Match(l => l.OwnerId == userId || l.Sales.Any(a => a.Owner.Id == userId)).
Project(l => new Listing
{
Id = l.Id,
Reference = l.Reference,
OwnerId = l.OwnerId,
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId),
Products = l.Products,
Status = l.Status,
DueDate = l.DueDate
}).ToListAsync();
return await result;
}

How can I get multiple data?

I can show just one customer, I know the problem is because I use FirstOrDefault in my LINQ.
How can get another customer? I still don't understand the concept of IQueryable or IEnumerable.
public int getNota(DateTime dt, int lap)
{
DataClassesPelleDataContext myDb = new DataClassesPelleDataContext();
var nota = (from u in myDb.TBL_TRANSAKSI_SEWA_LAPANGAN_REGULERs
where u.TGL_PEMAKAIAN.Value.Date == dt.Date && u.ID_LAPANGAN == lap
select u.ID_SEWA).FirstOrDefault();
return nota;
}
I dont know for sure what you are trying to achive
But you can use
var notasIds = yDb.TBL_TRANSAKSI_SEWA_LAPANGAN_REGULERs
.Where(u => u.TGL_PEMAKAIAN.Value.Date == dt.Date && u.ID_LAPANGAN == lap)
.Select(n => n.ID_SEWA)
.ToList();
and then loop over the notas with
foreach (var sewaId in notasIds)
{
// to logic here
}
You can also comment .Select() call and get whole objects.
Regars

Categories