Using Linq when getting value from nested list - c#

I need to set a variable's value to the value of a property that is nested in several Lists. Each list only has one item except for one list. I'm trying to do this:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.Where(x => x.Name == "Misc Expenses").myListE[0].price;
This produces a compile time error that says myListD does not contain a definition for myListE. What is the correct syntax?

After the .Where clause, you need to to .First() (or .ToList()) in order to apply the Where clause:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.Where(x => x.Name == "Misc Expenses").First().myListE[0].price;
Technically, though, you can replace that .Where with .First directly, too:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.First(x => x.Name == "Misc Expenses").myListE[0].price;

Related

How to assign to a variable the results of Find

I want to assign a variable from a Find method. Something like this:
object a = Collection.Find(x => x.propertie == whatever).propertie
The problem here is if my find query doesn't find anything. I just wanted to know if there was a way to do it only with one line.
What you can do is use LINQ to project your sequence of zero to n items into a property of that sequence. This will only apply the projection if the item exists:
var a = collection.Select(x => x.Property)
.FirstOrDefault(value => value == whatever);

Proper Syntax for Extension Method Query

I am trying to do something similar to my previous post, except I am using extension methods instead of LINQ. I get an error telling me that && cannot be used, so how would I search within a table using two strings entered by the user?
var query = (App.DBConnection.Table<Notes>().Where(
c => c.Note.Contains(textBox1.Text) && c => c.Note.Contains(textBox2.Text))).Single();
TextBox_Results.Text = query.Note;
Remove the second lambda operator c =>
var query = App.DBConnection.Table<Notes>()
.Where(c => c.Note.Contains(textBox1.Text)
&& c.Note.Contains(textBox2.Text)))
.Single();
Apart from that, i would use FirstOrDefault instead of Single. The latter throws an InvalidOperationException if there are no elements or if there are more than one. The former just returns null if no item matches the predicate in the Where.
You don't need to declare the c variable again
Where(c => c.Note.Contains(textBox1.Text) && c => c.Note.Contains(textBox2.Text)))
should be
Where(c => c.Note.Contains(textBox1.Text) && c.Note.Contains(textBox2.Text)))

how to filter entity type framework object by its child object value properties?

