If/else selected count from sql database - c#

What I'm doing now is getting my SQL database table: IsAcross varchar(45) into my if/else statement. My IsAcross table only consist of YES and NO.
So now I want to take out only select YES statement from SQL Server, so therefore I have put the thingy in the whole list first. Then I use if/else statement to extract out the YES but how am I supposed to do that?
Example: I have a total of 7 items in a list, 4 yes 3 no. I want to take out the all the 4 yes only. Something like that:
ViewModels.WordSearchVM wsvm = new ViewModels.WordSearchVM();
wsvm.ActivityID = id;
var results = db.CrossPuzzles.Where(m => m.ActivityID == id)
.Select(m => m.IsAcross)
.AsEnumerable()
.ToList();
if (results = "yes")
{
else
}

As far as I understand your problem, you can forget your if statement and simply extend the .Where part:
.Where(m => m.ActivityID == id && m.results=="yes")

var results = db.CrossPuzzles.Where(m => m.ActivityID == id)
.Where(m => m.IsAcross)
.AsEnumerable()
.ToList();
//OR
var results = db.CrossPuzzles.Where(m => m.ActivityID == id)
.Where(m => m.IsAcross == "YES")
.AsEnumerable()
.ToList();

var results = db.CrossPuzzles
.Where(m => m.ActivityID == id)
.Select(m => m.IsAcross)
.Where(x => x == "YES") // filter to "YES"
.ToList();
if (results.Count > 0)
// YES
else
// NO
This what you're looking for?

Related

EF cannot translate query

I have query for getting data
await _dbContext.VwJobSupplierWithScores
.Where(x => x.JobId == jobId && x.SupplierKey == supplierKey)
.OrderBy(x => x.SpendCurrencyJob)
.Select((x, i) => new {item = x, index = i})
.FirstOrDefaultAsync())!,
But for some reasons EF cannot translate it and I get this error
The LINQ expression 'DbSet()
.Where(x => (Guid?)x.JobId == __jobId_0 && x.SupplierKey == __supplierKey_1)
.OrderBy(x => x.PurchaseOrderValueCurrencyJob)
.Select((x, i) => new {
item = x,
index = i
})' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
How I can write it correctly, that LINQ can translate it?
One option, do as the error told you:
await _dbContext.VwJobSupplierWithScores
.Where(x => x.JobId == jobId && x.SupplierKey == supplierKey)
.OrderBy(x => x.SpendCurrencyJob)
.AsEnumerable()
.Select((x, i) => new {item = x, index = i})
.FirstOrDefaultAsync())!
Another option:
var dbObject = await _dbContext.VwJobSupplierWithScores
.Where(x => x.JobId == jobId && x.SupplierKey == supplierKey)
.OrderBy(x => x.SpendCurrencyJob)
.FirstOrDefaultAsync();
var yourmodel = new { item = dbObject, index = 0 };
Please note that some parts of your original code are completely pointless. Using the "!" after calling FirstOrDefault yourself? If you know there will always be one, just call First. The saving of the index? What do you think the index of the first element will be? So... there is actually no point in having your anonymous object, because the data it holds is redundant. I have shown two ways to make your compiler happy, but you should think about why the code does these weird things in the first place.
Such Select overload is not supported by EF and I actually do not see reason to use that. FirstOrDefaultAsync will return one entity and Index will be always ZERO:
await _dbContext.VwJobSupplierWithScores
.Where(x => x.JobId == jobId && x.SupplierKey == supplierKey)
.OrderBy(x => x.SpendCurrencyJob)
.Select(x => new {item = x, index = 0})
.FirstOrDefaultAync();
Your Problem is, the select not matching the objects in VmJobSupplierQithScores. EF tries to map your Query to that type. Because you do a select with a different type, it can not translate that query.
You can split your query into something like this.
var item = _dbContext.VwJobSupplierWithScores
.Where(x => x.JobId == jobId && x.SupplierKey == supplierKey)
.OrderBy(x => x.SpendCurrencyJob).First();
var result = new {item = x, index = 0};

Is there a way to simplify these linq statements using an .Include()?

