Where clause in Linq in List c# - c#

I have a struct like this:
struct Test
{
string name;
string family;
public Test...
}
in my code I have a list of this struct:
List<Test> testList=new List<Test>();
I have a linq expression like this:
var list =testList.Select(n=>n.Name);
but how can I filter this selection by Family of the testList? something like this:
var list=testList.Select(n=>n.Name).Where(f=>f.Family=="");
this Where clause just apply on selected Names which are a list of string
Any ideas how to do that?

Just put the Where before the Select:
var list=testList.Where(f=>f.Family=="").Select(n=>n.Name);
In Linq you need to apply the filter before projecting (unless the filter applies to the results of the projection rather than the original collection).

Filter using Where before you select just one property using Select. That way, you still get the full object:
testList.Where(t => t.Family == "").Select(t => t.Name)
After all, Select will take the object and then only pass on whatever you return in the lambda. In this case, you only return a string, so you throw all the other information from the Test object away. And as such, the information you want to filter on isn’t available anymore.
If you switch that around, you can filter on the test object, and then return only that one string.

Normally when I am checking for an empty value like that, I'll use string.IsNullOrEmpty(), just in case.
testList.Where(f=> string.IsNullOrEmpty(f.Family)).Select(n=>n.Name);

You should first apply where clause and the select your desired data:
var list=testList.Where(f=>f.Family=="").Select(n=>n.Name);

Related

It is possible to run LINQ queries over reflected generic collections?

I'm building SQL query engine that should take SQL Query as a string in the following format
from (Collection) select (fields) where (conditions)and run it over my Data class (which consists of List fields like List<Person>) and return the result of query
I've already created classes etc. now I just need to run the queries.
Query consists of Source string, ConditionsSet object which have the list of conditions, and Fields string collection which consists of names of fields that we want to display if the record match the conditions.
Let's jump to the code.
public void RunQuery(Data data, Query query)
{
var table = data.GetType().GetField(query.Source).GetValue(data); //Source object
// var output = from entry in table where QueryEngine.IsMatching(entry, query.ConditionsSet) select entry;
// Is something like this is possible? How to approach/do that? Am I forced to not use linq?
// The compiler tells that I cant use Linq because it cant find GetEnumerator in the table object
}
private bool IsMatching(object entry, ConditionsSet set)
{
foreach (Condition c in set.Conditions) // For example we assume the operator is == equality and every condition is separated by AND keyword
if (entry.GetType().GetField(c.Field).GetValue(entry).ToString() != c.Value) //c.Value is string
return false;
return true;
}
How should I approach that? Is LINQ unavailable for me?

Selecting specific columns with Linq, using string or propertyInfo

I am rebuilding our reporting system using EF, where as our old system used a lot of dynamic SQL (bad i know), so i would like to do it using Linq, so it uses parameterized queries etc.
In a report a user can choose which columns of data they want to view. Now how can i take these values and return an SQL statement using Linq and get the columns i need? I wonder if i should even bother and just return all the data, then just show the columns the user wants on screen, which may be want i need to do, but thought i would ask anyway.
So lets take the following Linq example, i say i would only like the Id, Name and Town, how could i do this. Currently i have something similar to
var columns = new List<string>() { "Id", "Name", "Town" };
return _context.Data
.Where(e => e.Name == "test")
.ToList();
Is this even possible?
if you yant select propertys accordance their names try Dynamic LINQ library:
public List<Data> ListByNames(string[] arr)
{
var str = string.Format("new ({0})", string.Join(", ", arr));
return _context.Data.Select(str);
}
Or write your own Expression, see #TomBrothers answer: https://stackoverflow.com/a/4546633/1271037
I know this kind of problem. Chief problem: with EF you are not handling columns any more but properties.
Try somthing like this:
var column="yourcolumn";
return _context.Data.Where(e => e.GetType().GetProperty(column).GetValue(_context, null)).ToList();

Filter Generic Collection Down to Records Containing Any Item in Collection of String

