Linq inside of Linq causing sequence to return no results
Here are my classes:
public class XDetail
{
public string Name { get; set; }
public int ID { get; set; }
}
public class X
{
public int XID { get; set; }
public int ID { get; set; }
}
The ID is shared between them to link X and XDetail (one to many relationship). I read in a file using the following linq query and shape an anonymous type:
var results = from line in File.ReadAllLines(file)
select new
{
XID = int.Parse(line.Substring(0, 8).TrimStart('0')),
Name = line.Substring(8, 255).Trim()
};
This data is used to check against existing X/XDetail to make appropriate changes or add new records. XList is a List and XDetailList is a List.
From there I attempt a fancy linq query to match up the appropriate items:
var changedData = from x in XList
join xDetail in XDetailList on x.ID equals xDetail.ID
where
开发者_如何学运维 (!results.Any(p => p.XID.Equals(x.XID))
|| !results.Any(p => p.Name.Equals(xDetail.Name)))
select new
{
XValue = x,
XDetailValue = xDetail,
Result = (from result in results
where result.Name.Equals(xDetail.Name)
select result).Single() // This line is my bane
};
So I can get the results I'm looking for shaped into that new anonymous type, but when I tried adding in that Result = ... inner linq query my whole set turns to: Sequence contains no elements. If I remove it I get the result set I was intending. X/XDetail are really typed DataRows that I need to use in processing farther down using the matched Result, but without that Result I will need to do a later linq query to find the match. I was hoping to do it in a psuedo-cool one step way.
I have tried changing Result to have no where clause and I can get a result, but the result I'm hoping to match on. Is there a better way to write this or a way to get the result set working again?
One problem is that results is an IEnumerable
- so you are re-querying it every time which causes the File.ReadAllLines(file)
to execute - effectively you are calling File.ReadAllLines(file)
N
times which does not sound healthy.
Instead you want to bring this enumeration into memory once - force eager execution with ToList()
:
var results = (from line in File.ReadAllLines(file)
select new
{
XID = int.Parse(line.Substring(0, 8).TrimStart('0')),
Name = line.Substring(8, 255).Trim()
}).ToList();
Try changing your .Single to .SingleOrDefault. It is possible you are finding a row where the given x.Detail.Name isn't in your results set.
(Moving from a comment to answer so that it can be marked appropriately)
精彩评论