LINQ query with boolean check - c#

I need a method which should return a list of stores from stores table, where customerid = id and Isactive = "true".
I am able to get the customerid match like so, how can I also include the Boolean check... need help with the query syntax..the "AND" operator
private IList<Store> GetStores(int id)
{
var stlist = db.Stores.Where(m => m.CustomerId == id).ToList();
return (stlist);
}

Assuming that Isactive is a property of records in db.Stores, like CustomerId is
You can just add the additional check inside the Where extension method:
Assuming that Isactive is a property of type bool
private IList<Store> GetStores(int id)
{
var stlist = db.Stores.Where(m => m.CustomerId == id && m.Isactive).ToList();
return (stlist);
}
But if Isactive is a property of type string as OP seems to indicate
private IList<Store> GetStores(int id)
{
var stlist = db.Stores.Where(m => m.CustomerId == id && m.Isactive == "true").ToList();
return (stlist);
}
In C# and many other languages, && is the Boolean AND operator.

private IList<Store> GetStores(int id)
{
var stlist = db.Stores.Where(m=>m.CustomerId == id && m.IsActive == true).ToList();
return stlist;
}

var stlist = db.Stores.Where(m => m.CustomerId == id && m.Isactive == "true").ToList();

Related

C# & Entity Framework linq query how to return the mapper even when object is null

I have the following query. When there is no matching record in the database, the method returns null. But I want the response to return object with null properties. How to achieve this?
public async Task<UserResponse> GetUserByEmployeeId(string employeeNumber)
{
var userRecord = await _context.User
.AsNoTracking()
.Include(u => u.Manager)
.Where(x => x.PersonNumber == employeeNumber)
.Select(user => UserReponseMapper.ToUserResponse(user))
.FirstOrDefaultAsync();
// The following returns expected value:
// But, looking for a better solution
/*
if(userRecord == null)
{
userRecord = new UserResponse();
}
*/
return userRecord;
}
public static UserResponse ToUserResponse(User user)
{
return new UserResponse
{
EmployeeNumber = user.PersonNumber,
ManagerNumber = user.Manager?.PersonNumber
};
}
Expected result when no matching record
{
EmployeeNumber: null,
ManagerNumber: null
}
Currently getting result as NULL;
If there are no matching records, ToUserResponse is not called and FirstOrDefaultAsync returns null. You can use the null-coalescing operator to return the alternative:
public async Task<UserResponse> GetUserByEmployeeId(string employeeNumber)
{
var userRecord = (await _context.User
.AsNoTracking()
.Include(u => u.Manager)
.Where(x => x.PersonNumber == employeeNumber)
.Select(user => UserReponseMapper.ToUserResponse(user))
.FirstOrDefaultAsync())
?? new UserResponse() { EmployeeNumber: null, ManagerNumber: null };
// ...
This operator checks the result of the first parameter against null; if the result is not null, it is returned, otherwise the second parameter is returned. It is basically a short form of the if-statement in your sample.
If you are looking to condense the lines.
userRecord = (userRecord == null) ? new UserResponse() : userRecord;
Or if you want to add it to the original you can add the Elvis operator. "??"
var userRecord = (await _context.User
.AsNoTracking()
.Include(u => u.Manager)
.Where(x => x.PersonNumber == employeeNumber)
.Select(user => UserReponseMapper.ToUserResponse(user))
.FirstOrDefaultAsync())
?? new UserResponse();
// ^ Checks for null
You need to change your construct if user is null as well.
return new UserResponse
{
EmployeeNumber = user?.PersonNumber,
ManagerNumber = user?.Manager?.PersonNumber
};
I was wrong in my comment (and deleted it), but it got me thinking; since you might want to add more logic to the "create this new object when the result is null" you could do something like the "pseudocode" below (it compiles, but it's just testcode)
public async Task<ResultObject> GetResultObjectAsync()
{
return ProcessResult(
(await GetResult())
.Where(x => x?.ID == new Guid())
.FirstOrDefault());
}
// this is your DB
async Task<List<ResultObject>> GetResult()
{
return new List<ResultObject>();
}
// this is the null-coalesce replacement
public static ResultObject ProcessResult(ResultObject? value)
{
if (value == null) return new ResultObject(); // or add more info like setting default values
return value;
}
// this is just a simple POCO for testing
public class ResultObject
{
public Guid ID { get; set; }
}

Using filters in linq expression tree

My idea is that I expose an api controller ​/api​/Events​/{clientId}​/{projectId}/{eventTypeId}
these tree parameters will be acting like filters in querying my db.Events table.
If I pass ClientId, and not pass other two filters it should just do filtering by ClientId.
I tried with this method:
public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query, CancellationToken cancellationToken)
{
Expression<Func<Event, int?>> clientId = (s => query.ClientId);
Expression<Func<Event, int?>> projectId = (s => query.ProjectId);
Expression<Func<Event, int?>> eventTypeId = (s => query.EventTypeId);
if (query.ProjectId.HasValue)
{
projectId = (p => p.ProjectId.Equals(query.ClientId)); //error: cannot implicitly convert type bool to int?
}
if (query.EventTypeId.HasValue)
{
eventTypeId = (e => e.EventTypeId == query.EventTypeId.Value);
}
var evts = await _context.Events.Where(clientId) //error: Argument 2: cannot convert from 'System.Linq.Expressions.Expression<System.Func<UNW.Domain.Entities.Event, int?>>' to 'System.Func<UNW.Domain.Entities.Event, bool>'
.Where(projectId)
.Where(eventTypeId)
.ToListAsync();
if (evts == null)
return null;
return evts.AsReadOnly();
}
and my GetEventsByClientIdAndProjectIdQuery model:
public int? ProjectId { get; set; }
public int? ClientId { get; set; }
public int? EventTypeId { get; set; }
What I am missing?
You can made it simpler
public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query,
CancellationToken cancellationToken)
{
var dbQuery = _context.Events;
if (query.ProjectId.HasValue)
{
dbQuery = dbQuery.Where(p => p.ProjectId.Equals(query.ClientId));
}
if (query.EventTypeId.HasValue)
{
dbQuery = dbQuery.Where(e => e.EventTypeId == query.EventTypeId.Value);
}
//same goes for projectID which is missing from your question
var evts = await dbQuery.ToListAsync();
//evts will nerver be null, you might want do something for evts.Count==0
//but it is fine to return an empty list
return evts.AsReadOnly();
}
The most concise solution I can think of
public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query, CancellationToken cancellationToken)
=> await _context.Events
.Where(evt => evt.ClientId.Equals(query.ClientId))
.Where(evt => query.ProjectId.HasValue ? evt.ProjectId.Equals(query.ProjectId.Value) : true)
.Where(evt => query.EventTypeId.HasValue ? evt.EventTypeId.Equals(query.EventTypeId.Value) : true)
.ToListAsync(cancellationToken)
.AsReadOnly();
If the filter is provided
Then use it
Otherwise do not filter out the element
I like and am a fan of the simplicity of #Magnetron's answer, but to build off of your existing code:
//error: cannot implicitly convert type bool to int?
Issue 1: The signatures for clientId, projectId and eventTypeId are all set up to return a nullable int (Func<Event, int?), but .Equals() returns a boolean value.
Assuming I'm understanding what you want to accomplish, you can try the below updates:
// 1. Change the return values from int? to boolean.
// 2. Go ahead and set your expression to return Events where the ClientId is equal
// to the ClientId passed in with your query parameter
Expression<Func<Event, bool>> clientId =
(s => s.ClientId.Equals(query.ClientId));
// 3. Similar to the above with ClientId, but we also include the guard clauses for the optional parameters (ProjectId and EventTypeId)
Expression<Func<Event, bool>> projectId =
(s => (!query.ProjectId.HasValue || query.ProjectId == 0) || s.ID.Equals(query.ProjectId));
Expression<Func<Event, bool>> eventTypeId =
(s => (!query.EventTypeId.HasValue || query.EventTypeId == 0) || s.ID.Equals(query.EventTypeId));
// (Issue 2 with clientId resolved by the updates made to resolve Issue 1)
var evts = await _context.Events.Where(clientId)
.Where(projectId)
.Where(eventTypeId)
.ToListAsync();
if (evts == null)
return null;
return evts.AsReadOnly();

