I'm trying to write a linq query that takes a dynamic property name. So for example, if the property name is 'test', a simple query would look like this:
var test = testList.Select(x => x.test).Distinct().ToList();
But I want to dynamically generate the property name, eg:
var propertyName = "test";
var test = testList.Select(x => x.propertyName).Distinct().ToList();
I get an error because 'propertyName' isn't an actual property.
What would be the best way to achieve this?
You'd have to use reflection to do what you're trying to do:
var test = testList
.Select(x => x.GetType().GetProperty(propertyName).GetValue(x))
.Distinct()
.ToList();
Related
I am using MVC and I have my entity model class which has a string property "type". My get method returns an array of strings to the post called objTypes[] from a MultiSelectList.
What I would like to do is a LINQ query to my db to query back only the objs that have type equal to one of the strings in the array. Similar to this:
objs = objs.Where(o => o.type == ("any of objType elements"))
You can use the Contains() method. Simply use:
var filteredObjs = objs.Where(o => objTypes.Contains(o.type));)
I think you can try this..
var objTypes = db.OBjs.select(a=>a.type).ToList();
var result = objs.Where(o => objTypes.Contains(o.type));
I have a list with addresses and each address has a 'From' property. I want to order them on that property using Linq.
This is what I have:
var orderedAddresses = addresses.OrderBy(?what goes here?);
This should be the code you are looking for assuming that your field is From
var orderedAddresses = addresses.OrderBy(x => x.From);
To OrderBy two columns you can use
var orderedAddresses = addresses.OrderBy(x => x.From).ThenBy(y => y.AnotherField);
I want do something like this:
string test = alarmType;
db.Alarms.Where(alarmType.Contains(m => m.Type)).ToList();
But this doesn't work. How can I make such query? Is it the only way to use pure SQL?
UPD
I'm trying to find whether records is substring of the "test", not conversly.
You have to reverse the condition:
var query = db.Alarms
.Where(a => alarmType.Contains(a.Type))
.ToList();
However, your code sample is confusing, if alarmType is a string i don't know what you're trying to achieve.
string test = alarmType;
Update: if you're using LINQ-To-Sql and you want to find all records where the Type is a substring of alarmType you can use:
var query = db.Alarms
.Where(a => SqlMethods.Like(alarmType, string.Format("%{0}%", a.Type)))
.ToList();
Try the following
string test = alarmType;
var result = db.Alarms.Where(m => alarmType.Contains(m.Type)).ToList();
Your LINQ query isn't well-formatted. You have:
db.Alarms.Where(alarmType.Contains(m => m.Type)).ToList();
So the parameter you've passed to Contains is a lambda, which isn't what Contains takes,
Likeiwse, Contains returns a bool, so you've passed a bool to Where, which is also not a parameter type it takes.
What you want is to pass a lambda to Where, like so:
db.Alarms.Where(m => alarmType.Contains(m.Type)).ToList();
Note how now both the Where and the Contains are being passed parameters of the correct type.
I want to populate a drop down with the public properties of a particular object, which I have done fine. But now when the user selects the value from the dropdown, I want it to group the DB table results by that column. I have tried using LINQ but I can only figure out how to explicitly group by an instance variables property, not by a reflection property. This is my method - the parameter passed in is the string name of the property. Eg it will be "Country" if the user wants to group by Customer.Country, it will be "State" if the user wants to group by Customer.State. But at the moment I have hard coded to group by "State" as I cannot figure out how to use the string value passed in with my LINQ query
private void DisplayReportAction(string category)
{
if (!string.IsNullOrEmpty(category))
{
SelectedCategory = category;
_summaries.Clear();
foreach (var custGroup in _customerInterface.CustomerInterface.GetAllCustomers().GroupBy(c => c.State)
.Select(group => new
{
Category = group.Key,
Count = group.Count()
})
.OrderBy(x => x.Category))
{
_summaries.Add(new CustomerReportSummaryViewModel(custGroup.Category, custGroup.Count));
}
ReportVisibility = Visibility.Visible;
}
}
You can use Reflection if you are using LINQ to Objects, for instance you can use this:
_customerInterface.CustomerInterface.GetAllCustomers()
.GroupBy(c => c.GetType().GetProperty(category).GetValue(c, null))
If you are using Linq To Sql then an alternative is to use dynamic queries, check this link
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You may build expression dynamically:
Expression<Func<Customer,T>> buildExpression<T>(string category)
{
//First build parameter of lambda ( 'c =>' part of expression)
ParameterExpression param = Expression.Parameter(typeof(Customer), "c");
//Then body of expression : ' => c.category'
Expression<Func<Customer, T>> exp = Expression.Lambda<Func<Customer, T>>(Expression.Property(param, category), param);
return exp;
}
And finally, call
_customerInterface.CustomerInterface.GetAllCustomers()
.GroupBy(buildExpression(category))
EDIT:
Well, sorry you still have to know the type of property to give T type parameter to buildExpression function
There are ways to do this, using for example GetProperty(category).PropertyType and then call MakeGenericMethod on GetType().GetMethod("buildExpression<>"), but this requires a little more work.
Anyway, you'll have to find a way to build CustomerReportSummaryViewModel from this type.
I don't know your use case, but you maybe all categories properties are of the same type, so you could hard-code it ?
If you are interested, and can't find a proper way to do it let me know I'll try to write a proper solution.
I'm sure that this can be easily done with Linq but I can't figure it out.
var ls1 = plotter.Model.Series.FirstOrDefault(x => x.IsSelected);
var ls2 = plotter.Model.Series.FirstOrDefault((x => x.IsSelected)&&(ls2!=ls1));
What I'm pretending to do is to obtain the two first objects that have their property IsSelected set to true.
I can't use the syntax written above because the compiler can't use "local variable ls2 before it is declared".
Use Where to filter only the selected results then use Take to select the first two e.g.
plotter.Model.Series.Where(x => x.IsSelected).Take(2);
Try this:
var ls1and2 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
You should use the Take method and do this
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);