I have an entity framework object called batch, this object has a 1 to many relationship to items.
so 1 batch has many items. and each item has many issues.
I want to filter the for batch items that have a certain issue code (x.code == issueNo).
I have written the following but Im getting this error:
items = batch.Select(b => b.Items
.Where(i => i.ItemOrganisations
.Select(o => o
.Issues.Select(x => x.Code == issueNo))));
Error 1:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<bool>>' to 'bool'
Error 2:
Cannot convert lambda expression to delegate type 'System.Func<Ebiquity.Reputation.Neptune.Model.Item,bool>' because some of the return types in the block are not implicitly convertible to the delegate return type
Select extension method needs a lambda expression that returns a boolean, but the inner o.Issues.Select returns an IEnumerable of boolean to the outer Select(o => o which result in the exception you're getting.
Try using Any instead which verifies that at least one element verifies the condition:
items = batch.Select(
b => b.Items.Where(
i => i.ItemOrganisations.Any(
o => o.Issues.Any(x => x.Code == issueNo)
)
)
);
If I understand correctly, you're trying to select through multiple layers of enumerables. In those cases you need SelectMany which flattens out the layers, not Select. LINQ's syntax sugar is made specifically to make SelectMany easier to reason about:
var items = from item in batch.Items
from org in item.ItemOrganizations
from issue in org.Issues
where issue.Code == issueNo
select item;
The compiler translates that into something like this:
var items = batch.Items
.SelectMany(item => item.ItemOrganizations, (item, org) => new {item, org})
.SelectMany(#t => #t.org.Issues, (#t, issue) => new {#t, issue})
.Where(#t => #t.issue.Code == issueNo)
.Select(#t => #t.#t.item);
You can always wrap this in a Distinct if you need to avoid duplicate items:
var items = (from item in batch.Items
from org in item.ItemOrganizations
from issue in org.Issues
where issue.Code == issueNo
select item).Distinct();
It's hard to tell what you're trying to do based on your code but I think you're looking for something like this;
var issue = batch.Select(b => b.Items).Select(i => i.Issues).Where(x => x.Code == issueNo).Select(x => x).FirstOrDefault();
The above query will return the first issue where the Issues Code property is equal to issueNo. If no such issue exists it will return null.
One problem (the cause of your first error) in your query is that you're using select like it's a where clause at the end of your query. Select is used to project an argument, when you do Select(x => x.Code == issueNo) what you're doing is projecting x.Code to a bool, the value returned by that select is the result of x.Code == issueNo, it seems like you want that condition in a where clause and then you want to return the issue which satisfies it which is what my query is doing.
items = from b in batch.Include("Items")
where b.Items.Any(x=>x.Code==issueNo)
select b;
You're getting lost in lambdas. Your LINQ chains are all embedded in each other, making it harder to reason about. I'd recommend some helper functions here:
static bool HasIssueWithCode(this ItemOrganization org, int issueNo)
{
return org.Issues.Any(issue => issue.Code == issueNo);
}
static bool HasIssueWithCode(this Item items, int issueNo)
{
return items.ItemOrganizations.Any(org => org.HasIssueWithCode(issueNo));
}
Then your answer is simply and obviously
var items = batch.Items.Where(item => item.HasIssueWithCode(issueNo));
If you inline these functions, the result is the exact same as manji's (so give manji credit for the correct answer), but I think it's a bit easier to read.

LinQ Statement for filterings

Im trying to filter out an ObservableCollection<MainBusinessObject> where I need to filter all items in the collection that have Subobject.PropertyX == true.
MainBusinessObject
- PropertyA int
- PropertyB string
- ListOfSubobject ObservableCollection<Subobject>
Subobject
- PropertyX bool
- PropertyY int
- PropertyZ - string
I really want to stay away from looping and if statements, but I can't seem to get the LinQ statements right. This is what I have so far:
return (MainBusinessObjectCollection)
listOfMainBusinessObject.Where(x =>
(x as MainBusinessObject).CanBePartitioned == true);
EDIT
I need to filter out the ListOfSubobject from the main business object
Depending if you want ANY sub-object to have that property or ALL sub-object to have that property:
var filteredList = listOfMainBusinessObject
.Where(x => x.ListOfSubobject.Any(s=>s.PropertyX));
or
var filteredList = listOfMainBusinessObject
.Where(x => x.ListOfSubobject.All(s=>s.PropertyX));
Also you have some casts that seem to be either invalid or unnecessary. To convert to a MainBusinessObjectCollection (assuming it is a collection of MainBusinessObjects), you're likely going to have to initialize it from the IEnumerable that Where returns:
var newList = new MainBusinessObjectCollection(filteredList);
If you want all Subobjects with Subobject.PropertyX == true:
listOfMainBusinessObject.SelectMany(x => x.ListOfSubobject)
.Where(x => x.PropertyX == true);

how to select an item from generic list by linq

I have a LINQ query which contains a method GetInstanceForDatabase()
principlesList.Select(p => p.GetInstanceForDatabase()).ToList()
where
List<PrincipleInstance>() principlesList = ...
// (contains list of principle like "Manual Trades", "OPM", "Flora")
GetInstanceForDatabase() is a method which takes all other info about a principle (like manual trades).
My problem is that I want to sort out only principle like only "Manual Trades".
I want to put a where clause. I tried but it is fails.
To get a single item use:
query.First(x => x.property == "Manual Trades");
// or
query.FirstOrDefault(x => x.property == "Manual Trades");
var list = p.GetInstanceForDatabase().where(x => x.propertyName == "Manual Trades").ToList();
I'm sure you're GetInstanceForDatabase needs to return your collection that you then filter for the 'Manual Trades' but I can't really tell how you get your list of PrincipalInstances from the question.
This is the correct syntax of using Where in LINQ
principlesList.Select(p => p.GetInstanceForDatabase()).Where(p => p.SomeProperty == "SomeValue").ToList();

Categories