Search all properties that are string - c#

Is there anyway to do change the "Where", in which it will automatic check all properties that contain a string instead of adding each property name manually?
items.Where(m => m.Property1.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property2.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property3.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property4?.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property5?.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property6.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.Property7?.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0
));
Thanks.

I would write a code using reflection...
public bool MyContains(object instance, string word)
{
return instance.GetType()
.GetProperties()
.Where(x => x.PropertyType == typeof(string))
.Select(x => (string)x.GetValue(instance, null))
.Where(x => x != null)
.Any(x => x.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0);
}
Then your code would be
items.Where(m=>MyContains(m,word));

Based on L.B answer: I accepted his answer
I broke it down into two functions because there is no need to get
the string properties for each instances in the where.
public static class ObjectUtils
{
public static IEnumerable<PropertyInfo> GetPropertiesByType<TEntity>(TEntity entity, Type type)
{
return entity.GetType().GetProperties().Where(p => p.PropertyType == type);
}
public static bool CheckAllStringProperties<TEntity>(TEntity instance, IEnumerable<PropertyInfo> stringProperties, string word)
{
return stringProperties.Select(x => (string)x.GetValue(instance, null))
.Where(x => x != null)
.Any(x => x.IndexOf(word, StringComparison.CurrentCultureIgnoreCase) >= 0);
}
}
Then
var stringProperties = ObjectUtils.GetPropertiesByType(new Item(), typeof(string));
items.Where(x => ObjectUtils.CheckAllStringProperties(x, stringProperties, word)));

Related

Why a separate function works with Must property rather than write the entire expression in it? (FluentValidation)

I am a newbie with Linq and fluent validation and I want to know.. Why with the method 1 I get an error but with the method 2 it works without any issue?.
This way doesn't work!! throws a null reference exception.
RuleFor(x => x)
.Must(ledger => !_companyDbContext.GeneralLedger.Any(x =>
x.Deleted == false
&& !(x.Id == ledger.Id)
&& x.AccountNumber == ledger.AccountNumber
&& x.LedgerAccount == ledger.LedgerAccount
&& x.AccountType == ledger.AccountType
&& x.Description == ledger.Description
)).WithMessage(ValidatorResources.Unique_Message);
This way works even if all the properties of the object are null.
RuleFor(x => x)
.Must(testDuplicateRecords)
.WithMessage("duplicated record");
public bool testDuplicateRecords( GeneralLedger ledger)
{
Expression<Func<GeneralLedger, bool>> predicate = (x) => x.Deleted == false && !(x.Id == ledger.Id)
&& x.AccountNumber == ledger.AccountNumber
&& x.LedgerAccount == ledger.LedgerAccount
&& x.AccountType == ledger.AccountType
&& x.Description == ledger.Description;
return !_companyDbContext.GeneralLedger.Any(predicate.Compile());
}

How to accelerate C#/Linq query? [i don't need to get data, i need to get condition]

public int being = 0;
public void Insert(Currency current, int number)
{
being = db.Currency.Where(x => x.ForDate == current.ForDate)
.Where(x => x.TitleId == current.TitleId)
.Where(x => x.Value == current.Value).Count(x=>x.Id > 0);
if (being == 0)
{
db.Currency.AddOrUpdate(current);
}
}
it's my code works so slowly, because of getting date but it is not necessary, i don't know other way.
maybe something like :
db.Currency.Find().Value.Equals(current.Value).where...where...
I think your main problem is the .Count(x => x.Id > 0), which forces the evaluation of all the conditions before and actually get the total number.
If you can, replace it with Any. In that way, it just has to get one row at most:
bool isBeing = db.Currency
.Where(x => x.ForDate == current.ForDate
&& x.TitleId == current.TitleId
&& x.Value == current.Value
&& x.Id > 0
)
.Any();
You can do all your conditions in just one where, and also you can skip having a bool variable to check your conditions
if(db.Currency.Where(x => x.ForDate == current.ForDate
&& x.TitleId == current.TitleId && x.Value == current.Value && x.Id > 0).Any())
{
db.Currency.AddOrUpdate(current);
}