Is there a better way to write a LINQ function?

So, I am new to LINQ and trying to figure out how to filter items.
That’s my task
public async Task<PagedList<Item>> GetItems (ItemParams itemParams) {
var items = _context.Items.AsQueryable ();
if (itemParams.CategoryId > 0) {
var category = GetCategory (itemParams.CategoryId);
items = items.Where (i => FilterItems (i, category.Result));
}
return await PagedList<Item>.CreatAsync (items, itemParams.PageNumber, itemParams.PageSize);
}
and the function that decides which items to return is
static bool FilterItems (Item item, Category category) {
if (item.CategoryId == category.Id) {
return true;
}
if (category.Children.Count > 0) {
foreach (Category cat in category.Children) {
return FilterItems (item, cat);
}
}
return false;
}
the get category func
public async Task<Category> GetCategory (int? id) {
if (id == null) {
return null;
}
var categories = _context.Categories.Include (x => x.Children).AsEnumerable ().Where (c => c.Id == id);
categories = Traverse (categories);
var category = await Task.FromResult (categories.First (c => c.Id == id));
return category;
}
Your filter will not work as expected, as the foreach returns at the first loop. Also the name FilterItems is not intuitive.
static bool ContainsItem(Category category, Item item)
{
return
category.Id == item.CategoryId ||
category.Children.Any(c => ContainsItem(c, item);
}
Since C# performs a short-circuit evaluation of the || Operator, the second term will not be evaluated if the first matches. Note that this is not a dirty trick, but is part of the C# specification.
From the code, it seems FilterItems() returns true if item is in current category or any sub-categories?
If that's the case, I think your current code has a problem: the recursive call to FilterItems() returns result immediately for the first sub-category without checking other sub-categories
Here is the modified code:
public static bool InCategoryOrSubCategory(Item item, Category category)
{
return item.CategoryId == category.Id ||
category.Children.Any(subCategory => InCategoryOrSubCategory(item, subCategory));
}
I change the name to InCategoryOrSubCategory to make it clearer
Here's a curried version, to make the Where call slightly nicer (but the method itself is a bit more cryptic):
public static Func<Item, bool> InCategoryOrSubCategory(Category category)
{
return item =>
item.CategoryId == category.Id ||
category.Children.Any(subCategory => InCategoryOrSubCategory(subCategory)(item));
}
Usage:
items.Where(InCategoryOrSubCategory(category))

Find item if it exists

I have list with items and I check if an item exists in a List. If it exists, I try to find it.
I think that it has a little overhead, because I currently make two passes over the list. Is it possible to do in single pass?
Currently I have.
public partial class Item
{
public string text;
public int id;
}
....
static List<Item> data = new List<Item>();
static stub = new Item() { text = "NaN", id = -1 };
public static Item Get(int targetId)
{
if (data.Any(f => f.id == targetId) == false)
{
return stub;
}
return data.Find(f => f.id == targetId);
}
I want something like
...
public static Item Get(int targetId)
{
Item result;
result = data.Find(f => f.id == targetId);
if (result == null)
{
return stub;
}
return result;
}
You seem to be looking for FirstOrDefault():
Item _stub = new Item
{
text = "NaN",
id = -1
};
public Item FindByID(int id)
{
// Find the first item that has the provided id, or null if none exist.
var existingItem = data.FirstOrDefault(i => i.id == id);
// When not found, return the _stub
return existingItem ?? _stub;
}
You also may want to reconsider your naming conventions and whether you actually need these members to be static.
You can use List.FindIndex:
public static Item get(int i)
{
int index = data.FindIndex(item => item.id == i);
if (index == -1) return stub;
return data[index];
}
If it's actually an array you can use Array.FindIndex:
public static Item get(int i)
{
int index = Array.FindIndex(data, item => item.id == i);
if (index == -1) return stub;
return data[index];
}
So FirstOrDefault() is the way to go. You can also use SingleOrDefault() if there is only supposed to be one item in that list.
static stub = new Item() { text = "NaN", id = -1 };
public static Item get(int i)
{
Item result;
result = data.FirstOrDefault(f => f.id == i);
if (result == null)
{
return stub;
}
return result;
}
I use an extension method for exactly this purpose
public static T FirstOrSpecificDefault<T>(this IEnumerable<T> list,
Func<T, bool> predicate, T defaultValue)
{
return list.FirstOrDefault(predicate) ?? defaultValue;
}
usage in your case would be
Item result = list.FirstOrSpecificDefault(f => f.id == i, stub);
I think you can try this:
return data.Find(f => f.id == i) ?? stub;

LINQ select depending on inner collection value

I have this piece of code:
public string Label { get; set; }
public bool IsSpoon(out Spoon sp)
{
sp = null;
foreach (Tool t in Tools.GetAllItems())
if ((sp = t.AllSpoons.FirstOrDefault(x => x.Label == this.Label)) != null)
break;
return sp != null;
}
How can this be optimised via LINQ?
I thought of something like this but this isn't allowed:
public string Label { get; set; }
public bool IsSpoon(out Spoon sp)
{
return Tools.GetAllItems().FirstOrDefault(x => (sp = x.AllSpoons.FirstOrDefault(y => y.Label == this.Label)) != null) != null;
}
EDIT : I did not notice the sp parameter, here is an update:
sp = Tools
.GetAllItems()
.SelectMany(x => x.AllSpoons)
.FirstOrDefault(y => y.Label == this.Label);
return sp != null;
You can flatten the list with SelectMany. Then you don't have to do anything tricky like assigning a value in the middle of a LINQ statement.
public bool IsSpoon(out Spoon sp)
{
sp = Tools.GetAllItems().SelectMany(t => t.AllSpoons)
.FirstOrDefault(x => x.Label == this.Label);
return sp != null;
}
Here is the essentially equivalent query syntax:
sp = (from tool in Tools.GetAllItems()
from spoon in tool.AllSpoons
where spoon.Label == this.Label
select spoon).FirstOrDefault();
public bool IsSpoon(out Spoon sp)
{
return Tools.GetAllItems()
.SelectMany(t => t.AllSpoons)
.Any(x => x.Label == this.Label);
}

Categories