back to UIgridview." />
开发者

simplify my groupby

hi i would like to return the group data back to the ui layer.

he开发者_如何学编程re is how i want to do a simplify the groupby "GenerationDate" and return the data in List<> back to UI gridview. i find it very troublesome as i got to do the forloop. Also in the UI layer i got to do another forloop for this simple groupby. Could you help to simplify it?

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;           

i do this so that i can get the MonthToPay in string


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;
        }
    }
}


I agree with the refactoring of Mahesh Velaga (+1 for that) and I like to add that logging errors at that level of the application is unusual. Especially when you decide to rethrow the exception any way. Therefore, I suggest that you remove the complete try catch with error logging and log only in the root of your application (if you're not already doing that). That makes your code much more cleaner.

When you've done that, you'll see that what's left is a nice readable method with hardly anything else than business logic.

UPDATE

But if we do not put the 'try catch' in the datamodel layer, how would the main caller catch the error? i have been using this pattern for years.. please correct me if i am wrong. Refer to this link.

Catching the way you do in your question or is done as is shown in the referenced article you provide is almost always sub optimal, because of several reasons:

  • Catching, logging and rethrowing at the service layer is unfortunate, because you will end up with double entries of this error in your logging system, simply, because you need to log at the top layer of your application anyway, because otherwise you will miss logging errors that do not originate from the service layer. Ignoring the error (by not rethrowing it) is also a bad idea, because the client should hardly ever continue when an error occurs.
  • Catching at the presentation layer as shown in the referenced article is also unfortunate, because this way you don't log the errors, but more importantly, you present the user with possibly technical and obscure error messages (perhaps even in a foreign language) that they don't understand and it will frustrate them. Even worse, it could lead to information leakage that allows hackers to see what going on under the surface when attacking your application (in case of a publicly exposed web application).

This doesn't mean that you can't display any error information to the users, but only do that for exceptions that you thrown explicitly to present error information for the users. For instance:

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

In this example, the BusinessLayerException is a special exception that is thrown from the business layer that contains error messages that are understandable for the user (possibly with a localized error message if your application is used by users of multiple languages).

For all other exceptions, most of the time you don't want to show the user that exact error message, because you have no idea what went wrong and how severe the error is and what information the exception contains. The best thing to do is to have as less error handling logic as possible in your presentation layer, and handle this at one place in the top layer of the application. Here you ensure that an error page is displayed to the user in that case and you ensure that the error is logged to the logging system.

You can configure ASP.NET to show a custom error page in case of an error. Here's an example:

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

The ErrorPage.htm can display general information like the general "it's our fault" error page here at Stackoverflow. Perhaps some contact information of support, your home phone number, so they can call you at night ;-)

By implementing the Application_Error method in the global.asax, you can at a single place in the application log unhandled exceptions:

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

   // Log the exception here.
}

Make sure you log al the information about the error you need, such as stack trace, error message, exception type, and all the inner exceptions that can occur.

I hope this helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