how to query the settingspropertyvaluecollection - linq

I have a settingspropertyvaluecollection.I dont want to loop through all the properties using a for each loop.Instead i want to query the collection.How do i do that?is there a way to use LINQ and do it?
Thanks

SettingsPropertyValueCollection doesn't implement IEnumerable<T> but it does implement IEnumerable. If you want to query it using LINQ you have a couple of options.
You could create a Where() extension method that takes IEnumerable and a query and performs the query for you:
public static class IEnumerableExtensions
{
public static IEnumerable<T> Where<T>(this IEnumerable input, Func<T,bool> query)
{
return input.Cast<T>().Where(item => query(item));
}
}
assuming:
var settings = new SettingsPropertyValueCollection
{
new SettingsPropertyValue(new SettingsProperty("Email")
{
DefaultValue = "a#a.com",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("City")
{
DefaultValue = "Austin",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("State")
{
DefaultValue = "TX",
PropertyType = typeof(string)
})
};
usage would be:
var matches = settings.Where<SettingsPropertyValue>(x => x.Name == "City")
alternatively you could use the LINQ Cast<T> operator to query the settings:
var matches = settings.Cast<SettingsPropertyValue>()
.Where(x => x.Name == "City");
if you expect only one possible match then use FirstOrDefault() instead of Where()
var match = settings.Cast<SettingsPropertyValue>()
.FirstOrDefault(x => x.Name == "City");

It's been a while since the question was answered and many things have changed since then.
You could cast the SettingsPropertyValueCollection to a list (or other container) and query it right away.
So, this would be my solution nowadays:
SettingsPropertyValueCollection settings = Properties.Settings.Default.PropertyValues
settings.Cast<SettingsPropertyValue>().ToList().Where(p => p.Name == "myProperty");

Related

Reflection within IQueryable in .NET Core

I am wondering how would the below code work and what would be the performance. I am interested in line #4 basically. How will linq and property info work together?
In other words will (int)prop.GetValue(a) and a.SomeId work the same way or will the reflection need to get everything to memory before checking the value?
var prop = type.GetProperty("SomeId");
if (prop != null)
{
DbSet<T> dbSet = _dbContext.Set<T>();
return dbSet.Where(a => (int)prop.GetValue(a) == 1);
}
In other words will (int)prop.GetValue(a) and a.SomeId work the same way
No.
Depending on the backing store, the context may fail to convert that expression ((int)prop.GetValue(a)) to the underlying query syntax, which in most cases would be SQL.
You could consider building a valid expression manually using the property info.
For example
//Assuming
Type type = typeof(T);
PropertyInfo prop = type.GetProperty("SomeId");
if (prop != null) {
//need to build a => a.SomeId == 1
// a =>
ParameterExpression parameter = Expression.Parameter(type, "a");
// a => a.SomeId
MemberExpression property = Expression.Property(parameter, prop);
// a => a.SomeId == 1
BinaryExpression body = Expression.Equal(property, Expression.Constant(1));
Expression<Func<T, bool>> expression = Expression.Lambda<Func<T, bool>>(body, parameter);
DbSet<T> dbSet = _dbContext.Set<T>();
return dbSet.Where(expression);
}

How to Search through all fields in a LINQ table?

in LINQ how do i search all fields in a table, what do i put for ANYFIELD in the below?
Thanks
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where d."ANYFIELD" == "VALUE" select d;
You can't. You must compare each field individually. It doesn't make sense to compare all fields, given a field may not even be of the same type as the object you're comparing to.
You can, using reflection. Try this:
static bool CheckAllFields<TInput, TValue>(TInput input, TValue value, bool alsoCheckProperties)
{
Type t = typeof(TInput);
foreach (FieldInfo info in t.GetFields().Where(x => x.FieldType == typeof(TValue)))
{
if (!info.GetValue(input).Equals(value))
{
return false;
}
}
if (alsoCheckProperties)
{
foreach (PropertyInfo info in t.GetProperties().Where(x => x.PropertyType == typeof(TValue)))
{
if (!info.GetValue(input, null).Equals(value))
{
return false;
}
}
}
return true;
}
And your LINQ query:
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where CheckAllFields(d, "VALUE", true) select d;
The third parameter should be true if you want to check all fields and all properties, and false if you want to check only all fields.
EDIT: Someone already built this...see here.
Not a full answer, but I don't agree with assertion that you simply can't...
You could come up with an extension method that dynamically filtered the IQueryable/IEnumerable (I'm guessing IQueryable by the db variable) based on properties of a similar type for you. Here's something whipped up in Linqpad. It references PredicateBuilder and is by no means complete/fully accurate, but I tested it out in Linq-to-SQL on some of my tables and it worked as described.
void Main()
{
YourDbSet.WhereAllPropertiesOfSimilarTypeAreEqual("A String")
.Count()
.Dump();
}
public static class EntityHelperMethods
{
public static IQueryable<TEntity> WhereAllPropertiesOfSimilarTypeAreEqual<TEntity, TProperty>(this IQueryable<TEntity> query, TProperty value)
{
var param = Expression.Parameter(typeof(TEntity));
var predicate = PredicateBuilder.True<TEntity>();
foreach (var fieldName in GetEntityFieldsToCompareTo<TEntity, TProperty>())
{
var predicateToAdd = Expression.Lambda<Func<TEntity, bool>>(
Expression.Equal(
Expression.PropertyOrField(param, fieldName),
Expression.Constant(value)), param);
predicate = predicate.And(predicateToAdd);
}
return query.Where(predicate);
}
// TODO: You'll need to find out what fields are actually ones you would want to compare on.
// This might involve stripping out properties marked with [NotMapped] attributes, for
// for example.
private static IEnumerable<string> GetEntityFieldsToCompareTo<TEntity, TProperty>()
{
Type entityType = typeof(TEntity);
Type propertyType = typeof(TProperty);
var fields = entityType.GetFields()
.Where (f => f.FieldType == propertyType)
.Select (f => f.Name);
var properties = entityType.GetProperties()
.Where (p => p.PropertyType == propertyType)
.Select (p => p.Name);
return fields.Concat(properties);
}
}
Useful resources for the unresolved part:
Finding the relevant properties
if this help some one.
first find all properties within Customer class with same type as query:
var stringProperties = typeof(Customer).GetProperties().Where(prop =>
prop.PropertyType == query.GetType());
then find all customers from context that has at least one property with value equal to query:
context.Customer.Where(customer =>
stringProperties.Any(prop =>
prop.GetValue(customer, null) == query));

NHibernate Linq ToFuture and Max

I want the following two queries to be executed in single round trip to database so I'm using ToFutureValue.
var query = AsQueryable()
.Where(x => x.User == user);
var singinCount = query
.Where(x => x.ActionDate >= from && x.ActionDate <= to)
.ToFutureValue(q => q.Count());
var lastSignin = query
.Where(x => x.ActionName.ToLower() == Actions.Signin))
.ToFutureValue(q => q.Max(x => x.ActionDate));
The problem is that Count and Max returns result but not IQueryable. I have found the following extension that enables me to pass Count to ToFutureValue:
public static IFutureValue<TResult> ToFutureValue<TSource, TResult>(
this IQueryable<TSource> source, Expression<Func<IQueryable<TSource>, TResult>> selector)
where TResult : struct
{
var provider = (INhQueryProvider)source.Provider;
var method = ((MethodCallExpression)selector.Body).Method;
var expression = Expression.Call((Expression)null, method, source.Expression);
return (IFutureValue<TResult>)provider.ExecuteFuture(expression);
}
Now I need to adopt that extension for Max because I have to pass arguments to Max (.ToFutureValue(q => q.Max(x => x.ActionDate))). How can I do that?
as a workaround
var lastSignin = query
.Where(x => x.ActionName.ToLower() == Actions.Signin))
.OrderByDescending(x => x.ActionDate)
.Take(1)
.ToFutureValue();
It looks like there is appropriate patch in GitHub pull request
#120
And here is jira bug NH-3184
the following is code from pull #120 that works:
public static IFutureValue<TResult> ToFutureValue<T, TResult>(
this IQueryable<T> query, Expression<Func<IQueryable<T>, TResult>> selector)
{
var nhQueryable = query as QueryableBase<T>;
if (nhQueryable == null)
{
throw new NotSupportedException("Query needs to be of type QueryableBase<T>");
}
var provider = (INhQueryProvider) query.Provider;
var expression = ReplacingExpressionTreeVisitor.Replace(
selector.Parameters.Single(),
query.Expression,
selector.Body);
return (IFutureValue<TResult>) provider.ExecuteFuture(expression);
}

Dynamically Sorting with LINQ

I have a collection of CLR objects. The class definition for the object has three properties: FirstName, LastName, BirthDate.
I have a string that reflects the name of the property the collection should be sorted by. In addition, I have a sorting direction. How do I dynamically apply this sorting information to my collection? Please note that sorting could be multi-layer, so for instance I could sort by LastName, and then by FirstName.
Currently, I'm trying the following without any luck:
var results = myCollection.OrderBy(sortProperty);
However, I'm getting a message that says:
... does not contain a defintion for 'OrderBy' and the best extension method overload ... has some invalid arguments.
Okay, my argument with SLaks in his comments has compelled me to come up with an answer :)
I'm assuming that you only need to support LINQ to Objects. Here's some code which needs significant amounts of validation adding, but does work:
// We want the overload which doesn't take an EqualityComparer.
private static MethodInfo OrderByMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(method => method.Name == "OrderBy"
&& method.GetParameters().Length == 2)
.Single();
public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
this IEnumerable<TSource> source,
string propertyName)
{
// TODO: Lots of validation :)
PropertyInfo property = typeof(TSource).GetProperty(propertyName);
MethodInfo getter = property.GetGetMethod();
Type propType = property.PropertyType;
Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
Delegate func = Delegate.CreateDelegate(funcType, getter);
MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
typeof(TSource), propType);
return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null,
new object[] { source, func });
}
Test code:
string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
foreach (string x in foo.OrderByProperty("Length"))
{
Console.WriteLine(x);
}
Output:
Jon
Tom
Holly
Robin
William
It even returns an IOrderedEnumerable<TSource> so you can chain ThenBy clauses on as normal :)
You need to build an Expression Tree and pass it to OrderBy.
It would look something like this:
var param = Expression.Parameter(typeof(MyClass));
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
Expression.Property(param, sortProperty),
param
);
Alternatively, you can use Dynamic LINQ, which will allow your code to work as-is.
protected void sort_grd(object sender, GridViewSortEventArgs e)
{
if (Convert.ToBoolean(ViewState["order"]) == true)
{
ViewState["order"] = false;
}
else
{
ViewState["order"] = true;
}
ViewState["SortExp"] = e.SortExpression;
dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression);
}
public void dataBind(bool ord, string SortExp)
{
var db = new DataClasses1DataContext(); //linq to sql class
var Name = from Ban in db.tbl_Names.AsEnumerable()
select new
{
First_Name = Ban.Banner_Name,
Last_Name = Ban.Banner_Project
};
if (ord)
{
Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
else
{
Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
grdSelectColumn.DataSource = Name ;
grdSelectColumn.DataBind();
}
you can do this with Linq
var results = from c in myCollection
orderby c.SortProperty
select c;
For dynamic sorting you could evaluate the string i.e. something like
List<MyObject> foo = new List<MyObject>();
string sortProperty = "LastName";
var result = foo.OrderBy(x =>
{
if (sortProperty == "LastName")
return x.LastName;
else
return x.FirstName;
});
For a more generic solution see this SO thread: Strongly typed dynamic Linq sorting
For this sort of dynamic work I've been using the Dynamic LINQ library which makes this sort of thing easy:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx
You can copy paste the method I post in that answer, and change the signature/method names:
How to make the position of a LINQ Query SELECT variable
You can actually use your original line of code
var results = myCollection.OrderBy(sortProperty);
simply by using the System.Linq.Dynamic library.
If you get a compiler error (something like cannot convert from or does not contain a definition...) you may have to do it like this:
var results = myCollection.AsQueryable().OrderBy(sortProperty);
No need for any expression trees or data binding.
You will need to use reflection to get the PropertyInfo, and then use that to build an expression tree. Something like this:
var entityType = typeof(TEntity);
var prop = entityType.GetProperty(sortProperty);
var param = Expression.Parameter(entityType, "x");
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
myCollection,
(dynamic) access);

How can I do an OrderBy with a dynamic string parameter?

I want to do this:
var orderBy = "Nome, Cognome desc";
var timb = time.Timbratures.Include("Anagrafica_Dipendente")
.Where(p => p.CodDipendente == 1);
if(orderBy != "")
timb = timb.OrderBy(orderBy);
Is there an OrderBy overload available that accepts a string parameter?
If you are using plain LINQ-to-objects and don't want to take a dependency on an external library it is not hard to achieve what you want.
The OrderBy() clause accepts a Func<TSource, TKey> that gets a sort key from a source element. You can define the function outside the OrderBy() clause:
Func<Item, Object> orderByFunc = null;
You can then assign it to different values depending on the sort criteria:
if (sortOrder == SortOrder.SortByName)
orderByFunc = item => item.Name;
else if (sortOrder == SortOrder.SortByRank)
orderByFunc = item => item.Rank;
Then you can sort:
var sortedItems = items.OrderBy(orderByFunc);
This example assumes that the source type is Item that have properties Name and Rank.
Note that in this example TKey is Object to not constrain the property types that can be sorted on. If the func returns a value type (like Int32) it will get boxed when sorting and that is somewhat inefficient. If you can constrain TKey to a specific value type you can work around this problem.
Absolutely. You can use the LINQ Dynamic Query Library, found on Scott Guthrie's blog. There's also an updated version available on CodePlex.
It lets you create OrderBy clauses, Where clauses, and just about everything else by passing in string parameters. It works great for creating generic code for sorting/filtering grids, etc.
var result = data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo asc");
var query = DbContext.Data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo ascending");
Another solution from codeConcussion (https://stackoverflow.com/a/7265394/2793768)
var param = "Address";
var pi = typeof(Student).GetProperty(param);
var orderByAddress = items.OrderBy(x => pi.GetValue(x, null));
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
You don't need an external library for this. The below code works for LINQ to SQL/entities.
/// <summary>
/// Sorts the elements of a sequence according to a key and the sort order.
/// </summary>
/// <typeparam name="TSource">The type of the elements of <paramref name="query" />.</typeparam>
/// <param name="query">A sequence of values to order.</param>
/// <param name="key">Name of the property of <see cref="TSource"/> by which to sort the elements.</param>
/// <param name="ascending">True for ascending order, false for descending order.</param>
/// <returns>An <see cref="T:System.Linq.IOrderedQueryable`1" /> whose elements are sorted according to a key and sort order.</returns>
public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string key, bool ascending = true)
{
if (string.IsNullOrWhiteSpace(key))
{
return query;
}
var lambda = (dynamic)CreateExpression(typeof(TSource), key);
return ascending
? Queryable.OrderBy(query, lambda)
: Queryable.OrderByDescending(query, lambda);
}
private static LambdaExpression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}
(CreateExpression copied from https://stackoverflow.com/a/16208620/111438)
I did so:
using System.Linq.Expressions;
namespace System.Linq
{
public static class LinqExtensions
{
public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string dir = "asc")
{
// parametro => expressão
var parametro = Expression.Parameter(typeof(TSource), "r");
var expressao = Expression.Property(parametro, field);
var lambda = Expression.Lambda(expressao, parametro); // r => r.AlgumaCoisa
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "OrderBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "OrderByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string field, string dir = "asc")
{
var parametro = Expression.Parameter(typeof(TSource), "r");
var expressao = Expression.Property(parametro, field);
var lambda = Expression.Lambda<Func<TSource, string>>(expressao, parametro); // r => r.AlgumaCoisa
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "ThenBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "ThenByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
}
}
Use :
example.OrderBy("Nome", "desc").ThenBy("other")
Work like:
example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)
Look at this blog here. It describes a way to do this, by defining an EntitySorter<T>.
It allows you to pass in an IEntitySorter<T> into your service methods and use it like this:
public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
using (var db = ContextFactory.CreateContext())
{
IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);
return sortedList.ToArray();
}
}
And you can create an EntitiySorter like this:
IEntitySorter<Person> sorter = EntitySorter<Person>
.OrderBy(p => p.Name)
.ThenByDescending(p => p.Id);
Or like this:
var sorter = EntitySorter<Person>
.OrderByDescending("Address.City")
.ThenBy("Id");
You need to use the LINQ Dynamic Query Library in order to pass parameters at runtime,
This will allow linq statements like
string orderedBy = "Description";
var query = (from p in products
orderby(orderedBy)
select p);
If your columnName is in a variable col, then
string col="name";
list.OrderBy(x=>x[col])
As what Martin Liversage said, you can define a Func<>before you pass it to OrderBy method, but I found an interesting way to do that.
You can define a dictionary from string to Func<> like this :
Dictionary<string, Func<Item, object>> SortParameters = new Dictionary<string, Func<Item, object>>()
{
{"Rank", x => x.Rank}
};
And use it like this :
yourList.OrderBy(SortParameters["Rank"]);
In this case you can dynamically sort by string.
In one answer above:
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
There is an syntax error, ,null must be added:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null));

Resources