0

SQLから戻ってくるグループ化されたデータを処理しようとしています。私が書いている方法は、「ケースステータスの概要」画面のデータを提供することです。ネストされたXMLドキュメントを生成する必要があります。

今では簡単な方法で実行できますが、linqの "group by"ステートメントを使用して、既にネストされているデータを投影できるかどうかを調べようとしています。(簡単な方法は、データベースから表形式でデータをプルバックし、それをforループして出力用のXmlドキュメントを形成することです)

データ階層は次のとおりです。

すべてのケースにはDebtTypeがあり、すべてのDebtTypeにはクライアントがあります。

データを取得するSQLは次のとおりです。

SELECT   ClientNames.ClientID                                             ,
         ClientNames.ClientCode                                           ,
         ClientNames.ClientName                                           ,
         DebtTypes.DebtTypeID                                             ,
         DebtTypes.DebtTypeShortDesc                                      ,
         DebtTypes.DebtTypeLongDesc                                       ,
         Cases.CurrentStateCode                                           ,
         SUM(1 - CAST(Cases.CaseClosed AS INT))  AS OpenCaseCount         ,
         SUM(CAST(Cases.CaseClosed AS     INT))  AS ClosedCaseCount       ,
         SUM(CAST(Cases.CaseOnHold AS     INT))  AS OnHoldCaseCount       ,
         SUM(CAST(Cases.CaseReferred AS   INT))  AS ReferredCaseCount     ,
         COUNT(Cases.CaseID)                     AS TotalCaseCount        ,
         SUM(Cases.CaseTotalPaid)                AS TotalAmountPaid       ,
         SUM(Cases.CaseCurrentOutstandingAmount) AS TotalAmountOutstanding,
         SUM(Cases.CaseTotalDebtWrittenOff)      AS TotalAmountWrittenOff ,
         SUM(Cases.CaseTotalDebtCancelled)       AS TotalAmountCancelled
FROM     ClientNames
         INNER JOIN ClientDebtTypes
         ON       ClientNames.ClientID = ClientDebtTypes.ClientID
         INNER JOIN DebtTypes
         ON       ClientDebtTypes.DebtTypeID = DebtTypes.DebtTypeID
         INNER JOIN Cases
         ON       ClientDebtTypes.ClientDebtTypeID = Cases.CaseClientDebtTypeID
GROUP BY ClientNames.ClientID       ,
         ClientNames.ClientCode     ,
         ClientNames.ClientName     ,
         DebtTypes.DebtTypeID       ,
         DebtTypes.DebtTypeShortDesc,
         DebtTypes.DebtTypeLongDesc ,
         Cases.CurrentStateCode
ORDER BY ClientNames.ClientID,
         DebtTypes.DebtTypeID,
         CurrentStateCode

Linqerを使用して、次のように変換します。

from clientnames in db.ClientNames
join clientdebttypes in db.ClientDebtTypes on clientnames.ClientID equals clientdebttypes.ClientID
join debttypes in db.DebtTypes on clientdebttypes.DebtTypeID equals debttypes.DebtTypeID
join cases in db.Cases on new { ClientDebtTypeID = clientdebttypes.ClientDebtTypeID } equals new { ClientDebtTypeID = cases.CaseClientDebtTypeID }
group new {clientnames, debttypes, cases} by new {
  clientnames.ClientID,
  clientnames.ClientCode,
  clientnames.ClientName1,
  debttypes.DebtTypeID,
  debttypes.DebtTypeShortDesc,
  debttypes.DebtTypeLongDesc,
  cases.CurrentStateCode
} into g
orderby
  g.Key.ClientID,
  g.Key.DebtTypeID,
  g.Key.CurrentStateCode
