Linq Optional ORing (Method Syntax) - c#

How do I combine these two methods into one?
public override Expression<Func<Attachment, bool>> MatchingCriteria
{
get { return a => a.Activity.Parent.ActivityUsers.Any(x => (x.User.Id == id)); }
}
and
public override Expression<Func<Attachment, bool>> MatchingCriteria
{
get { return a => a.Activity.ActivityUsers.Any(x => (x.User.Id == id)); }
}
notably, the idea is that I want to check the root record for links to a certain User. But, a may be a root or may be a child (one decendant/level only; not recursive). I want an ORing, so to speak, of these two Linq expressions.

Maybe something like:
public override Expression<Func<Attachment, bool>> MatchingCriteria
{
get
{
return a => a.Activity.Parent.ActivityUsers
.Concat(a.Activity.ActivityUsers).Any(x => (x.User.Id == id));
}
}
Or since you're only worried about a single level deep you could probably use:
public override Expression<Func<Attachment, bool>> MatchingCriteria
{
get
{
return a => a.Activity.Parent.Any(a2 =>
a2.ActivityUsers.Any(x =>
(x.User.Id == id) || x.Activity.ActivityUsers.Any(y =>
y.User.Id == id)));
}
}
This option is probably more appropriate.

public override Expression<Func<Attachment, bool>> MatchingCriteria
{
get { return a => a.Activity.Parent.ActivityUsers.Any(x => (x.User.Id == id))
|| a.Activity.ActivityUsers.Any(x => (x.User.Id == id));
}
}

Related

