如何在Linq语句中确定哪个WHERE子句是正确的

时间:2012-05-01 20:52:42

标签: c# linq

LINQ中有没有办法告诉哪个WHERE子句命中?我有一个名为Company的对象,它可以反过来拥有多个BillTo对象,每个BillTo对象可以有多个Generator对象。

Company
|
+-- BillTo1 - named First
|    |
|    |-- Generator1 - named Alpha
|    |
|    +-- Generator2 - named Beta
|
+-- BillTo2 - named Second
     |
     +-- Generator3 - name Gamma

这是linq语句(为其他where语句删除了额外的东西):

bool HaveCompany = !string.IsNullOrWhiteSpace(Company);
var AllData = (from co in db.Companies
             join bt in db.Billtoes on co.ID equals bt.CompanyID into bts
             from b in bts.DefaultIfEmpty()
             join gn in db.Generators on b.ID equals gn.BillToID into gns
             from g in gns.DefaultIfEmpty()
             where co.Active == true
             && (
                co.Name.Contains(HaveCompany ? Company : co.Name) ||
                b.Name.Contains(HaveCompany ? Company : b.Name) ||
                g.Name.Contains(HaveCompany ? Company : g.Name)
             )
             select new {
                 CompanyID = co.ID,
                 BillTo = b,
                 Generator = g,
                 Name = co.Name,
             }).ToList();

问题是,它找到了正确的一切。如果我在BillTo上找到“Name”匹配,我不需要做“Generator = g”,反之亦然,如果我在Generator上找到它我不需要做“BillTo = b”。< / p>

因此,如果有办法知道哪个WHERE子句被击中,那么我会在结果中添加适当的b或g。我知道我可以通过AFTER得到结果重新检查并重新检查我实际发送的7个字段中的每一个作为WHERE子句,但这似乎是太多额外的代码。也许我的LINQ的调整是有序的?是否有我可以通过反射或某些东西提取的值来找出被击中的内容?

2 个答案:

答案 0 :(得分:3)

你必须决定 - 你想要三个选择分支(实际上它应该是我认为的两个嵌套?:语句)?或者您想选择一个拥有所有潜在成员的对象?就个人而言,为避免在select语句中使用具体类型,或使用dynamic,我只想扩展您的匿名类型:

您可以使用let进行一次Contains检查,然后在where子句和匿名类型成员的分配中使用这些检查:

 /* .... */
 let coContains = co.Name.Contains(HaveCompany ? Company : co.Name)
 let bContains = b.Name.Contains(HaveCompany ? Company : b.Name)
 let gContains = g.Name.Contains(HaveCompany ? Company : g.Name)
 where co.Active == true
 && ( coContains || bContains || gContains )
 select new {
   /* sticking the booleans on there as well - might not want to do that */
   CoContains = coContains,
   BContains = bContains,
   GContains = gContains,
   /* other properties as per your code example */
   CompanyID = co.ID,
   BillTo = !gContains && bContains ? b : (BillTo)null,
   Generator = gContains && !bContains ? g : (Generator)null,
   Name = co.Name
 }).ToList();

所以你仍然会返回相同的数据(因为评论说你可能实际上并不想要那些额外的数据 布尔,我只是把它们放在那里,因为它可能会简化你之后运行的任何控制流逻辑)但是你只是在布尔符合(我认为是)你的标准的情况下分配它们。 BillToGenerator属性将为null(我在此处假设类型名称),如果它们不应被读取。

答案 1 :(得分:0)

如果您确定符合哪个条件,则可能是对数据进行分区而不是对其进行过滤。分区是GroupBy的工作。然后你可以根据键进行条件组投影。

.GroupBy(x =>  x.co.Name.Contains(HaveCompany ? Company : co.Name)  ? 1 :
  x.b.Name.Contains(HaveCompany ? Company : b.Name) ? 2 :
  x.gen.Name.Contains(HaveCompany ? Company : gen.Name) ? 3 :
  0
)
.SelectMany(g =>
g.Key == 1 ? g.Select(x => new {
  CompanyID = x.co.ID,
  BillTo = x.b,
  Generator = x.gen,
  Name = co.Name
} :
g.Key == 2 ? g.Select(x => new {
  CompanyID = co.ID,
  BillTo = b,
  Generator = (Generator) null,
  Name = co.Name
} :
g.Key == 3 ? g.Select(x => new {
  CompanyID = co.ID,
  BillTo = (BillTo) null,
  Generator = gen,
  Name = co.Name
} :
g.Where(x => false)
)