简化我的groupby

时间:2011-02-25 15:49:51

标签: c# linq linq-to-sql

嗨我想将组数据返回到ui层。

这里是我想如何简化groupby“GenerationDate”并返回List<>中的数据回到UI gridview。 我觉得这很麻烦,因为我做了forloop。同样在UI层,我必须为这个简单的groupby做另一个forloop。你能帮忙简化一下吗?

public List<SalaryTracker> GetSalaryTrackerOrderByGenerationDate(int tutorId)
{
    List<SalaryTracker> salary = new List<SalaryTracker>();
    using (leDataContext db = new leDataContext())
    {
        try
        {
            var r = 
                from s in db.SalaryTrackers
                where s.StaffId == 2 && s.PaymentDate == null
                group s by s.GenerationDate into g
                where g.Count() > 0
                select new
                {
                    date = g.Key, totalSalary = g.Sum(p => p.SalaryAmount)
                };

            foreach (var rr in r)
            {
                SalaryTracker m = new SalaryTracker();
                m.GenerationDate = rr.date;
                m.SalaryAmount = rr.totalSalary;
                salary.Add(m);
            }

            return salary; 
        }
        catch (Exception ex)
        {
            Logger.Error(typeof(SalaryTracker), ex.ToString());
            throw;
        }                    
    }
}

--------------- GUI

totalCommissionsGroup = salary.GetSalaryTrackerOrderByGenerationDate(tutor.Id);

IList<SalaryTracker> rr = (
    totalCommissionsGroup.GroupBy(x => x.GenerationDate)
    .Select(g => new SalaryTracker
    {
        MonthId = g.Key.Month,
        MonthToPay = common.GetMonthName(Convert.ToInt16(g.Key), true),
        SalaryAmount = g.Sum(x => x.SalaryAmount)
    })).ToList<SalaryTracker>();  

gvSalaryPayment.DataSource = rr;           

我这样做,以便我可以在字符串

中获得MonthToPay

2 个答案:

答案 0 :(得分:2)

public List<SalaryTracker> GetSalaryTrackerOrderByGenerationDate(int tutorId)
{
    using (var db = new leDataContext())
    {
        try
        {
            return (
                from s in db.SalaryTrackers
                where s.StaffId == 2 && s.PaymentDate == null
                group s by s.GenerationDate into g
                select new
                { 
                    MonthId = g.Key.Month,
                    // I don't know what "common" is in your UI code, 
                    // I am just using GetMonthName here
                    MonthToPay = GetMonthName(Convert.ToInt16(g.Key), true), 
                    SalaryAmount = g.Sum(p => p.SalaryAmount)  
                })
                .AsEnumerable()
                .Select(x => new SalaryTracker 
                { 
                    MonthId = x.MonthId,
                    MonthToPay = x.MonthToPay, 
                    SalaryAmount = x.SalaryAmount  
                })
                .ToList();
        }
        catch (Exception ex)
        {
            Logger.Error(typeof(SalaryTracker), ex.ToString());
            throw;
        }
    }
}

答案 1 :(得分:0)

我同意Mahesh Velaga的重构(+1),我想补充一点,应用程序的那个级别的日志记录错误是不寻常的。特别是当你决定以任何方式重新抛出异常时。因此,我建议您删除带有错误日志记录的完整try catch,并仅在应用程序的根目录中记录(如果您还没有这样做)。这使您的代码更加清晰。

当你这样做的时候,你会发现剩下的是一个很好的可读方法,除了业务逻辑之外别无其他任何东西。

更新

  

但如果我们不把'试试'   在datamodel层,怎么会   主调用者捕获错误?我有   多年来一直在使用这种模式..   如果我错了,请纠正我。参考   这个link

按照您提供的referenced article中所示的方式,按照您提供的方式进行操作几乎总是次优的,原因如下:

  • 在服务层捕获,记录和重新抛出是不幸的,因为您最终会在日志记录系统中输入此错误的两个条目,因为您无论如何都需要登录应用程序的顶层,否则您将错过不是来自服务层的日志记录错误。忽略错误(通过重新抛出它)也是一个坏主意,因为当发生错误时客户端几乎不会继续。
  • referenced article所示,在表示层捕获也很不幸,因为这样您就不会记录错误,但更重要的是,您可能会向用户显示可能的技术性和模糊错误消息(甚至可能在外语中)他们不理解,这会使他们感到沮丧。更糟糕的是,它可能导致信息泄露,使黑客能够在攻击您的应用程序时查看表面下发生的事情(如果是公开的Web应用程序)。

这并不意味着您无法向用户显示任何错误信息,而只会对您明确抛出以向用户显示错误信息的异常执行此操作。例如:

try
{
    // Call into service layer
}
catch (BusinessLayerException ex)
{
    this.ValidationSummary1.Add(new CustomValidator
    {
        ErrorMessage = ex.Message, IsValid = false
    });
}

在此示例中,BusinessLayerException是从业务层抛出的特殊异常,其中包含可供用户理解的错误消息(如果多个用户使用您的应用程序,可能会出现本地化错误消息)语言)。

对于所有其他异常,大多数情况下您不希望向用户显示确切的错误消息,因为您不知道出了什么问题以及错误有多严重以及异常包含哪些信息。最好的办法是在表示层中尽可能减少错误处理逻辑,并在应用程序顶层的一个位置处理它。在这种情况下,您可以确保在这种情况下向用户显示错误页面,并确保将错误记录到日志系统中。

您可以configure ASP.NET在出现错误时显示自定义错误页面。这是一个例子:

<customErrors mode="RemoteOnly" 
    defaultRedirect="~/ErrorPage.htm">
</customErrors>

ErrorPage.htm可以显示一般信息,例如Stackoverflow上的一般“它是我们的错误”错误页面。也许一些支持的联系信息,您的家庭电话号码,以便他们可以在晚上给您打电话; - )

通过在global.asax中实现Application_Error方法,您可以在应用程序日志中的单个位置处理未处理的异常:

void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();

   // Log the exception here.
}

确保记录有关所需错误的信息,例如堆栈跟踪,错误消息,异常类型以及可能发生的所有内部异常。

我希望这会有所帮助。