C# Lambda表达式LINQ等价于同一表/变量上的SQL Exists查询
我正在尝试使用lambda表达式格式在LINQ中复制以下SQL查询(以使其与迄今为止开发的代码保持一致): 在查看了其他问题(这是我能找到的最接近的问题,但没有显示如何“或”条件)之后,我认为下面的内容会起作用,但它只会导致堆栈溢出(严重)异常和一条关于未加载pdb文件的消息,我认为这有点让人费解C# Lambda表达式LINQ等价于同一表/变量上的SQL Exists查询,c#,sql,entity-framework,linq,lambda,C#,Sql,Entity Framework,Linq,Lambda,我正在尝试使用lambda表达式格式在LINQ中复制以下SQL查询(以使其与迄今为止开发的代码保持一致): 在查看了其他问题(这是我能找到的最接近的问题,但没有显示如何“或”条件)之后,我认为下面的内容会起作用,但它只会导致堆栈溢出(严重)异常和一条关于未加载pdb文件的消息,我认为这有点让人费解 products = products .Where(p => !p.DateObsolete.HasValue || p.DateObsolete
products = products
.Where(p => !p.DateObsolete.HasValue
|| p.DateObsolete > DateTime.Now
|| products.Any(p1 => p1.Ref01 == p.Ref01
&& p1.Ref02 == p.Ref02
&& p1.Ref03 == p.Ref03
&& p1.Version == p.Version + 1
&& p1.DateApproved == null));
产品是可计量的变量
在此上下文中,产品定义为以下数据集:
public class Product
{
public int ProductID { get; set; }
[MaxLength(200)]
public string Name { get; set; }
[MaxLength(3)]
public string Ref01 { get; set; }
[MaxLength(3)]
public string Ref02 { get; set; }
public int Ref03 { get; set; }
public int Version { get; set; }
public DateTime? DateReceivedByGraphics { get; set; }
public DateTime? DateApproved { get; set; }
public DateTime? DateObsolete { get; set; }
public bool Deleted { get; set; }
public bool Discontinued { get; set; }
}
正如您所知,我是LINQ的新手(并在上面发布问题),因此我们将非常感谢您的帮助。您可以通过加入来完成此任务
DateTime date = DateTime.Today; // or .Now
var products = context.Products.Join(context.Products,
p1 => new { p1.Ref01, p1.Ref02, p1.Ref03 },
p2 => new { p2.Ref01, p2.Ref02, p2.Ref03 },
(p1, p2) => new { Product = p1, p1.Version, JoinedVersion = p2.Version, JoinedDateApproved = p2.DateApproved } )
.Where(x=> x.Product.DateObsolete > date && x.JoinedVersion == x.Version+1 && !x.JoinedDateApproved.HasValue)
.Select(x=>x.Product)
.ToList();
这将在参考1-3中将产品连接到自身,但随后选择“左侧”项目及其版本、“右侧”版本和批准日期。Where条件隔离了“右侧”版本大于左侧版本且未批准日期的情况。结果将是“左”产品,其对应产品符合这些标准
更新:
如果您已经将产品过滤到一组已知的适用产品,那么这将对对象起作用。例如:
// given products is an IQueryable representing the filtered products...
DateTime date = DateTime.Today; // or .Now
var productList = products.ToList(); // Materialize the EF Queryable into list of entities.
productList = productList.Join(productList,
p1 => new { p1.Ref01, p1.Ref02, p1.Ref03 },
p2 => new { p2.Ref01, p2.Ref02, p2.Ref03 },
(p1, p2) => new { Product = p1, p1.Version, JoinedVersion = p2.Version, JoinedDateApproved = p2.DateApproved } )
.Where(x=> x.Product.DateObsolete > date && x.JoinedVersion == x.Version+1 && !x.JoinedDateApproved.HasValue)
.Select(x=>x.Product)
.ToList();
如果您的目标是尝试将其作为一个IQueryable作用域保留到EF,那么我怀疑如果可能的话,它可能不值得这么复杂/时间。最坏的情况是,如果您确实希望保留IQueryable,请使用上面的命令将产品ID选择到列表中,然后将该列表作为IQueryable的筛选器应用
var productList = products.ToList(); // Materialize the EF Queryable into list of entities.
// Fetch a list of applicable product IDs.
var productIds = productList.Join(productList,
p1 => new { p1.Ref01, p1.Ref02, p1.Ref03 },
p2 => new { p2.Ref01, p2.Ref02, p2.Ref03 },
(p1, p2) => new { ProductId = p1.ProductId, DateObsolete = p1.DateObsolete, p1.Version, JoinedVersion = p2.Version, JoinedDateApproved = p2.DateApproved } )
.Where(x=> x.DateObsolete > date && x.JoinedVersion == x.Version+1 && !x.JoinedDateApproved.HasValue)
.Select(x=>x.ProductId)
.ToList();
// Filter the original IQueryable.
products = products.Where(x => productIds.Contains(x.ProductId));
正如Aleks Andreev和Ivan Stoev所建议的,将表达式分配给一个新变量可以解决问题。我不确定为什么第一次这样做不起作用,但我猜,在完成查询后,我尝试将结果重新分配回原始变量,以便不必在更改后的所有代码中更改变量名。我们可以看到产品实体吗?我指的是此查询中隐含的所有属性。缺少信息:EF版本+类型和
产品的原产地。我猜数据库是Sql Server。请尝试将表达式分配给新变量,如var newProducts=products。其中(…
最有可能与products
变量闭包相关。尝试var query=products.Where(…)
而不是将结果查询分配给products
变量。对不起,@AleksAndreev和Ivan,我又尝试了一次重新分配(我试图跟踪故障的确切点)它起作用了:我不确定我做了什么不同。谢谢,但我不确定我是否可以这样做。更多背景:此查询是在原始产品集合上运行的几个查询之一,用于识别满足用户指定搜索条件的产品集合,因此我需要在products变量rat中对集合运行它她比原始的数据集要好。我尝试了这个,但似乎不能用变量开始连接。如果这只是暴露了我对LINQ的理解不足,那就很抱歉了!
var productList = products.ToList(); // Materialize the EF Queryable into list of entities.
// Fetch a list of applicable product IDs.
var productIds = productList.Join(productList,
p1 => new { p1.Ref01, p1.Ref02, p1.Ref03 },
p2 => new { p2.Ref01, p2.Ref02, p2.Ref03 },
(p1, p2) => new { ProductId = p1.ProductId, DateObsolete = p1.DateObsolete, p1.Version, JoinedVersion = p2.Version, JoinedDateApproved = p2.DateApproved } )
.Where(x=> x.DateObsolete > date && x.JoinedVersion == x.Version+1 && !x.JoinedDateApproved.HasValue)
.Select(x=>x.ProductId)
.ToList();
// Filter the original IQueryable.
products = products.Where(x => productIds.Contains(x.ProductId));