How do I perform a dynamic select in Linq? - linq

I am trying to figure out how to dynamically specify the properties for my select clause in a linq query.
Lets say I have a collection of employee objects. At run time, the end user will be specifying which properties they would like to see for those employees, so I need to be able to dynamically construct my Linq select clause.
I have used the dynamic Linq library, but I prefer not to use that, because it requires me to build a string to pass to the select method. I'd like to understand how to do this via Expressions.

This looks like something that fits more with your requirements of not using dynamic linq.

Use Reflection to get the dynamic Column Values
//columns variable has column name as comma separated String which you
can save in DB //example string columns ="Name,Id,Age";
var strColumns =columns.split(,);
foreach(var myObject in MyObjectcollection)
{
for(int index =0;index<strColumns.count();index++)
{
//Create a collection of objects
mycollection.add(myObject.GetType().GetProperty(strColumns[index]).GetValue(myObject, null));
}
}

Related

Realm Xamarin LINQ Select

Is there a way to restrict the "columns" returned from a Realm Xamarin LINQ query?
For example, if I have a Customer RealmObject and I want a list of all customer names, do I have to query All<Customer> and then enumerate the results to build the names list? That seems cumbersome and inefficient. I am not seeing anything in the docs. Am I missing something obvious here? Thanks!
You have to remember that Realm is an object based store. In a RDBMS like Sqlite, restricting the return results to a sub-set of "columns" of an "record" makes sense, but in an object store, you would be removing attributes from the original class and thus creating a new dynamic class to then instantiate these new classes as objects.
Thus is you want just a List of strings representing the customer names you can do this:
List<string> names = theRealm.All<Customer>().ToList().Select(customer => customer.Name).ToList();
Note: That you take the Realm.All<> results to a List first and then using a Linq Select "filter" just the property that you want. Using a .Select directly on a RealmResults is not currently supported (v0.80.0).
If you need to return a complex type that is a subset of attributes from the original RealObject, assuming you have a matching POCO, you can use:
var custNames = theRealm.All<Customer>().ToList().Select((Customer c) => new Name() { firstName = c.firstName, lastName = c.lastName } );
Remember, once you convert a RealmResult to a static list of POCOs you do lose the liveliness of using RealmObjects.
Personally I avoid doing this whenever possible as Realm is so fast that using a RealmResult and thus the RealObjects directly is more efficient on processing time and memory overhead then converting those to POCOs everytime you need to new list...

Building a dynamic anonymous type Select statement using Linq

