2017-07-10 66 views
4

假设我们有两个表父“DocumentCodes”和Child“Documents”。 DocumentCodes表具有列DID,DocumentName,PrintOrder和AscOrDesc 文档表具有列ID,DID和EffectiveDate.We通过连接这两个表获取数据表。基于行值的LINQ OrderBy

我们需要根据以下规则对此数据表进行排序。

  1. 按“PrintOrder”列排序。
  2. 如果两行或更多行具有相似的“DocumentNames”值,则根据“AscOrDesc”值按“EffeciveDate”升序或降序排序。 “AscOrDesc”列仅接受'A'或'D'。如果值是'A',我们需要对“EffectiveDate”进行升序排序,如果值是'D',则需要对“EffectiveDate”进行降序排序。

例如,

DocumentCodes

DID  DocumentName  PrintOrder  AscOrDesc 
1  Test1    1    D 
2  Test2    2    A 
3  Test3    3    D 

文献

ID  DID  EffectiveDate  
1   2   7/9/2017 
2   1   5/5/2017 
3   2   7/8/2017 
4   3   4/9/2017 

以上两个表之后加入。我们有DataTable。

ID  DocumentName EffectiveDate PrintOrder AscOrDesc 
1   Test2  7/9/2017  2   A 
2   Test1  5/5/2017  1   D 
3   Test2  7/8/2017  2   A 
4   Test3  4/9/2017  3   D 

现在使用上述规则对此DataTable进行排序后。 DataTable应该看起来像这样。

ID  DocumentName EffectiveDate PrintOrder AscOrDesc 
1   Test1   5/5/2017  1   D 
2   Test2   7/8/2017  2   A 
3   Test2   7/9/2017  2   A 
4   Test3   4/9/2017  3   D 

注意:EffectiveDate格式为MM/DD/YYYY格式。

我试着用下面的代码,但它不工作。

var records2 = from q in datatable.AsEnumerable() 
       let sortorder= q.Field<string>("AscOrDesc") == "A" ? 
       "q.Field<DateTime>(\"EffectiveDate\") ascending": 
       "q.Field<DateTime>(\"EffectiveDate\") descending" 
       orderby q.Field<int>("PrintOrder"),sortorder 
       select q; 

我在做什么错在上面的代码?

+3

它没有多大意义了中行的排序中指定*在行中* - 如果一行的AscOrDesc设置为'A'而另一行的AscOrDesc设置为'D'会怎么样?这两行如何比较? –

+0

从来没有使用过LINQ to SQL,但这样做甚至可以工作你在做什么?谈论你正在构建的字符串,LINQ to SQL解析字符串并且做到了魔法?我有点相信它只是通过这个字符串来完成命令,所以完全是虚拟的......但也许?!? –

+0

Hi @JonSkeet,对于每个文档名将具有特定的“AscOrDesc”值。因此,如果相同的文档名称出现两次,“AscOrDesc”将相同。 –

回答

3

的情况是相当难看,因为它有两个结果排在理论上可以比较相同的PrintOrder但不同的值为AscOrDesc。它只是阻止这种情况的数据来源。

我确实有一个可怕的黑客,我认为应该工作,但我真的不以此为荣。基本上,想象一下日期是一个数字......按降序排序相当于排除“日期编号”的排序。对于DateTime,我们可以只取Ticks值,导致:

var records2 = from q in datatable.AsEnumerable() 
       let ticks = q.Field<DateTime>("EffectiveDate").Ticks * 
        (q.Field<string>("AscOrDesc") == "A" ? 1 : -1) 
       orderby q.Field<int>("PrintOrder"), ticks 
       select q; 

丑陋不堪,心里很不舒服,但它应该工作...

+0

好主意,肯定比我的方法更短。 :) –

+1

它的工作正常。非常感谢@jonskeet –

1

看起来像一个错字,希望这个作品

  var records2 = from q in datatable.AsEnumerable() 
      orderby q.Field<int>("PrintOrder") 
      orderby q.Field<string>("AscOrDesc") == "A" ? q.Field<DateTime>("EffectiveDate") : q.Field<DateTime>("EffectiveDate") descending 
      select q; 

通常我的语句中是这样

var result = from q in datatable.AsEnumerable() 
       orderby q.PrintOrder 
       orderby q.AscOrDesc== "A" ? q.EffectiveDate: q.EffectiveDate descending 
       select q; 
+0

字段名称是不同的@derloopkat。 – mjwills

+0

嗨@Lakshmikanthan,我纠正了代码,但仍然无法正常工作。它将按“PrintOrder”进行排序,但不会按生效日期排序 –

+2

问题是'AscOrDesc'字段应指示如何使用EffectiveDate'字段 - 当前您正在使用PrintOrder排序,然后通过*串*。这是行不通的。 –

2

很丑陋,但不可能想出更好的东西适合您的需求。 也许你有运气,@JonSkeet会再次来。 :)

(使用LINQ到对象,你需要重写它适合你的LINQ to SQL)

static void Main(string[] args) 
{ 
    var lstFoos = new List<Foo>() { 
     new Foo() { Id = 1, DocumentName = "Test2", EffectiveDate = new DateTime(2017, 7, 9), PrintOrder = 2, AscOrDesc = "A" }, 
     new Foo() { Id = 2, DocumentName = "Test1", EffectiveDate = new DateTime(2017, 5, 5), PrintOrder = 1, AscOrDesc = "D" }, 
     new Foo() { Id = 3, DocumentName = "Test2", EffectiveDate = new DateTime(2017, 7, 8), PrintOrder = 2, AscOrDesc = "A" }, 
     new Foo() { Id = 4, DocumentName = "Test3", EffectiveDate = new DateTime(2017, 4, 9), PrintOrder = 3, AscOrDesc = "D" }, 
     }; 

    var result = lstFoos.OrderBy(x => x.PrintOrder).GroupBy(x => x.DocumentName).SelectMany(x => 
    { 
     if (x.Count() > 1) 
     { 
      var ascOrDesc = x.First().AscOrDesc; 
      return new List<Foo>(ascOrDesc == "A" ? x.OrderBy(y => y.EffectiveDate) : x.OrderByDescending(y => y.EffectiveDate)); 
     } 

     return new List<Foo>() {x.First()}; 
    }); 

    foreach (var foo in result) 
     Console.WriteLine(foo.ToString()); 

    Console.ReadLine(); 
} 

public class Foo 
{ 
    public int Id { get; set; } 
    public string DocumentName { get; set; } 
    public DateTime EffectiveDate { get; set; } 
    public int PrintOrder { get; set; } 
    public string AscOrDesc { get; set; } 

    public override string ToString() 
    { 
     return $"Id: {Id} | DocumentName: {DocumentName} | EffectiveDate: {EffectiveDate} | PrintOrder: {PrintOrder} | AscOrDesc: {AscOrDesc}"; 
    } 
} 
+0

谢谢你的帮助。 –