2

これが私が持っているコードの非常に単純化されたバージョンです:

class PrintJob : IEntity
{
    public string UserName { get; set; }
    public string Departmen { get; set; }
    public int PagesPrinted { get; set; }
}

class PrintJobReportItem
{
    public int TotalPagesPrinted { get; set; }
    public int AveragePagesPrinted { get; set; }
    public int PercentOfSinglePagePrintJobs { get; set; }
}

class PrintJobByUserReportItem : PrintJobReportItem
{
    public string UserName { get; set; }
}

class PrintJobByDepartmenReportItem : PrintJobReportItem
{
    public string DepartmentName { get; set; }
    public int NumberOfUsers { get; set; }
}

次に、2つのクエリがあります。

var repo = new Repository(...);

var q1 = repo.GetQuery<PrintJob>()
    .GroupBy(pj => pj.UserName)
    .Select(g => new PrintJobByUserReportItem
    {
    #region this is PrintJobReportItem properties
        TotalPagesPrinted = g.Sum(p => p.PagesPrinted),
        AveragePagesPrinted = g.Average(p => p.PagesPrinted),
        PercentOfSinglePagePrintJobs = g.Count(p => p.PagesPrinted == 1) / (g.Count(p => p.PagesPrinted) != 0 ? g.Count(p => p.PagesPrinted) : 1) * 100,
    #endregion    
        UserName = g.Key
    });

var q2 = repo.GetQuery<PrintJob>()
    .GroupBy(pj => pj.Departmen)
    .Select(g => new PrintJobByDepartmenReportItem
    {
    #region this is PrintJobReportItem properties
        TotalPagesPrinted = g.Sum(p => p.PagesPrinted),
        AveragePagesPrinted = g.Average(p => p.PagesPrinted),
        PercentOfSinglePagePrintJobs = g.Count(p => p.PagesPrinted == 1) / (g.Count(p => p.PagesPrinted) != 0 ? g.Count(p => p.PagesPrinted) : 1) * 100,
    #endregion    
        DepartmentName = g.Key,
        NumberOfUsers = g.Select(u => u.UserName).Distinct().Count()
    });

TotalPagesPrinted、AveragePagesPrinted、PercentOfSinglePagePrintJobsに値を割り当てて再利用できるようにし、DRYの原則に従うように、パーツを抽出するための提案は何でしょうか。

私はEF4.1コードのみのアプローチを使用していますが、別のテクノロジーまたはアプローチに切り替えることはできません。また、そのデータをマテリアライズできません。グリッドコンポーネントが後でクエリするものを追加するため、クエリとして保持する必要があります。そのため、LinqtoObjectに切り替えることができません。

4

2 に答える 2

2

2つのプロパティを持つ新しいクラスCLASSNAMEを作成します

  • PrintJobReportItemタイプ
  • グループ化IEnumerable<IGrouping<TKey, TSource>>

次に、拡張メソッドを作成します

public static IQueryable<CLASSNAME> EXTENSIONNAME<TKey, TSource>(this IEnumerable<IGrouping<TKey, TSource>> source)
{
  return from g in source
         select new CLASSNAME
         {
           PrintJobReportItem = new PrintJobReportItem
                                {
                                  TotalPagesPrinted = g.Sum(p => p.PagesPrinted),
                                  AveragePagesPrinted = etc...,
                                  PercentOfSinglePagePrintJobs = etc...,
                                },
           GROUPING = g
         };
}

その後、そのように使用します、私はテストしていませんが、それはうまくいくと思います

var q1 = repo.GetQuery<PrintJob>()
    .GroupBy(pj => pj.UserName)
    .EXTENSIONNAME()
    .Select(g => new PrintJobByDepartmenReportItem
                 {
                    PrintJobReportItem = g.PrintJobReportItem,
                    DepartmentName = g.GROUPING.Key,
                    NumberOfUsers = g.GROUPING.Select(u => u.UserName).Distinct().Count()

                 });
于 2011-06-08T16:36:06.977 に答える
0

私が考えることができる最も簡単なことPrintJobByDepartmenReportItemは、単一のIEnumerable<IGrouping<string, PrintJob>>パラメーターを受け入れるコンストラクターを作成することです(これはサンプルの変数のタイプであると私は信じていgます)。これにはパラメーターのないコンストラクター定義も必要であり、継承されたクラスは、パラメーターを使用して基本クラスのコンストラクターを呼び出すためのコンストラクタープロトタイプも実装する必要があることに注意してください。

コンストラクタ

public PrintJobReportItem()
{
}

public PrintJobReportItem(IEnumerable<IGrouping<string, PrintJob>> g)
{
    this.TotalPagesPrinted = g.Sum(i => i.GetEnumerator().Current.PagesPrinted);
    this.AveragePagesPrinted = g.Average(i => i.GetEnumerator().Current.PagesPrinted);
    this.PercentOfSinglePagePrintJobs = g.Count(i => i.GetEnumerator().Current.PagesPrinted == 1) * 100 / g.Count(i => i.GetEnumerator().Current.PagesPrinted > 1);
}

継承されたコンストラクタ

public PrintJobByDepartmentReportItem(IEnumerable<IGrouping<string, PrintJob>> g) : base(g)
{
    this.DepartmentName = g.First().Key;
    this.NumberOfUsers = g.Select(i => i.GetEnumerator().Current.UserName).Distinct().Count();
}

クエリ

var q1 = repo.GetQuery<PrintJob>()
    .GroupBy(pj => pj.UserName)
    .Select(g => new PrintJobByUserReportItem(g));

var q2 = repo.GetQuery<PrintJob>()
    .GroupBy(pj => pj.Department)
    .Select(g => new PrintJobByDepartmentReportItem(g));

これには、常に文字列メンバーによってグループ化されると想定するという1つの欠点がありますが、おそらくGroupBy(i => i.MyProperty.ToString())適切な場合、またはプロトタイプを受け入れるように変更することができますIEnumerable<IGrouping<object, PrintJob>>

于 2011-06-08T16:45:56.770 に答える