C# 实体框架-其中带有Any()和All()的子句使用

C# 实体框架-其中带有Any()和All()的子句使用,c#,entity-framework,linq,lambda,C#,Entity Framework,Linq,Lambda,有一个结构: 客户端有多个案例,案例有多个日志 public class Client { public int Id { get; set; } public IEnumerable<Case> Cases { get; set; } } public class Case { public int CaseId { get; set; } public IEnumerable

有一个结构:

客户端有多个案例,案例有多个日志

    public class Client
    {
        public int Id { get; set; }
        public IEnumerable<Case> Cases { get; set; }
    }

    public class Case
    {
        public int CaseId { get; set; }
        public IEnumerable<Log> Histories { get; set; }
    }

    public class Log
    {
        public int Id { get; set; }
        public string Code { get; set; }
    }
公共类客户端
{
公共int Id{get;set;}
公共IEnumerable事例{get;set;}
}
公开课案例
{
public int CaseId{get;set;}
公共IEnumerable历史记录{get;set;}
}
公共类日志
{
公共int Id{get;set;}
公共字符串代码{get;set;}
}
我想从每个案例代码属性中检索所有日志都设置为“错误”的客户机或根本没有日志的客户机。此外,为了发布代码的目的,我有两个简单的条件,您可以在下面的simplified中看到(当然EF使用IQueryable而不是ICollection)

首先,我尝试创建名为AllOrEmpty的扩展方法,该方法工作良好,但在LINQtoEntities中不起作用(它不接受扩展方法)

公共静态类扩展
{
公共静态bool AllOrEmpty(此IEnumerable源,Func谓词)
{
返回source.All(谓词)| |!source.Any();
}
}
var sampleIds=new List(){1,2,3};
实体db=新实体();
db.客户
.Where(client=>client.Cases
.Where(cas=>sampleid.Contains(cas.CaseId))
.SelectMany(cas=>cas.History
.Where(log=>log.Id<10)
)
.AllOrEmpty(log=>log.Code==“错误”)client.Id);
其次,我尝试在where子句中创建带有return语句的lambda表达式,它工作正常,但不适用于IQueryable和returns错误:带有语句体的lambda表达式无法转换为表达式树

         db.Clients
            .Where(client => 
            {
                var logs = client.Cases
                    .Where(cas => sampleIds.Contains(cas.CaseId))
                    .SelectMany(cas => cas.Histories
                        .Where(log => log.Id < 10)
                        );

                return !logs.Any() || logs.All(log => log.Code == "WRONG");
             })
             .Select(client => client.Id);
db.Clients
.其中(客户端=>
{
var logs=client.Cases
.Where(cas=>sampleid.Contains(cas.CaseId))
.SelectMany(cas=>cas.History
.Where(log=>log.Id<10)
);
return!logs.Any()| | logs.All(log=>log.Code==“错误”);
})
.Select(client=>client.Id);

我不知道如何创建这样的查询,保持它的简单,避免一些脏代码。有什么想法吗?

这个linq查询应该做您想做的事情:

var IDs = from client in db.Clients
                from cas in client.Cases.Where(c => sampleIds.Contains(c.CaseId))
                let logs = cas.Histories.Where(l => l.Id < 10)
                where !logs.Any() || logs.All(l => l.Code == "WRONG")
                select client.Id;
var id=来自数据库中的客户端。客户端
来自client.Cases.Where(c=>sampleid.Contains(c.CaseId))中的cas
让logs=cas.Histories.Where(l=>l.Id<10)
哪里logs.Any()| | logs.All(l=>l.Code==“错误”)
选择client.Id;

如果您希望客户端的所有历史记录项的代码都设置为“错误”

如果要获取没有任何案例历史记录项的所有客户端

var clientsWithNoLogs = clist.Where(s => s.Cases.Any(c => !c.Histories.Any()));
如果你想同时满足这两个条件

var combined = clist.Where(s => s.Cases.Any(c => c.Histories.All(h => h.Code == "WRONG")
                                                                  || !c.Histories.Any()) );

您可以利用LINQ查询语法,它与
let
子句和透明标识符一起大大简化了此类查询

例如,您的查询可以如下所示:

var query =
    from client in db.Clients
    let logs = from cas in client.Cases
               where sampleIds.Contains(cas.CaseId)
               from log in cas.Histories
               where log.Id < 10
               select log
    where !logs.Any() || logs.All(log => log.Code == "WRONG")
    select client.Id;

你@Shyju和Josh Knack可能都不明白我的意思。我不想一个接一个地选择符合条件的案例,但我对待每个案例中的所有日志就像在一个包中一样,只有当每个案例中的所有日志都符合条件时(所有日志都有代码“错误”或此包为空),我才想选择这样的用户。尝试最后一个LINQ语句(组合)。这很有趣,但你是对的,all()方法为空集合返回true,因此它完全解决了我的问题。谢谢
var combined = clist.Where(s => s.Cases.Any(c => c.Histories.All(h => h.Code == "WRONG")
                                                                  || !c.Histories.Any()) );
var query =
    from client in db.Clients
    let logs = from cas in client.Cases
               where sampleIds.Contains(cas.CaseId)
               from log in cas.Histories
               where log.Id < 10
               select log
    where !logs.Any() || logs.All(log => log.Code == "WRONG")
    select client.Id;
class Foo
{
    public int Bar { get; set; }
}

var source = new List<Foo>();
bool test1 = !source.Any() || source.All(e => e.Bar == 0);
bool test2 = source.All(e => e.Bar == 0);
bool test3 = !source.Any(e => e.Bar == 0);
Debug.Assert(test1 == test2 && test2 == test3);