LINQ OrderBy基于行值

时间:2017-07-10 08:46:35

标签: c# linq

假设我们有两个表Parent" DocumentCodes"和孩子"文件"。 DocumentCodes表包含列DID,DocumentName,PrintOrder和AscOrDesc  Documents表有列ID,DID和EffectiveDate。我们通过连接这两个表来获取数据表。

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

  1. 排序方式" PrintOrder"列升序。
  2. 如果两行或更多行具有相似的" DocumentNames"价值然后排序" EffeciveDate"根据" AscOrDesc"升序或降序值。 " AscOrDesc"专栏只接受' A'或者' D'。如果价值是' A'我们需要排序" EffectiveDate"提升,如果价值是“D' D'我们需要排序" EffectiveDate"降。
  3. 例如,

    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 个答案:

答案 0 :(得分:3)

这种情况相当丑陋,因为理论上可以比较两个具有相同PrintOrder但不同AscOrDesc值的结果行。它只是防止这种情况的数据来源。

我确实有一个可怕的黑客,我认为应该有效,但我真的不为此感到骄傲。基本上,假设日期是一个数字......按降序排序相当于通过否定&#34;日期编号&#34;来排序。对于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;

丑陋,但它应该有用......

答案 1 :(得分:2)

非常难看,但无法找到更符合您需求的东西。 也许你有运气,而且@JonSkeet会再来一次。 :)

(使用LINQ To Object,你需要重写它适合你的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}";
    }
}

答案 2 :(得分:0)

看起来像一个TYPO,希望这个工作

           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;