Cannot access variable on mapping (C#)

I have a method on the back end, that gets values related to a foreign key of the table.
Those foreign keys can be nullable, but one of those keys always will have value.
Here is method
public async Task<ListResultDto<QuoteListDto>> GeQuotesTabData(int? landlordId, int? agentId,
int? propertyTenantId)
{
if (landlordId.HasValue)
{
var query = _quoteRepository.GetAll()
.Where(x => x.LandlordId == landlordId);
}
if (agentId.HasValue)
{
var query = _quoteRepository.GetAll()
.Where(x => x.AgentId == agentId);
}
if (propertyTenantId.HasValue)
{
var query = _quoteRepository.GetAll()
.Where(x => x.PropertyTenantId == propertyTenantId);
}
return new ListResultDto<QuoteListDto>(await query.ProjectTo<QuoteListDto>(ObjectMapper)
.OrderBy(x => x.Id).ToListAsync());
}
At this row, I get an error Cannot resolve symbol query
return new ListResultDto<QuoteListDto>(await query.ProjectTo<QuoteListDto>(ObjectMapper)
.OrderBy(x => x.Id).ToListAsync());
How do I need to rewrite my method?
Declare and initialise your variable. Additionally I would re-write you method like so:
public async Task<ListResultDto<QuoteListDto>> GeQuotesTabData(int? landlordId, int? agentId,
int? propertyTenantId)
{
var query = _quoteRepository.GetAll();
if (landlordId.HasValue)
{
query = query.Where(x => x.LandlordId == landlordId);
}
if (agentId.HasValue)
{
query = query.Where(x => x.AgentId == agentId);
}
if (propertyTenantId.HasValue)
{
query = query .Where(x => x.PropertyTenantId == propertyTenantId);
}
return new ListResultDto<QuoteListDto>(await query.ProjectTo<QuoteListDto>(ObjectMapper)
.OrderBy(x => x.Id).ToListAsync());
}
Also taken from this answer, you can create a WhereIf extension to clean up the if statements.
public static IQueryable<TSource> WhereIf<TSource>(
this IQueryable<TSource> source,
bool condition,
Expression<Func<TSource, bool>> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
Making your code look like this:
public async Task<ListResultDto<QuoteListDto>> GeQuotesTabData(int? landlordId, int? agentId,
int? propertyTenantId)
{
var list = await _quoteRepository.GetAll()
.WhereIf(landlordId.HasValue, x => x.LandlordId == landlordId)
.WhereIf(agentId.HasValue, x => x.AgentId == agentId)
.WhereIf(propertyTenantId.HasValue, x => x.PropertyTenantId == propertyTenantId)
.ProjectTo<QuoteListDto>(ObjectMapper)
.OrderBy(x => x.Id)
.ToListAsync();
return new ListResultDto<QuoteListDto>(list);
}
Your problem is variable scope. When you define a variable it is only visible in the scope you define it in.
You define three different query variables in a local scope. None of them are accessible where you try to use it.
You need to define it before using it, something like this:
public async Task<ListResultDto<QuoteListDto>> GeQuotesTabData(int? landlordId, int? agentId,
int? propertyTenantId)
{
IQueryable<Quote> query = null;
if (landlordId.HasValue)
{
query = _quoteRepository.GetAll().Where(x => x.LandlordId == landlordId);
}
if (agentId.HasValue)
{
query = _quoteRepository.GetAll().Where(x => x.AgentId == agentId);
}
if (propertyTenantId.HasValue)
{
query = _quoteRepository.GetAll().Where(x => x.PropertyTenantId == propertyTenantId);
}
return new ListResultDto<QuoteListDto>(await query.ProjectTo<QuoteListDto>(ObjectMapper)
.OrderBy(x => x.Id).ToListAsync());
}
Of course all of your queries should be of the same type. Otherwise you will have to define and execute them in the local scopes.
You should probably also add some error handling of the case where query is null, when you try to use it.

Is there anyway I can optimize this code to much shorter?

Is there anyway I can optimize this code into shorter?
MakeList, TrimList and etc are List type.
and Vehicle are models.
My problem is code is very long. I have 20 property in model.
if (MakeList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => MakeList.Contains(b.Vehicle.Make));
}
if (TrimList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => TrimList.Contains(b.Vehicle.Trim));
}
if (ModelList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => ModelList.Contains(b.Vehicle.Model));
}
if (StockNoList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => StockNoList.Contains(b.Vehicle.StockNo));
}
if (BodyStyleList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => BodyStyleList.Contains(b.Vehicle.Body));
}
if (ExtColorList?.Any() == true)
{
bidVehicles = bidVehicles.Where(b => ExtColorList.Contains(b.Vehicle.Exterior));
}
return bidVehicles;
For LINQ to Objects:
public static class FilterExt
{
public static IEnumerable<TItem> ApplyFilter<TProp, TItem>(this IEnumerable<TItem> list, List<TProp> filter, Func<TItem, TProp> prop)
{
if (filter == null || filter.Count == 0)
{
return list;
}
return list.Where(x => filter.Contains(prop.Invoke(x)));
}
}
...
var filtered = bidVehicles
.ApplyFilter(MakeList, x => x.Vehicle.Make)
.ApplyFilter(TrimList, x => x.Vehicle.Trim).ToList();
If you use EF (means bidVehicles is IQueryable) you have to write expression for each property because you need full predicate Expression<Func<BidVehicle, bool>> not just Func<BidVehicle, TProp>.

How to access an unknown property in C# Generics

I am creating a general repository class as part of my Entity Framework Code First data layer. To get the single row by id, if all the entities have id name as "ID" it will work as shown by the following:
public T GetSingle(int id)
{
return GetAll().FirstOrDefault(x => x.ID == id);
}
But I would like to name my entity primarykey as "EnityName"+Id, such as AddressId or ApplicantId etc. Is there any way to have the code:
return GetAll().FirstOrDefault(x => x.<EntityName>Id == id);
to make to work?
Thanks
You can do it easier only create method "Get single" and pass predicate
public virtual T GetSingle(Expression<Func<T, bool>> predicate)
{
if (predicate != null)
{
return context.Set<T>().Where(predicate).SingleOrDefault();
}
else
{
throw new ArgumentNullException("Predicate value is null");
}
}
And call it:
yourContext.GetSingle(g => g.Id == id);
you can use Attributes for this and read the Property which has the right Attribute.
public abstract class MyIdAttribute: Attribute
{
}
public class MyClass
{
[MyId]
WhatEverName {get; set;}
}
and in your Method
public T GetSingle(int id)
{
var propertyInfos = typeof(T).GetProperties().Where(property => property.GetCustomAttributes<MyIdAttribute>().Count() > 0).ToList();
if (propertyInfos.Any())
{
foreach(T current in GetAll())
{
object value = propertyInfos[0].GetValue(current);
if(value == id)
{
return current;
}
}
}
}
Cheers
Thomas

