LINQ Entity Framework Variable to select db Column - c#

does anyone know how do I query a variable to select a column name of a table? Example is given as below. Instead of Select(x => x.ColumnName), I would like to Select(field).
public bool isFound(string field, int id)
{
db.Table.Where(x => x.tableID == id).Select(field).First();
return;
}

Try this,
string field = "tableID";
ParameterExpression param = Expression.Parameter(typeof(Table), "x");
MemberExpression propExpression = Expression.PropertyOrField(param, field);
Expression<Func<Table, string>> selector = Expression.Lambda<Func<Table, string>>(propExpression, param);
var result = db.Table.Select(selector).First();
Or Use Nuget package DotNetHelper - https://www.nuget.org/packages/DotNetHelper/
Install-Package DotNetHelper
-
var result = db.users.SelectFirst<Table, string>("Name");

This is completely untested and I'm not sure its a thing, but could you create a templated extension method?
public static IQueryable<T> Select(this IQueryable<T> list, string field)
{
// Create an Expression and find the property field
ParameterExpression pe = Expression.Parameter(typeof(string), field);
// Apply the Expression to the IQueryable
}
Here's a link with some expression creation:
https://msdn.microsoft.com/en-us/library/Bb882637.aspx

Have a look at the dynamic linq library:
https://www.nuget.org/packages/System.Linq.Dynamic.Library/
I have a project where I return a list of distinct values from a specified column as follows:
public static List<string> GetValuesFromDB(string column)
{
GradInfoEntities db = new GradInfoEntities();
//if i pass the column name in it doesn't work
//i suspect that if i pass as param, it gets quoted coz i'm passing in the value, not the column
var temp = db.Grads.Where(string.Format("{0} != null", column)).Select(column);
List<string> result = temp.Cast<string>().ToList();
return result;
}
The Dyamanic Linq Library adds overloads for where and select (and a few others, but I've only used those two) that allow you to specify which columns you want to select via a passed in variable.
I've snipped out the sorting and distinct call, but basically I'm returning a string list of all values that aren't null from the passed in column
Edit: I've just checked and there is no First(), but there is a Take(), and an Any()

Related

Use multiple ThenBy directly without any order

I'm trying to sort based on multiple columns simultaneously in LINQ.
To achieve to this sorted list I should use SortBy for the first column and then multiple ThenBy to sort the result of OrderBy by another column.
But the problem is that I don’t have any order in using ThenBy(s) and that's because user chooses the first column and I use this column as parameter to OrderBy and the rest of columns are parameters to ThenBy.
So I first, declare a dynamic global variable like :
dynamic result;
Then create an entity model like :
DatabaseEntityContext context = new DatabaseEntityContext();
And query data to get an adequate Anonymous Data Type :
var query1 = db.context.Select(x => new { Column1 = x.Column1, Column2 = x.Column2,
Column3 = x.Column3, Column4 = x.Column4, Column5 = x.Column5 }).ToList();
var query2 = query1.Select(x => new { Column1 = x.Column1, Column2 = x.Column2,
Column3 = x.Column3, TotalColumn = x.Column4 + "-" + x.Column5 }).ToList();
And finally assign query2 to result like :
result = query2;
To use LINQ functions on result I cast it to ((IEnumerable<dynamic>)result)
but the thing is the result of this cast doesn't have any ThenBy extension and I can't use OrderBy first because the list may already been sorted by another column and I should use a ThenBy to sort it again based on the result of previously sorted list.
My problem is, I have multi factors to use in ThenBy but I can’t sort this because I should OrderBy first,then use ThenBy after OrderBy and I can’t use ThenBy directly.
So how can I use ThenBy directly with a previously ordered list ?!
Update 1 :
According to #Patrick Hofman I changed my cast type to IOrderedQueryable like :
result = ((IOrderedQueryable<dynamic>)result).ThenBy(x => x.MyDynamicField).ToList();
but no it gives me a compile error on "x.MyDynamicField" :
An expression tree may not contain a dynamic operation
I also test IOrderedEnumerable but it gives InvalidCastException error :
Unable to cast object of type
'System.Collections.Generic.List1[<>f__AnonymousType15[System.String,System.String,System.DateTime,System.TimeSpan,System.Nullable1[System.Int32]]]'
to type 'System.Linq.IOrderedEnumerable1[System.Object]'.
ThenBy is an extension method on IOrderedQueryable, not IEnumerable. If you want to call ThenBy, you should cast it to an IOrderedQueryable:
var r = ((IOrderedQueryable<dynamic>)result).ThenBy(...);
As juharr commented, you can even expand this to check the type and then chose either ThenBy or OrderBy, using the same predicate to filter on.
Instead of using OrderBy/ThenBy you could:
public static class QueryableOrderBy
{
public static IOrderedQueryable<TSource> OrderBySimple<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
{
var ordered = source as IOrderedQueryable<TSource>;
if (source != null)
{
return ordered.ThenBy(keySelector);
}
return source.OrderBy(keySelector);
}
public static IOrderedQueryable<TSource> OrderByDescendingSimple<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
{
var ordered = source as IOrderedQueryable<TSource>;
if (source != null)
{
return ordered.ThenByDescending(keySelector);
}
return source.OrderByDescending(keySelector);
}
}
These methods will "analyze" if there is already another OrderBy (then they will use ThenBy) or not.

Cannot get the dynamic OrderBy to work on my generic list

I cannot get the dynamic OrderBy to work on my generic list;
var list = CacheObjects.CompetencyAssessments
.Select(x => new CompetencyAssessmentLineViewModel(x))
.ToList();
var sortInfo = string.Format("{0} {1}", request.SortingName, request.SortingOrder);
var displayList = list.AsQueryable()
.OrderBy(sortInfo)
.Skip(startIndex)
.Take(pageLength);
I am using a string for the dynamic functionality of OrderBy.
But the code does not compile;
Error 1 The type arguments for method 'System.Linq.Queryable.OrderBy(System.Linq.IQueryable, System.Linq.Expressions.Expression>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
What am I doing wrong?
The signature of the method is:
public JsonResult GridData(JqGridRequest request)
and JqGridRequest is from the NuGet package Lib.Web.Mvc. So:
request.SortingName is a string with the name of the field, and
request.SortingOrder is the sort order
See: http://tpeczek.com/2011/03/jqgrid-and-aspnet-mvc-strongly-typed.html
I suspect you've confused IEnumerable and IQueryable with the Dynamic LINQ library mentioned by Scott Guthrie 6 years ago. This is an external library that you have to add to your project. Its latest version was released as a NuGet package 2 years ago.
The library has some limitations, so another System.Linq.Dynamic project appeared in Codeplex last year.
Neither of the libraries is an official, supported LINQ provider. You can use them if they are convenient but you shouldn't frequent updates to them.
Actually, since you seem to be building an ASP.NET MVC application, it may be better to sort the results in the view or Javascript than try to do so on the server side. Most grids allow sorting by a column.
If you want to sort the results for paging purposes, a better option would be to do so using using your ORM's language, eg Entity SQL for Entity Framework or HQL for NHibernate.
The problem was that the Dynamic library was referenced twice in my project. At least I know what to look out for if something like this happens again.
As the error message is telling you, you're passing a string to OrderBy wen it's expecting an Expression<Func<CompetencyAssessmentLineViewModel, TKey>>. You need to provide such an expression.
Creating one is hard, because you don't even know the type of the field you are sorting on at compile time. This means that once you generate the proper expression for selecting the property, you have to use reflection to call OrderBy simply because the generic arguments cannot be supplied at compile time.
private static Tuple<Expression, Type> GetSelector<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T));
Expression body = Expression.Property(parameter, propertyName);
return Tuple.Create(Expression.Lambda(body, parameter) as Expression
, body.Type);
}
private static IOrderedQueryable<T> OrderBy<T>(IQueryable<T> query,
string property, bool ascending)
{
var selector = GetSelector<T>(property);
Type[] argumentTypes = new[] { typeof(T), selector.Item2 };
var methodName = ascending ? "OrderBy" : "OrderByDescending";
var orderByMethod = typeof(Queryable).GetMethods()
.First(method => method.Name == methodName
&& method.GetParameters().Count() == 2)
.MakeGenericMethod(argumentTypes);
return (IOrderedQueryable<T>)
orderByMethod.Invoke(null, new object[] { query, selector.Item1 });
}
private static IOrderedQueryable<T> ThenBy<T>(IOrderedQueryable<T> query,
string property, bool ascending)
{
var selector = GetSelector<T>(property);
Type[] argumentTypes = new[] { typeof(T), selector.Item2 };
var methodName = ascending ? "ThenBy" : "ThenByDescending";
var orderByMethod = typeof(Queryable).GetMethods()
.First(method => method.Name == methodName
&& method.GetParameters().Count() == 2)
.MakeGenericMethod(argumentTypes);
return (IOrderedQueryable<T>)
orderByMethod.Invoke(null, new object[] { query, selector.Item1 });
}
public static IOrderedQueryable<T> OrderBy<T>(
this IQueryable<T> query,
string property)
{
return OrderBy<T>(query, property, true);
}
public static IOrderedQueryable<T> OrderByDescending<T>(
this IQueryable<T> query,
string property)
{
return OrderBy<T>(query, property, false);
}
public static IOrderedQueryable<T> ThenBy<T>(
this IOrderedQueryable<T> query,
string property)
{
return ThenBy<T>(query, property, true);
}
public static IOrderedQueryable<T> ThenByDescending<T>(
this IOrderedQueryable<T> query,
string property)
{
return ThenBy<T>(query, property, false);
}
Now that we have all of that in place to order based on a string property, you can do essentially what you wanted to do before:
var displayList = list.OrderBy(request.SortingName)
.ThenBy(request.SortingOrder)
.Skip(startIndex)
.Take(pageLength);

