C# 如何对对象集合和每个对象内部的集合运行LINQ查询
我有一个对象集合,其中每个对象也有一个集合。像这样:C# 如何对对象集合和每个对象内部的集合运行LINQ查询,c#,linq,C#,Linq,我有一个对象集合,其中每个对象也有一个集合。像这样: public class Product { public int Id { get; set; } public List<Tuple<string, double>> Sales { get; set; } } 是否可以在一行中完成此操作?这里的关键是,在实际定义完整个查询之前,不要通过使用SingleOrDefault来具体化查询。改为使用Where,然后在最后使用SingleOrDefault
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}
是否可以在一行中完成此操作?这里的关键是,在实际定义完整个查询之前,不要通过使用
SingleOrDefault来具体化查询。改为使用Where
,然后在最后使用SingleOrDefault
var query = (from product in Model.Products
where product.Id == someProductId
let sale = product.Sales.SingleOrDefault(i => i.Item1 == sale.Id)
where sale != null
select new
{
product,
saleAmount = sale.Item2,
})
.SingleOrDefault();
有可能在一行中完成吗
我相信,通过将支票合并到第二个销售数组(如
var products = Model.Products.Where(p => p.Id == product.Id
&&
p.Sales.Any(i => i.Item1 == sale.Id) );
var saleAmount = (products != null && products.Any())
? products.First().Sales.First().Item2.ToString()
: string.Empty;
使用默认值
此解决方案使用默认的人造产品的帮助,该人造产品是预先创建的产品
,在找不到时使用。在扩展方法中使用它,该方法确定是否已返回空投影,在这种情况下,它将返回faux实例。之后,我们可以安全地提取一个值,该值将是string.empty
,并将其分配给最后一个字符串productSale
下面我使用硬编码的1.5
作为销售价格,以便于阅读示例
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product()
{ Id = -1,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>(string.Empty, 0.0) }};
var productSale =
Products.Where(p => p.Id == product.Id && p.Sales.Any (s => s.Item2 == 1.5 ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First()
.Item1;
您将面临NullReferenceExceptions
,我怀疑您的代码是否会更清晰。我希望您意识到,SingleOrDefault
如果列表中有多个项具有生成id,将引发异常。您确定不想在此处使用FirstOrDefault
。@JimMischel,鉴于他正在处理主键,它们不应该被复制。如果它们真的存在,那将是数据中的一个bug,应该抛出。@Servy如果它们是主键,那么(此处nickpicking)FirstOrDefault
在性能方面更快(因为不需要检查是否有重复项来抛出异常)。@Servy:我没有看到任何说明他正在使用主键的内容。但是如果是这样的话,那当然,这是一个非常有趣的方法。这是否可能使用lambda表达式?@ShaiCohen这是使用lambda表达式。@ShaiCohen Alambda
表达式是一个条件表达式,它通过“goes to”=>
语法推断特定的检查语法。您正在思考的lambda
是linq
表达式,它可以是Servy所做的查询语法(从技术上讲,他是一个混合体),也可以是我在示例中使用的方法语法。我们都使用lambda
s来表示检查操作,例如i=>i.Item1==sale.Id
。有关更多信息,请参阅。@OmegaMan:谢谢您的澄清。就在你认为你知道一些事情的时候@我们都去过那里。很乐意帮忙。
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product()
{ Id = -1,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>(string.Empty, 0.0) }};
var productSale =
Products.Where(p => p.Id == product.Id && p.Sales.Any (s => s.Item2 == 1.5 ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First()
.Item1;
void Main()
{
var targetSalePrice = 1.5;
var targetProductId = 2;
var Products = new List<Product>() { new Product()
{ Id = 2,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("actual", 1.6) } }
};
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product() { Id = -1, Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("faux string.Empty", 0.0) }};
var productSale =
Products.Where(p => p.Id == targetProductId
&& p.Sales.Any (s => s.Item2 == targetSalePrice ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First ()
.Item1;
productSale.Dump(); // outputs the string "faux string.Empty" from the faux default.
}
// Define other methods and classes here
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}