Simplify if statement - c#

How can I simplify such statement:
var someList = new List<someType>();
if (String.IsNullOrEmpty(groupId))
{
someList = CTX.Values.Include(c => c.Customer).ToList();
}
else
{
someList = CTX.Values.Include(c => c.Customer).Where(c => c.GroupId== groupId).ToList();
}
The difference is only in .Where(c => c.GroupId== groupId). Is it possible to include the condition String.IsNullOrEmpty(groupId) inside the query statement?

You can construct the query in multiple steps. Simply add the Where part only when groupId is not empty.
The query will only be executed once you call ToList().
var values = CTX.Values.Include(c => c.Customer);
if(!String.IsNullOrEmpty(groupId))
values = values.Where(c => c.GroupId == groupId);
someList = values.ToList();

Maybe this?
someList = CTX.Values.Include(c => c.Customer)
.Where(c => String.IsNullOrEmpty(groupId)
|| c.GroupId== groupId)
.ToList();
EDITED BY PLB REQUEST :)
bool isGroupValid = String.IsNullOrEmpty(groupId);
someList = CTX.Values.Include(c => c.Customer)
.Where(c => isGroupValid
|| c.GroupId== groupId)
.ToList();

You can add:
.Where(c => String.IsNullOrEmpty(groupId))
That is:
CTX.Values.Include(c => c.Customer)
.Where(c => c.GroupId == groupId || c => String.IsNullOrEmpty(groupId))
.ToList();

Related

Linq complex queries C#

i have this:
int item = particleEdges.ElementAt(i).Key;
Point3 hashPoint = particleEdges[item][j].hashEdge;
var hashList = particleEdges
.Where(p => p.Value.Any(q => q.hashEdge == hashPoint))
.Select(r => r.Key != item)
.ToList();
How to exclude "item" from hashList? Broke my head. Linq doesn't want to open to me.
var hashList = particleEdges
.Where(p => p.Value.Any(q => q.hashEdge == hashPoint))
.Where(r => r.Key != item)
.Select(s => s.Key)
.ToList();

Is there a way to set this entity/linq query to IEnumerable?

I'm trying to return an IEnumerable activities instead of "var"
var activities = ctx.Activities.Where(a => a.SiteID == propID)
.Where(a => a.ActivityTypeName == "Call")
.Select(x => new
{
x.DateTimeEntry,
x.Contact.OwnerContact.ParcelDatas
.FirstOrDefault(a => a.OwnerContactID == x.Contact.OwnerContact.OOwnerID)
.Parcel_LetterTracking.LMailDate,
x.FAQs.FirstOrDefault(a => a.ActivityID == x.ActivityID)
.FAQ_Library.FaqNum,
x.FAQs.FirstOrDefault(a => a.ActivityID == x.ActivityID)
.FAQ_Library.Question
});
edit: data type Object compiles but I'm not sure if that's right.
.Select already returns a an IEnumerable<TResult> also combine your ..where() clauses with && instead. https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=netframework-4.8 also one other thing you can do is use .AsEnuemerable()
var activities = ctx.Activities.Where(a => a.SiteID == propID && a.ActivityTypeName == "Call")
.Select(x => new
{
x.DateTimeEntry,
x.Contact.OwnerContact.ParcelDatas.FirstOrDefault(a => a.OwnerContactID == x.Contact.OwnerContact.OOwnerID).Parcel_LetterTracking.LMailDate,
x.FAQs.FirstOrDefault(a => a.ActivityID == x.ActivityID).FAQ_Library.FaqNum,
x.FAQs.FirstOrDefault(a => a.ActivityID == x.ActivityID).FAQ_Library.Question
}).AsEnumerable();

Order by with conditions