Best way to order a List<type> by field C# Lambda

I have the following code that works fine, but I was wondering if there is any better way to order the select depending on what the user choose.
public List<TB_PRODUTO> GetAll(int ID_Empresa, String Order)
{
if(Order.Equals("COD_HERBALIFE"))
return Ent.TB_PRODUTO.Where(x => x.ID_EMPRESA == ID_Empresa).Select(x => x).OrderBy(x => x.COD_HERBALIFE).ToList();
else if (Order.Equals("DESCRICAO"))
return Ent.TB_PRODUTO.Where(x => x.ID_EMPRESA == ID_Empresa).Select(x => x).OrderBy(x => x.DESCRICAO).ToList();
else
return Ent.TB_PRODUTO.Where(x => x.ID_EMPRESA == ID_Empresa).Select(x => x).OrderBy(x => x.PRECO).ToList();
}
Thanks in advance.
private static object GetPropertyValue(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
public List<TB_PRODUTO> GetAll(int ID_Empresa, String Order)
{
return Ent.TB_PRODUTO.Where(x => x.ID_EMPRESA == ID_Empresa).Select(x => x).OrderBy(x => GetPropertyValue(x, Order)).ToList();
}
GetPropertyValue will return the property matching the Order string, provided the string exactly matches the property.

How to avoid duplication with QueryOver

I have two methods and don't like the duplication:
public Order LatestOrderOver(decimal amount)
{
return session.QueryOver<Order>()
.Where(o => o.Amount > amount)
.OrderBy(sr => sr.CompleteUtcTime).Desc
.Take(1)
.SingleOrDefault<Order>();
}
public Order LatestAmericanOrderOver(decimal amount)
{
return session.QueryOver<Order>()
.Where(o => o.Amount > amount && o.Country == "USA")
.OrderBy(sr => sr.CompleteUtcTime).Desc
.Take(1)
.SingleOrDefault<Order>();
}
What is the best way to avoid duplication when you have similar criteria (in the Where clause) used in the QueryOver and similar options at the end?
If you are using Linq To Objects, you can just refactor out the delegate:
private Order LatestOrderOver(Func<Order, bool> f) {
return
session.QueryOver<Order>()
.Where(f)
.OrderBy(sr => sr.CompleteUtcTime).Desc
.Take(1)
.SingleOrDefault<Order>();
}
public Order LatestOrderOver(decimal amount) {
return LatestOrderOver(o => o.Amount > amount);
}
public Order LatestAmericanOrderOver(decimal amount) {
return LatestOrderOver(o => o.Amount > amount && o.Country == "USA");
}
Otherwise it might work with just changing Func<> to Expression<>, but I don't have much experience with that.
Beside Guffa's suggestion, what do you think about an extension method?
public static class QueryOverExtensions
{
public static Order LastOrder(this IQueryOver<Order, Order> query)
{
return query
.Where(o => o.Amount > amount)
.OrderBy(sr => sr.CompleteUtcTime).Desc
.Take(1)
.SingleOrDefault<Order>();
}
// Other query over extension methods
}
Then you could write your methods as:
public Order LatestOrderOver(decimal amount)
{
return session.QueryOver<Order>()
.LastOrder();
}
public Order LatestAmericanOrderOver()
{
return session.QueryOver<Order>()
.Where(o => o.Country == "USA")
.LastOrder();
}

Categories

Resources