How to combine the multiple part linq into one query?

Operator should be ‘AND’ and not a ‘OR’.
I am trying to refactor the following code and i understood the following way of writing linq query may not be the correct way. Can somone advice me how to combine the following into one query.
AllCompany.Where(itm => itm != null).Distinct().ToList();
if (AllCompany.Count > 0)
{
//COMPANY NAME
if (isfldCompanyName)
{
AllCompany = AllCompany.Where(company => company["Company Name"].StartsWith(fldCompanyName)).ToList();
}
//SECTOR
if (isfldSector)
{
AllCompany = AllCompany.Where(company => fldSector.Intersect(company["Sectors"].Split('|')).Any()).ToList();
}
//LOCATION
if (isfldLocation)
{
AllCompany = AllCompany.Where(company => fldLocation.Intersect(company["Location"].Split('|')).Any()).ToList();
}
//CREATED DATE
if (isfldcreatedDate)
{
AllCompany = AllCompany.Where(company => company.Statistics.Created >= createdDate).ToList();
}
//LAST UPDATED DATE
if (isfldUpdatedDate)
{
AllCompany = AllCompany.Where(company => company.Statistics.Updated >= updatedDate).ToList();
}
//Allow Placements
if (isfldEmployerLevel)
{
fldEmployerLevel = (fldEmployerLevel == "Yes") ? "1" : "";
AllCompany = AllCompany.Where(company => company["Allow Placements"].ToString() == fldEmployerLevel).ToList();
}
Firstly, unless AllCompany is of some magic custom type, the first line gives you nothing.
Also I have a doubt that Distinctworks the way You want it to. I don't know the type of AllCompany but I would guess it gives you only reference distinction.
Either way here'w what I think You want:
fldEmployerLevel = (fldEmployerLevel == "Yes") ? "1" : "";
var result = AllCompany.Where(itm => itm != null)
.Where(company => !isfldCompanyName || company["Company Name"].StartsWith(fldCompanyName))
.Where(company => !isfldSector|| fldSector.Intersect(company["Sectors"].Split('|')).Any())
.Where(company => !isfldLocation|| fldLocation.Intersect(company["Location"].Split('|')).Any())
.Where(company => !isfldcreatedDate|| company.Statistics.Created >= createdDate)
.Where(company => !isfldUpdatedDate|| company.Statistics.Updated >= updatedDate)
.Where(company => !isfldEmployerLevel|| company["Allow Placements"].ToString() == fldEmployerLevel)
.Distinct()
.ToList();
Edit:
I moved Distinct to the end of the query to optimize the processing.
How about trying like this;
AllCompany = AllCompany .Where(company => (company => company.Statistics.Created >= createdDate)) && (company.Statistics.Updated >= updatedDate));
If every part of query is optional (like created date, last update date..) then you can build linq query string.
Here's a sneaky trick. If you define the following extension method in its own static class:
public virtual IEnumerable<T> WhereAll(params Expression<Predicate<T> filters)
{
return filters.Aggregate(dbSet, (acc, element) => acc.Where(element));
}
then you can write
var result = AllCompany.WhereAll(itm => itm != null,
company => !isfldCompanyName || company["Company Name"].StartsWith(fldCompanyName),
company => !isfldSectorn || fldSector.Intersect(company["Sectors"].Split('|')).Any(),
company => !isfldLocation || fldLocation.Intersect(company["Location"].Split('|')).Any(),
company => !isfldcreatedDate || company.Statistics.Created >= createdDate,
company => !isfldUpdatedDate || company.Statistics.Updated >= updatedDate,
company => !isfldEmployerLevel || company["Allow Placements"].ToString() == fldEmployerLevel)
.Distinct()
.ToList();

Mixing two linq statement into one?