select new {
  ClientID = (System.Int32?)g.Key.ClientID,
  g.Key.ClientCode,
  g.Key.ClientName1,
  DebtTypeID = (System.Int32?)g.Key.DebtTypeID,
  g.Key.DebtTypeShortDesc,
  g.Key.DebtTypeLongDesc,
  g.Key.CurrentStateCode,
  OpenCaseCount = (System.Int64?)g.Sum(p => 1 - Convert.ToInt32(p.cases.CaseClosed)),
  ClosedCaseCount = (Int32?)g.Sum(p => Convert.ToInt32(p.cases.CaseClosed)),
  OnHoldCaseCount = (Int32?)g.Sum(p => Convert.ToInt32(p.cases.CaseOnHold)),
  ReferredCaseCount = (Int32?)g.Sum(p => Convert.ToInt32(p.cases.CaseReferred)),
  TotalCaseCount = (Int64?)g.Count(p => p.cases.CaseID != null),
  TotalAmountPaid = (System.Decimal?)g.Sum(p => p.cases.CaseTotalPaid),
  TotalAmountOutstanding = (System.Decimal?)g.Sum(p => p.cases.CaseCurrentOutstandingAmount),
  TotalAmountWrittenOff = (System.Decimal?)g.Sum(p => p.cases.CaseTotalDebtWrittenOff),
  TotalAmountCancelled = (System.Decimal?)g.Sum(p => p.cases.CaseTotalDebtCancelled)
}

さて、私が言ったように、そこで停止して、Xmlデータを作成するためのforループを正しくすることができます。IGrouping<ClientName,IGrouping<DebtType,SummaryClass>>しかし、ネストされたグループ( )を作成してから、データをネストされた形式で投影しようとしています。

現在、LinqToXsdを使用してout Xmlドキュメントの強力な型ラッパーを作成していますが、基本的にこれは、out出力型が次のことを意味します。

private class ClientSummary
{
    public string ClientName { get; set; }
    public IList<DebtTypeSummary> DebtTypes { get; set; }
}

private class DebtTypeSummary
{
    public string DebtType { get; set; }
    public IList<StateCodeSummary> StateCodes { get; set; }
}

private class StateCodeSummary
{
    public string StateCode { get; set; }
    public int TotalCount { get; set; }
    public decimal TotalAmountPaid { get; set; }
    //etc
    //etc
    //etc
}

今、私は次のLinqを書くところまで来ました:

var grouping = from cases in db.Cases
              join clientdebttypes in db.ClientDebtTypes on cases.CaseClientDebtTypeID equals clientdebttypes.ClientID
              join debttypes in db.DebtTypes on clientdebttypes.DebtTypeID equals debttypes.DebtTypeID
              group cases by new ClientDebtTypePair() { ClientDebtType = clientdebttypes, DebtType = debttypes } into casesByClientDebtTypes
              join clientnames in db.ClientNames on casesByClientDebtTypes.Key.ClientDebtType.ClientName equals clientnames
              group casesByClientDebtTypes by clientnames;