string rep = "Joe Shmoe"
ObjectSet<StoreData> storeData = edmContext.StoreData;
ObjectSet<CallData> callData = edmContext.CallData;
IEnumerable<string> repStoreData = storeData.Where(r => r.RepName == rep).Select(s => s.Location);
IEnumerable<CallData> repCallData = Here is where I want to filter down the callData collection down to just the records that have a location that is contained in the repStoreData collection
I've tried using some form of Join and Any but don't really understand the arguments those are asking for.
This was my best attempt and it is a no go.
... = callData.Join(d => d.LOCATION.Any(repStoreData));
Well you don't have to use a join. You could just use:
callData.Where(d => repStoreData.Contains(d.LOCATION))
That's assuming d.LOCATION is a single string.
However, you probably don't want to do that with your current declaration of repStoreData as IEnumerable<string> - LINQ won't be able to turn that into a query to be executed at the database.
If you're able to declare repStoreData as IQueryable<string>, however, that would be more likely to work well. I don't know whether that will work with ObjectSet<T>, but I'd hope so.

How get propery value of an dynamic type?

[update]
I'm sorry, i should tag this question
as MVC-2, I pass result of query into
view's model, so i must specify type
of my model in View's header
defintion. I declare it like this:
Inherits="System.Web.Mvc.ViewPage<IQueryable<dynamic>>"
how ever nothing changed and none of
answers doesn't work for me :(.
finally i used an ModelView class as
helper to put my query result in it.
:(
[/update]
I have a query like this:
IQueryable<dynamic> result = from d in KiaNetRepository.KiaNetEntities.Discounts
where d.AgentTypeID == agentTypeId
select new { d.Category, d.DiscountValue, d.PriceConfige };
then i retrive value in my view like this:
foreach(var item in result){
Category cat = item.Category; // throws exception 'object' does not contain a definition for 'Category'
//...
}
note that type of query as IQueryable is anonymouse class...
Try to declare names explicitly:
select new { Category = d.Category, DiscountValue = d.DiscountValue, PriceConfige = d.PriceConfige }
If you are not forcing result to be of IQueryeable<dynamic> for any specific reason, I would recommend using var result = .... This will let the compiler make result of type IQueryable<T> with T the type of the anonymous class that you create using new { ... } in the select. There is no necessity for using dynamic from the code that you show here.
If you replace the inappropriate declaration IQueryable<dynamic> by var, sure it works, I've just also tested it.
Your problem is that your foreach loop being in the view page gets compiled into a separate assembly. Since anonymous types are internal the dynamic doesn't see it because of the permissions don't allow it.
Simplest fix is to call ToList() on your query statement and then select each anonymous type and copy parameters to a declared class or expandoobject.

How can I use drop down list value (String) to filter linq results?

I'm filling a drop-down list using the following:
var columnNames = db.Mapping.MappingSource.GetModel(typeof(StaffDirectoryDataContext))
.GetMetaType(typeof(Person)).DataMembers;
I'm then converting that to a List<String> to populate a drop down list.
I then want to be able to get a set of results based on the user's selection. For example, if they select "First name" from the drop down list and type "Bob" into the text box I want to run a LINQ query where first name = bob.
I'm probably being thick but I can't find a way! Pseudo code would be...
var q = from x in dc.Persons
where x.[selected column name] == [textbox value]
select x;
Can anybody help? Essentially I have the column name as a String value, and I can't figure out how to tell the LINQ query that that's the column to filter on!
Could do this in ADO.NET with my eyes closed, but determined to use LINQ all the way!!
Thanks in advance.
David Buchanan has posted a solution for this problem using reflection :
msdn forum
I'm not sure you can do this dynamically, but you can do it conditionally. Something like this:
switch(selected column name)
{
case "student_no":
q = q.where(p=>p.StudentNo == value);
break;
case "student_id":
q = q.where(p=>p.StudentId == value);
break;
}
You can iterate through your columns and keep building the wheres. The SQL won't be executed as long as none of the calls force the IQueryable to execute.
I think expression trees are the right way to do this, but I don't know them very well so I'm going to give you the alternate way I would have done this if I didn't feel like learning expression tree building..
public interface IFilter { IEnumerable RetreiveFilter(string filterValue); }
public class FirstNameFilter : IFilter
{
private const string FILTER_TYPE_NAME = "First Name";
public IEnumerable RetreiveFilter(string filterValue)
{
return _myData.Where(person => person.FirstName = filtervalue);
}
public override string ToString()
{
return FILTER_TYPE_NAME;
}
}
Create a class like this for each filter type, and then fill your dropdown with these filters, and when they type info into the filter text, it will execute against the ((IFilter)filterDropDown.SelectedItem).RetreiverFilter(filterTextBox.Text);

Categories

Resources