Currently I am doing a keyword search on the Plates table (Name column) but also have a Search (searching on SearchTerm column) table which contains Plat Id's that I also want to search and return the corresponding platforms.
The code below works but I'd like to simplify the logic using an .Include statement if possible although I'm not quite sure how. Any help would be greatly appreciated.
if (!string.IsNullOrEmpty(request.Keyword))
{
var searchTermPlateIds = await _db.Search
.Where(x=> x.SearchTerm.ToLower().Contains(request.Keyword.Trim().ToLower()))
.Select(x => x.PlatformId)
.ToListAsync(ct);
var plateFromPlateIds = await _db.Plate
.OrderBy(x => x.Name)
.Where(x => searchTermPlateIds.Contains(x.Id) && x.Status != PlateStatus.Disabled)
.ToListAsync(ct);
plates = await _db.Plates
.OrderBy(x => x.Name)
.Where(x => !string.IsNullOrEmpty(request.Keyword.Trim()) && x.Name.ToLower().Contains(request.Keyword.Trim().ToLower()) && x.Status != PlateStatus.Disabled)
.ToListAsync(ct);
plates = plates.Union(platesFromPlateIds).ToList();
}
Remember simple thing, Include ONLY for loading related data, not for filtering.
What we can do here - optimize query, to make only one request to database, instead of three.
var query = _db.Plates
.Where(x => x.Status != PlateStatus.Disabled);
if (!string.IsNullOrEmpty(request.Keyword))
{
// do not materialize Ids
var searchTermPlateIds = _db.Search
.Where(x => x.SearchTerm.ToLower().Contains(request.Keyword.Trim().ToLower()))
.Select(x => x.PlatformId);
// queryable will be combined into one query
query = query
.Where(x => searchTermPlateIds.Contains(x.Id);
}
// final materialization, here you can add Includes if needed.
var plates = await query
.OrderBy(x => x.Name)
.ToListAsync(ct);

C# Entity Framework. Simplify query

How to simplify the next query to database:
public Plan? Get(DateTime now)
{
return context.Plans
.Where(x => IsActivePlan(x, now)) // 1 condition
.Where(x => IsPlolongingPlan(x, now)) // 2 condition
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}
What I need:
If there are objects after 1 condition, then execute "OrderBy" and return the first element. If there are no objects, then go to the 2 condition, execute "OrderBy" and return "FirstOrDefault". I don't want the objects to be taken at once by two conditions.
Thank you
something like this
public Plan? Get(DateTime now)
{
return context.Plans.Where(x => IsActivePlan(x, now)).OrderBy(x => x.StartedAt).FirstOrDefault()
?? context.Plans.Where(x => IsPlolongingPlan(x, now)).OrderBy(x => x.StartedAt).FirstOrDefault();
}
because you don't want two conditions been true at once you have to:
return context.Plans
.Where(x => (IsActivePlan(x, now) && !IsPlolongingPlan(x, now)) ||
(!IsActivePlan(x, now) && IsPlolongingPlan(x, now)))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
You can check before if exist any
Like this:
var result = null;
if (context.Plans.Any(x => IsActivePlan(x, now)))
{
result = context.Plans.Where(x => IsActivePlan(x, now))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}
else
{
result = context.Plans.Where(x => IsPlolongingPlan(x, now))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}

Getting no results from simple Query

I've tried the following and it returned me every Tutor
List<Tutor>tutorsList = tutors.ToList();
Furthermore, I tried to select only Tutors with a specific subject (Tutor-Subject is n:n)
Subject subjectEntity = subjects.Where(s => s.Name == input).FirstOrDefault();
List<Tutor>tutorsList = tutors.Where(t => t.Subjects.Contains(subjectEntity)) .ToList();
As a result, my tutorsList is empty, even subjectEntity is correct (I printed it to console).
But when I loop every Tutor and print the Subjects, there is a Tutor with Subject input.
Any ideas?
If you also have id's, you can do the following:
Subject subjectEntity = subjects
.Where(s => s.Name == input)
.FirstOrDefault();
List<Tutor> tutorsList = tutors
.Where(t => t.Subjects
.Select(x => x.SubjectId)
.Contains(subjectEntity.SubjectId)
)
.ToList();
If not, you can try to do it in a single query
List<Tutor> tutorsList = tutors
.Where(t => t.Subjects.Any(x => x.Name == input))
.ToList()
simplify in one line, using Any, when working on an inner collection.
var tutorsList = tutors.Where(t => t.Subjects
.Any(s => s.Name == input)).ToList();
Try below
Subject subjectEntity = subjects.Where(s => s.Name == input).FirstOrDefault();
List<Tutor>tutorsList = tutors.Where(t => t.Subjects.Any(x=>x.UniqueField==subjectEntity.UniqueField)).ToList();

I want to convert this foreach loop to a LINQ statement

I am not an great at linq by any means but I usually have no issues with a problem of this sort. I want to convert this foreach statement to a LINQ statement:
var existingKeys = new List<int>();
foreach (var taskKey in request.Keys)
{
existingKeys.AddRange(_context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
.Select(x => x.TaskGroupNameKey));
}
I thought this would do it:
var existingKeys = request.Keys.ForEach(taskKey => _context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
.Select(x => x.TaskGroupNameKey));
That apparently returns a void not a list...
This:
var existingKeys = request.Keys.Select(taskKey =>
_context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
.Select(keys => keys.TaskGroupNameKey));
Gives me an "IEnumerable<IQueryable<int>>. So what is the secret sauce that I am missing here?
You shouldn't be performing N database queries in the first place. Using LINQ to perform those N queries instead of a foreach loop doesn't fix that core problem.
You need to re-conceptualize your query so that you have just one query that gets all of the data that you need. In this case that means getting all of the items that match your collection of keys rather than trying to match a single key and then performing N of those queries.
var requestedKeys = request.Keys;
var existingKeys = _context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key &&
requestedKeys.Contains(x.TaskKey))
.Select(x => x.TaskGroupNameKey))
.ToList();
var existingKeys = request
.SelectMany(r => r.Keys)
.SelectMany(tk =>
_context.WebTaskGroups
.Where(x.TaskGroupNameKey == key && x.TaskKey == tk)
.Select(x => x.TaskGroupNameKey))
.ToList();
var existingKeys = _context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key && request.Keys.Contains(x.TaskKey))
.Select(x => x.TaskGroupNameKey)
.ToList();
ForEach return a void: http://msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.110).aspx
ForEch: Performs the specified action on each element of the List.
So what to do, is for each item in the list of request.Keys to perform the action to add to the list of existingKeys.
For example:
request.Keys.ForEach(taskKey =>
existingKeys.AddRange(_context.WebTaskGroups
.Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
.Select(x => x.TaskGroupNameKey));

Categories