I have 2 linq statements, both of them are fully working. I am wondering if it is possible to mix them into one and get proper list after one linq.
var result = list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device == _text))
.ToList();
var list666 = list3.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj).ToList();
LINQ methods return IEnumerable<T>, and can operate on IEnumerable<T>.
You can write
sequence.Where(...).Select(...)
One list:
var result = list3.Where(obj => {
var dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture);
return (list4.Any(x => x == obj.Srodek.category1) &&
(obj.Srodek.Source.Device == _text || obj.Srodek.ID.Device == _text)) ||
(dt >= czas11 && dt <= czas22);})
.ToList();
Why you cant just mix them? list.where(.........).select(.......).toList();
var result = list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device== _text))
.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj)
.ToList();
You can join both linq queries using Union.
list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device == _text))
.Union(list3.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj));

Linq Complex OrderBy by Props attributes

I have a class with some props tagged with some attributes. I want to display them on a specific order. So far I can put them in a order, but not on the order that I want.
Here is a simple example of the props with the attributes
[IncludeInEditor]
[IsInPk]
ID
[IncludeInEditor(IsReadOnlyOnModify=true)]
Name
[IncludeInEditor]
Address
[IncludeInEditor]
DOB
The order that I want is:
1st - Props with IsInPk attribute
2nd - Props with IncludeInEditor(IsReadOnlyOnModify=true)
3rd - Props with IncludeInEditor
So far I got this with no sucess and not 100% done (still missing the IsReadOnlyOnModify=true part)
var properties =
item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Count() > 0)
.Select (x => new
{
Property = x,
Attribute = (IsInPkAttribute)Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true)
})
.OrderBy(x => x.Attribute != null ? 1 : -1)
.Select(x => x.Property)
.ToArray();
You can create your own IComparer<T> implementation to compare the attributes on each property:
public class AttributeComparer : IComparer<Attribute>
{
public int Comparer(Attribute x, Attribute y)
{
if(x == null) return y == null ? 0 : -1;
if(y == null) return 1;
if(x is IsInPkAttribute) return (y is IsInPkAttribute) ? 0 : 1;
else if(y is IsInPkAttribute) return -1;
else
{
xa = (IncludeInEditorAttribute)x;
ya = (IncludeInEditorAttribute)y;
if(xa.IsReadOnlyOnModify == ya.IsReadOnlyOnModify) return 0;
else return x.IsReadOnlyOnModify ? 1 : -1;
}
}
}
Then your query becomes:
var properties = item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Any())
.Select (x => new
{
Property = x,
Attribute = Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true) ?? Attribute.GetCustomAttribute(x, typeof(IncludeInEditorAttribute, true))
})
.OrderBy(x => x.Attribute, new AttributeComparer())
.Select(x => x.Property)
.ToArray();
After the help of Lee, finally it´s working. The correct code is:
var properties =
item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Any())
.Select(x => new
{
Property = x,
Attribute = Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true)
?? Attribute.GetCustomAttribute(x, typeof(IncludeInEditorAttribute), true)
})
.OrderBy(x => x.Attribute, new IncludeInEditorAttributeComparer())
.Select(x => x.Property)
.ToArray();
This code that Lee sent, I made a little change.
public class IncludeInEditorAttributeComparer : IComparer<Attribute>
{
public int Compare(Attribute x, Attribute y)
{
//In this case we can assume that
//won´t have null values
if (x is IsInPkAttribute && !(y is IsInPkAttribute))
return -1;
else if (y is IsInPkAttribute && !(x is IsInPkAttribute))
return 1;
else
{
bool xa = (x is IncludeInEditorAttribute ? (x as IncludeInEditorAttribute).IsReadOnlyOnModify : false);
bool ya = (y is IncludeInEditorAttribute ? (y as IncludeInEditorAttribute).IsReadOnlyOnModify: false);
if (xa && !ya)
return -1;
else if (ya && !xa)
return 1;
else
return 0;
}
}
}

Categories