Dynamically select columns in runtime using entity framework

I have an existing function like this
public int sFunc(string sCol , int iId)
{
string sSqlQuery = " select " + sCol + " from TableName where ID = " + iId ;
// Executes query and returns value in column sCol
}
The table has four columns to store integer values and I am reading them separately using above function.
Now I am converting it to Entity Framework .
public int sFunc(string sCol , int iId)
{
return Convert.ToInt32(TableRepository.Entities.Where(x => x.ID == iId).Select(x => sCol ).FirstOrDefault());
}
but the above function returns an error
input string not in correct format
because it returns the column name itself.
I don't know how to solve this as I am very new to EF.
Any help would be appreciated
Thank you
Not going to be useful for the OP 8 years later, but this question has plenty of views, so I thought it could be helpful for others to have a proper answer.
If you use Entity Framework, you should do Linq projection (Select()), because that leads to the correct, efficient query on the db side, instead of pulling in the entire entity.
With Linq Select() you normally have to provide a lambda, though, so having your your column/property name in a string poses the main difficulty here.
The easiest solution is to use Dynamic LINQ (EntityFramework.DynamicLinq Nuget package). This package provides alternatives to the original Linq methods, which take strings as parameters, and it translates those strings into the appropriate expressions.
Example:
async Task<int> GetIntColumn(int entityId, string intColumnName)
{
return await TableRepository.Entities
.Where(x => x.Id == entityId)
.Select(intColumnName) // Dynamic Linq projection
.Cast<int>()
.SingleAsync();
}
I also made this into an async call, because these days all database calls should be executed asynchronously. When you call this method, you have to await it to get the result (i.e.: var res = await GetIntColumn(...);).
Generic variation
Probably it's more useful to change it into an extension method on IQueryable, and make the column/property type into a generic type parameter, so you could use it with any column/property:
(Provided you have a common interface for all your entities that specifies an Id property.)
public static async Task<TColumn> GetColumn<TEntity, TColumn>(this IQueryable<TEntity> queryable, int entityId, string columnName)
where TEntity : IEntity
{
return await queryable
.Where(x => x.Id == entityId)
.Select(columnName) // Dynamic Linq projection
.Cast<TColumn>()
.SingleAsync();
}
This is called like this: var result = await TableRepository.Entities.GetColumn<Entity, int>(id, columnName);
Generic variation that accepts a list of columns
You can extend it further to support selecting multiple columns dynamically:
public static async Task<dynamic> GetColumns<TEntity>(this IQueryable<TEntity> queryable, int entityId, params string[] columnNames)
where TEntity : IEntity
{
return await queryable
.Where(x => x.Id == entityId)
.Select($"new({string.Join(", ", columnNames)})")
.Cast<dynamic>()
.SingleAsync();
}
This is called like this: var result = await TableRepository.Entities.GetColumns(id, columnName1, columnName2, ...);.
Since the return type and its members are not known compile-time, we have to return dynamic here. Which makes it difficult to work with the result, but if all you want is to serialize it and send it back to the client, it's fine for that purpose.
This might help to solve your problem:
public int sFunc(string sCol, int iId)
{
var _tableRepository = TableRepository.Entities.Where(x => x.ID == iId).Select(e => e).FirstOrDefault();
if (_tableRepository == null) return 0;
var _value = _tableRepository.GetType().GetProperties().Where(a => a.Name == sCol).Select(p => p.GetValue(_tableRepository, null)).FirstOrDefault();
return _value != null ? Convert.ToInt32(_value.ToString()) : 0;
}
This method now work for dynamically input method parameter sCol.
Update:
This is not in context of current question but in general how we can select dynamic column using expression:
var parameter = Expression.Parameter(typeof(EntityTable));
var property = Expression.Property(parameter, "ColumnName");
//Replace string with type of ColumnName and entity table name.
var selector = Expression.Lambda<Func<EntityTable, string>>(property, parameter);
//Before using queryable you can include where clause with it. ToList can be avoided if need to build further query.
var result = queryable.Select(selector).ToList();
You have to try with dynamic LINQ. Details are HERE
Instead of passing the string column name as a parameter, try passing in a lambda expression, like:
sFunc(x => x.FirstColumnName, rowId);
sFunc(x => x.SecondColumnName, rowId);
...
This will in the end give you intellisense for column names, so you avoid possible errors when column name is mistyped.
More about this here: C# Pass Lambda Expression as Method Parameter
However, if you must keep the same method signature, i.e. to support other/legacy code, then you can try this:
public string sFunc(string sCol , int iId)
{
return TableRepository.Entities.Where(x => x.ID == iId).Select(x => (string) x.GetType().GetProperty(sCol).GetValue(x)});
}
You might need to adjust this a bit, I didn't have a quick way of testing this.
You can do this:
var entity = _dbContext.Find(YourEntity, entityKey);
// Finds column to select or update
PropertyInfo propertyInfo = entity.GetType().GetProperty("TheColumnVariable");