var projected = from casesByClientDebtTypes in grouping
            let client = casesByClientDebtTypes.Key
            select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
              {
                  Client = new Client()
                  {
                      ClientID = client.ClientID,
                      DisplayName = client.ClientName1,
                  },
                  DebtTypes = from cases in casesByClientDebtTypes
                              let debttype = cases.Key.DebtType
                              select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType.DebtTypesLocalType()
                              {
                                   DebtType = new DebtType()
                                   {
                                        DebtTypeID = debttype.DebtTypeID,
                                         Description = debttype.DebtTypeLongDesc,
                                          DisplayName = debttype.DebtTypeShortDesc,
                                   },
                                    StatesCodes = from cases2 in cases
                                                  select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType.DebtTypesLocalType.StatesCodesLocalType()
                                                  {
                                                       ClosedCasesCount = cases2.Sum(p => Convert.ToInt32(p.cases.CaseClosed))

これは、データベーステーブルを結合してグループ化し、結果をClientSummaryに投影しようとします(クラス名は異なりますが、上記は出力クラスの簡略化されたビューであるためです)。Casesテーブルまでドリルダウンすると完全に失敗し、集計関数の実行方法がよくわからないことがわかりました。それらはsでのみ利用可能でIGrouping<K, T>あるように見え、私は混乱しているようです。

また、要約がサーバー側で計算されるようにする必要があります。何百万ものケースを引き戻すのは悪いことです。

誰かがこれを手伝ってくれますか?これも可能ですか?

よろしく、

ジェームズ。

------- ### UPDATE 1 ### -------

OK、今日もこれに取り組んでいます。Linq2SQLを使用してパック2Dデータをプルし、Linq2Objectsを使用して再フォーマットすることにしました。

これが私が始めたものです:

var sql = from clientnames in db.ClientNames
      join clientdebttypes in db.ClientDebtTypes on clientnames.ClientID equals clientdebttypes.ClientID
      join debttypes in db.DebtTypes on clientdebttypes.DebtTypeID equals debttypes.DebtTypeID
      join cases in db.Cases on new { ClientDebtTypeID = clientdebttypes.ClientDebtTypeID } equals new { ClientDebtTypeID = cases.CaseClientDebtTypeID }
      group new { clientnames, debttypes, cases } by new
      {
          clientnames.ClientID,
          clientnames.ClientCode,
          clientnames.ClientName1,
          debttypes.DebtTypeID,
          debttypes.DebtTypeShortDesc,
          debttypes.DebtTypeLongDesc,
          cases.CurrentStateCode
      } into g
      orderby
        g.Key.ClientID,
        g.Key.DebtTypeID,
        g.Key.CurrentStateCode
      select new
      {
          Client = new Client{ ClientID = g.Key.ClientID, DisplayName = g.Key.ClientName1 },
          DebtType = new DebtType{ DebtTypeID = g.Key.DebtTypeID, DisplayName = g.Key.DebtTypeShortDesc, Description = g.Key.DebtTypeLongDesc },
          StateSummary = new LoadCaseStatusOverviewScreenOutput.ClientsLocalType.DebtTypesLocalType.StatesCodesLocalType()
          {
              StateCode = g.Key.CurrentStateCode,
              OpenCasesCount = g.Sum(p => 1 - Convert.ToInt32(p.cases.CaseClosed)),
              ClosedCasesCount = g.Sum(p => Convert.ToInt32(p.cases.CaseClosed)),
              OnHoldCasesCount = g.Sum(p => Convert.ToInt32(p.cases.CaseOnHold)),
              ReferredCasesCount = g.Sum(p => Convert.ToInt32(p.cases.CaseReferred)),
              TotalCasesCount = g.Count(p => p.cases.CaseID != null),
              TotalAmountPaid = g.Sum(p => p.cases.CaseTotalPaid),
              TotalAmountOutstanding = g.Sum(p => p.cases.CaseCurrentOutstandingAmount),
              TotalAmountWrittenOff = g.Sum(p => p.cases.CaseTotalDebtWrittenOff),
              TotalAmountCancelled = g.Sum(p => p.cases.CaseTotalDebtCancelled),
          }
      };
var res = sql.ToList();

output.Clients = (from results in res
              group results by results.Client into resultsByClient
              from resultsByDebtType in
                  (from results in resultsByClient
                   group results by results.DebtType)
              group resultsByDebtType by resultsByClient.Key into resultsByDebtTypeByClient
              select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
              {
                  Client = resultsByDebtTypeByClient.Key,
                  DebtTypes = (from resultsByDebtType in resultsByDebtTypeByClient
                               select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType.DebtTypesLocalType()
                               {
                                   DebtType = resultsByDebtType.Key,
                                   StatesCodes = (from results in resultsByDebtType
                                                  let summary = results.StateSummary
                                                  select results.StateSummary).ToList()
                               }).ToList()
              }).ToList();

これは実行されますが、結果ごとに1つのClient / DebtType/Summaryセットが生成されます。したがって、この場合、クライアントは1つだけですが、最終的には1300のクライアントになり、すべて同じになります。私はそれを次のように単純化しました:

output.Clients = (from results in res
             group results by results.Client into resultsByClient
             select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
             {
                  Client = resultsByClient.Key,
                  DebtTypes = null,
             }).ToList();

これにより、1300のクライアントが生成されます。次に私はこれを試しました:

output.Clients = (from results in res
             group results by results.Client.ClientID into resultsByClient
             select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
             {
                  Client = new Client { ClientID = resultsByClient.Key },
                  DebtTypes = null,
             }).ToList();

そして、それは1つのクライアントを生成します(万歳!)。すべてのクライアント情報を失うことを除いて(ブー!)、コンテンツではなく参照によってクライアントを比較しているので、次のように書きました。

public partial class Client
{
    public static bool operator ==(Client left, Client right)
    {
        return left.ClientID == right.ClientID;
    }

    public static bool operator !=(Client left, Client right)
    {
        return left.ClientID != right.ClientID;
    }

    public override int GetHashCode()
    {
        return ClientID;
    }
}

それは何もしませんでした。を繰り返し呼び出しGetHashCode()、一致するClientIDに対して同じハッシュコードを返すように強制しましたが、それでも1300のクライアントグループが作成されました。

よろしく、

ジェームズ。

------- ### UPDATE 2 ### -------

OK、Linq2Sqlが次のようにグループ化するための単純な値のみを出力するようにすることに挑戦したいと思いました。

g.Key.ClientID,
g.Key.ClientName1,
g.Key.DebtTypeID,
g.Key.DebtTypeShortDesc,
g.Key.DebtTypeLongDesc,

次に、テストLinq2Objectsを次のように変更しました。

output.Clients = (from results in res
              group results by new { ClientID = results.ClientID, DisplayName = results.ClientName1 } into resultsByClient
              select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
              {
                  Client = new Client { ClientID = resultsByClient.Key.ClientID, DisplayName = resultsByClient.Key.DisplayName },
                  DebtTypes = null,
              }).ToList();

それはうまくいきます。したがって、匿名タイプは、(明らかに)参照されていないコンテンツによって、私が望む方法で比較します。これは次のことを行いません。

output.Clients = (from results in res
              group results by new SiDemClient { ClientID = results.ClientID, DisplayName = results.ClientName1 } into resultsByClient
              select new LoadCaseStatusOverviewScreenOutput.ClientsLocalType()
              {
                  Client = resultsByClient.Key,//new Client { ClientID = resultsByClient.Key.ClientID, DisplayName = resultsByClient.Key.DisplayName },
                  DebtTypes = null,
              }).ToList();

それでも1300のグループが作成されます。

だから、匿名のタイプは私が理解できない魔法の方法で比較します。Clientクラスを匿名タイプのように比較するにはどうすればよいですか?

よろしく、

ジェームズ。

-------###ソリューションが見つかりました###-------

-------###謎めいたことに感謝します###-------

Equals()==演算子を実装する代わりに、メソッドをオーバーライドする必要がありました。これでグループ化が機能し、再利用できるすばらしいXmlドキュメントができました。

public partial class SiDemClient
{
    public override bool Equals(object obj)
    {
        if (obj is SiDemClient)
        {
            return this.ClientID.Equals(((SiDemClient)obj).ClientID);
        }
        return false;
    }


    public override int GetHashCode()
    {
        return ClientID;
    }
}

どうもありがとう、

ジェームズ。

4

1 に答える 1

0

オーバーライドするときGetHashCodeは、もオーバーライドする必要がありますEquals==!=演算子は関係ありません。

これで試してください:

public partial class Client
{
    public override bool Equals(object obj)
    {
        if (obj is Client)
        {
            return this.ClientID.Equals(((Client)obj).ClientID);
        }
        return false;
    }

    public override int GetHashCode()
    {
        return this.ClientID.GetHashCode();
    }
}

それが役立つかどうかを確認してください。

于 2011-08-24T10:35:09.617 に答える