//list is IEnumeable NOT IEnumerable<T>
var IEnumerable<object> = list.AsQueryable().Cast<object>().Select(x=> .........);
object actually has a POCO underlying Anonymous class e.g
AccountId,Name,SecretInfo
What I want in the select statement is
AccountId = x.GetType().GetProperty("AccountId").GetValue(x,null),
Name = x.GetType().GetProperty("Name").GetValue(x,null)
Also I want to hide the SecretInfo Column which I can pass as a hardcoded string "SecretInfo"
Basically the select list needs to be built up dynamically on the Anonymous type....
How can this be done....Any Linq punters out there who can help me?
The answer to your question relies on anonymous types. The following code is what you can use:
var result = list.AsQueryable().Cast<Info>().Select(x => new
{
AccountId = x.AccountId,
Name = x.Name
});
Between the brackets that follow the new keyword in the select statement, you are creating an anonymous type that will have two implicitly typed read-only fields (AccountId and Name). Hope this helps!
I would like to post this quote from the linked (no pun intended) article:
Anonymous types typically are used in the select clause of a query expression to return a subset of the properties from each object in the source sequence. For more information about queries, see LINQ Query Expressions (C# Programming Guide).

Get all the includes from an Entity Framework Query?

I've the following Entity Model : Employee has a Company and a Company has Employees.
When using the Include statement like below:
var query = context.Employees.Include(e => e.Company);
query.Dump();
All related data is retrieved from the database correctly. (Using LEFT OUTER JOIN on Company table)
The problem is hat when I use the GroupBy() from System.Linq.Dynamic to group by Company.Name, the Employees are missing the Company data because the Include is lost.
Example:
var groupByQuery = query.GroupBy("new (Company.Name as CompanyName)", "it");
groupByQuery.Dump();
Is there a way to easily retrieve the applied Includes on the 'query' as a string collection, so that I can include them in the dynamic GroupBy like this:
var groupByQuery2 = query.GroupBy("new (Company, Company.Name as CompanyName)", "it");
groupByQuery2.Dump();
I thought about using the ToString() functionality to get the SQL Command like this:
string sql = query.ToString();
And then use RegEx to extract all LEFT OUTER JOINS, but probably there is a better solution ?
if you're creating the query in the first place - I'd always opt to save the includes (and add to them if you're making a composite query/filtering).
e.g. instead of returning just 'query' return new QueryContext {Query = query, Includes = ...}
I'd like to see a more elegant solution - but I think that's your best bet.
Otherwise you're looking at expression trees, visitors and all those nice things.
SQL parsing isn't that straight either - as queries are not always that simple (often a combo of things etc.).
e.g. there is a `span' inside the query object (if you traverse a bit) which seems to be holding the 'Includes' but it's not much help.

linq problem with distinct function

I am trying to bind distinct records to a dropdownlist. After I added distinct function of the linq query, it said "DataBinding: 'System.String' does not contain a property with the name 'Source'. " I can guarantee that that column name is 'Source'. Is that name lost when doing distinct search?
My backend code:
public IQueryable<string> GetAllSource()
{
PromotionDataContext dc = new PromotionDataContext(_connString);
var query = (from p in dc.Promotions
select p.Source).Distinct();
return query;
}
Frontend code:
PromotionDAL dal = new PromotionDAL();
ddl_Source.DataSource = dal.GetAllSource();
ddl_Source.DataTextField = "Source";
ddl_Source.DataValueField = "Source";
ddl_Source.DataBind();
Any one has a solution? Thank you in advance.
You're already selecting Source in the LINQ query, which is how the result is an IQueryable<string>. You're then also specifying Source as the property to find in each string in the databinding. Just take out the statements changing the DataTextField and DataValueField properties in databinding.
Alterantively you could remove the projection to p.Source from your query and return an IQueryable<Promotion> - but then you would get distinct promotions rather than distinct sources.
One other quick note - using query syntax isn't really helping you in your GetAllSources query. I'd just write this as:
public IQueryable<string> GetAllSource()
{
PromotionDataContext dc = new PromotionDataContext(_connString);
return dc.Promotions
.Select(p => p.Source)
.Distinct();
}
Query expressions are great for complicated queries, but when you've just got a single select or a where clause and a trivial projection, using the dot notation is simpler IMO.
You're trying to bind strings, not Promotion objects... and strings do not have Source property/field
Your method returns a set of strings, not a set of objects with properties.
If you really want to bind to a property name, you need a set of objects with properties (eg, by writing select new { Source = Source })

Dynamic Linq - no property or field exists in type 'datarow'

I am using Northwind Customers Table where I fill the dataset and get the datatable.
I am trying to use dynamic linq and want to select columnName dynamically
var qry = MyDataTable.AsEnumerable().AsQueryable().Select("new(Country)");
Right now I have hard coded country but even then I get this error
No property or field 'Country' exists in type 'datarow'
I would like to eventually change this query to take the column name dynamically.
Please help!!! thanks.
The important hint is here (in bold):
No property or field 'Country' exists
in type 'datarow'
The extension method AsEnumerable of the DataTable class returns an IEnumerable<T> where T has the type DataRow. Now the Select method of Dynamic LINQ wants to work with this type DataRow which hasn't a property Country of course.
You could try this instead:
var qry = MyDataTable.AsEnumerable().AsQueryable()
.Select("new(it[\"Country\"] as CountryAlias)");
it now represents a variable of type DataRow and you can use methods of this type and perhaps also the indexer in my example above. (Dynamic LINQ supports accessing array elements by an integer index, but I am not sure though if accessing an indexer with a string key will work.)
I've used Slauma's answer and it worked. In addition i was doing OrderBy with dynamic linq maybe this will help to someone. I'll just drop the code here.
string dynamicLinqText = $"it[\"{sortColumnName}\"] {sortDirection}"; //it["PERSON_NAME"] asc
result = result.AsEnumerable().OrderBy(dynamicLinqText).CopyToDataTable();

Resources