Any shorter solution for select - from - where LINQ?

I have the search function. and I want to select all value in my Book table which contain _searchdata but I dont know how to express at "where" with the short code instead of listing all items of Table like this:
(I just get some items for example, it contains about 100 items like Booktitle, Author, Genre... i dont want to specify it because it's so long)
public void SearchAny(string _searchdata)
{
var searchAnyInDB = from Book x in BookDB.Books
where (x.BookTitle.Contains(_searchdata)
|| x.Author.Contains(_searchdata)
|| x.Genre.Contains(_searchdata))
select x;
DataSearch.Clear();
DataSearch = new ObservableCollection<Book>(searchAnyInDB);
}
Because LINQ to Entities and LINQ to SQL both use Expression<Func<TSource, bool>> as IQueryable.Where extension method parameter, you can use reflection to create that Expression during compile type and generate all there || instead of typing them into your source code.
Would be something like:
var searchAnyInDB = from Book x in BookDB.Books
where (GetWhereExpression<Book>(_searchdata))
select x;
And GetWhereExpression<TSource> method:
static Expression<Func<TSource, bool>> GetWhereExpression<TSource>(string value)
{
var param = Expression.Parameter(typeof(TSource));
var val = Expression.Constant(value);
var expression = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
foreach(var prop in typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if(prop.PropertyType == typeof(string))
{
expression = Expression.OrElse(expression,
Expression.Call(
Expression.Property(param, prop),
"Contains",
null,
val
)
);
}
}
return Expression.Lambda<Func<TSource, bool>>(expression, param);
}
You still can do better then that, ex. remembering the expression for type to prevent using reflection every time you need to execute the query with different search texts, etc. But it should give you an idea where to go.

c# List<string> to Lambda Expression with starter example: Refactor to handle the List

I have this:
List<string> fields;
fields[0] = "firstFieldName";
fields[1] = "secondFieldName";
...
fields[n] = "nthFieldName";
I want to get this:
var selector = p => new {p.firstField, p.secondField, ..., p.nthFieldName}
// selector is of type Expression<Func<Entity, object>>
GoofBallLogic had this code that was simliar, ending up with p => p.column
// Entity is an object in a diagram from Entity Framework 4
var p = Expression.Parameter(typeof(Entity, "p");
var selector = Expression.Lambda<Func<Entity, string>(
Expression.Property(p, columnToGroupBy), p );
EDIT: What I am trying to accomplish
I have a "generic" Repository:
public class Repository<E, C> : IRepository<E,C>
{
private C _dc {get;set;} // ObjectContext (Entity Framework 4)
private string _entityName {get;set;}
public string entityKeyName {get;private set;}
public List<string> entityKeys {get;private set;}
public Expression<Func<E, object>> entityKey {get;private set;}
private EntityContainer _containerName {get;set;}
public Repository(C myDC)
{ _dc = myDC; // TODO: check for null
// Name of "this" ObjectContext
_containerName = _dc.MetadataWorkspace.GetEntityContainer(
_dc.DefaultContainerName, DataSpace.CSpace);
// Name of "this" Entity
_entityName = _containerName.BaseEntitySets
.Where(p => p.ElementType.Name == typeof (E).Name)
.Select( p => p.Name).FirstOrDefault();
// String list of the keys
entityKeys = _containerName
.BaseEntitySets.First(meta => meta.ElementType.Name ==
typeof(E).Name)
.ElementType.KeyMembers.Select(k => k.Name).ToList();
// Thanks Jon Skeet for this cool comma sep list formula
entityKeyName = string.Join(",", entityKeys.ToArray() );
entityKey = Expression.Lambda<Func<E, object>> ...
What to do to set entityKey as an object that can be used in
an OrderBy statement since Linq to Entities requires
ordering a set before doing a .Skip().Take()
Edit:
Amazingly, Orderby can take this:
p => "field1,field2,field3"
Which allows my code to execute but doesn't actually order the items by the field values. It's a first step in TDD I guess: use a literal.
I found this an interesting problem and took some time to figure it out, and found a relatively easy way to do it.
Anyhow, here's an example on how to do a single field sort (i'll use your first field), if you want to sort on more fields you'll have to create expressions for them too and use .ThenBy(xxx) after the usual OrderBy(xxx).
// Create a parameter which passes the object
ParameterExpression param = Expression.Parameter(typeof(E), "a");
// Create body of lambda expression
Expression body = Expression.PropertyOrField(param, fieldname);
// Create lambda function
Expression<Func<E, string>> exp = Expression.Lambda<Func<E, string>>(body, param);
// Compile it so we can use it
Func<E, string> orderFunc = exp.Compile();
Now you can do an OrderBy(orderFunc) and it'll sort the list by the property named in fieldname. Only downside being it only works for string fields (return value of expression). Could probably work around that too though.
Fixed to work with any IComparable type:
// Create a parameter which passes the field
ParameterExpression param = Expression.Parameter(typeof(E), "a");
// Create body of lambda expression
Expression body = Expression.TypeAs(Expression.PropertyOrField(param, fieldname), typeof(IComparable));
// Create lambda function
Expression<Func<E, IComparable>> exp = Expression.Lambda<Func<E, IComparable>>(body, param);
// Compile it so we can use it
Func<E, IComparable> orderFunc = exp.Compile();
You cannot do this easily because you cannot construct a new expression for a type that doesn’t exist at runtime. (You can have anonymous types in C# because the C# compiler creates the type for you.)
If you want to do it the really hard way, you could generate a dynamic assembly and actually create the type you need. There is a short example here.
I suspect that there is an easier way, though. We would need to know what your goal is (what you need this expression tree for), which you haven’t stated.
From your edited question, it appears that you just want to be able to order by multiple keys. That is easily possible simply by using .OrderBy() followed by .ThenBy(). I’m assuming that you are using an IQueryable<E> here:
IQueryable<E> query = ...;
IOrderedQueryable<E> ordered = null;
foreach (var key in entityKeys)
{
// Code from Doggett to construct the lambda expression for one step
ParameterExpression param = Expression.Parameter(typeof(E), "a");
var body = Expression.TypeAs(
Expression.PropertyOrField(param, key),
typeof(IComparable));
var exp = Expression.Lambda<Func<E, IComparable>>(body, param);
if (ordered == null)
ordered = query.OrderBy(exp);
else
ordered = ordered.ThenBy(exp);
}
var finalQuery = (ordered ?? query).Skip(n).Take(m);

Categories

Resources