Try to get this in following order but doesn't work, it does not return the right order, where Cancelled is picked before Unpaid, please let me know
dt = dt.AsEnumerable()
.OrderBy(x => x["TicketStatus"].ToString())
.ThenBy(x => x["TicketStatus"].ToString() == "Attended")
.ThenBy(x => x["TicketStatus"].ToString() == "Issued")
.ThenBy(x => x["TicketStatus"].ToString() == "Unpaid")
.ThenBy(x => x["TicketStatus"].ToString() == "Cancelled")
.GroupBy(x => new {EventID = x["EventID"].ToString(), ContactID = x["ContactID"].ToString()})
.Select(x => x.FirstOrDefault()).CopyToDataTable();
Try something like this
string[] status= { "Attended", "Issued", "Unpaid", "Cancelled" };
var sortstatus = from s in status
orderby s
select s;
just find out this works
List<string> sortOrder = new List<string> { "Attended", "Issued", "Unpaid", "Cancelled" };
dt = dt.AsEnumerable()
.OrderBy(x => sortOrder.IndexOf(x["TicketStatus"].ToString()))
.GroupBy(x => new {EventID = x["EventID"].ToString(), ContactID = x["ContactID"].ToString()})
.Select(x => x.FirstOrDefault()).CopyToDataTable();

Append WHERE to query based on a condition

I have a query like so:
if (catId == null || catId == 0)
{
productVM = db.Products
.Include(x => x.Category)
.ToArray()
.Select(x => new ProductVM(x))
.ToList();
}
else
{
productVM = db.Products
.Include(x => x.Category)
.ToArray()
.Where(x => x.CategoryId == catId)
.Select(x => new ProductVM(x))
.ToList();
}
That works, but as you can see the only difference between the 2 queries is .Where(x => x.CategoryId == catId).
Is there a more elegant way to write this?
Entity Framework doesn't actually query the database until you materialise the data, for example with ToList() or iterating over the results. So you can build up your query as you go without hitting the database:
var query = db.Products.Include(x => x.Category);
if(catId != null && catId != 0)
{
//Add a where clause
query = query.Where(x => x.CategoryId == catId);
}
productVM = query
.ToList()
.Select(x => new ProductVM(x));
Note that I removed the ToArray call as that also materialises the data which means each subsequent method on the data is acting on the entire table from the database.
You could expand the Where statement to include the test for null or 0 on catId. This might not work if the field catId in the database is nullable or can have a value of 0.
productVM = db.Products
.Include(x => x.Category)
.Where(x => catId == null || catId == 0 || x.CategoryId == catId)
.Select(x => new ProductVM(x))
.ToList();
Also you should remove the ToArray() as it queries the entire Products table from the database then perform the filtering and projecting in memory on the client.
Another way.
var products = db.Products.Include(x => x.Category).ToArray()
if (catId == null || catId == 0)
{
productVM = products.Select(x => new ProductVM(x)).ToList();
}
else
{
productVM = products.Where(x => x.CategoryId == catId)
.Select(x => new ProductVM(x)).ToList();
}
Simply re-assign query:
var query = db.Products;
if (condition)
query = query.Where(criteria);
var list = query.ToList();

Adding more parameters to a Linq query

I'm using this query to count number of orders by date. I'm trying to add one more parameter that counts total products for each order, however I can't get it to work atm.
This is the essential part of a method that is suposed to return a list of 3 parameters (Date, TotalOrders and TotalProducts). Im using a Linq query to get a list with total order for each date, im wondering how to add my third parameter to the list "TotalProducts" and if i can do by adding one more search parameter in the Query. The foreach part below do not work propertly, it will return a list of TotalProducts but CreationDate will be the same for ech item in the list. I also have a feeling putting a foreach inside a foreach dosn't seem optimal for this:
var orders = _orderService.SearchOrderStatistics(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid);
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new { Date = s.Key, Count = s.Count() });
List<GCOrdersModel> TotalOrdersPaid = new List<GCOrdersModel>();
foreach (var g in result)
{
foreach (var opv in orders)
{
GCOrdersModel _Om = new GCOrdersModel(g.Date, g.Count.ToString(), opv.OrderProductVariants.Count.ToString());
TotalOrdersPaid.Add(_Om);
}
}
return TotalOrdersPaid;
To access total products for every orders I must use OrderProductVariants.Count.ToString()
Can I add this parameter to the query?
Thx
You could try this:
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = opv.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count, opv.OrderProductVariants.Count.ToString()))
.ToList();
That way, you don't have to iterate over your result again. And it automatically creates your list of GCOrdersModel.
Edit
Does this work?
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = s.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count(), s.OrderProductVariants.Count.ToString()))
.ToList();
How about:
var opvCount =
opv
.OrderProductVariants
.Count
.ToString();
return
orders
.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new
{
Date = s.Key,
Count = s.Count()
})
.Select(x =>
new GCOrdersModelg(x.Date, g.Count.ToString(), opvCount));

Categories