简体   繁体   中英

How to refactor LINQ query

I have the following code:

result = from i in _dbContext.Meetings
         where i.UserInvitedID == CurrentUserID && i.MeetingStatus == null && //!i.IsTex &&
         DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value > dateWithTime
         //where i.UserInvitedID == CurrentUserID && i.MeetingStatus == null && DbFunctions.TruncateTime(i.AllowedTime.AllowedDate.Day) >= date
         select new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp()
         {
             Name = i.UserInviter.FirstName + " " + i.UserInviter.LastName,
             Company = i.UserInviter.Company,
             Company2 = i.UserInvited.Company,
             MeetingID = i.MeetingID,
             Time = DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value,
             CreatedTime = i.dateCreated,
             Image = i.UserInviter.ProfileImage,
             TableNumber = i.TableNumber,
             Username = i.UserInviter.aspnet_User.UserName,
             Username2 = i.UserInvited.aspnet_User.UserName,
             UsernameInviter = i.UserInviter.aspnet_User.UserName,
             RequestText = i.RequestText,
             NoteInviter = i.NoteInviter,
             ResendInvitationCount = (i.ResendInvitationCount.HasValue) ? i.ResendInvitationCount.Value : 0,
             NoteInvited = i.NoteInvited,
             MeetingType = i.MeetingType.TypeName
         };

I use many such extentions with different modifications, but each of them has the same part select new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp().... .

ie

result = from i in _dbContext.Meetings
         where i.UserInviterID == CurrentUserID && i.MeetingStatus == null && !i.IsTex && DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value > dateWithTime
         //where i.UserInviterID == CurrentUserID && i.MeetingStatus == null && DbFunctions.TruncateTime(i.AllowedTime.AllowedDate.Day) >= date
         select new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp()
         {
             Name = i.UserInvited.FirstName + " " + i.UserInvited.LastName,
             //...
         };


result = from i in _dbContext.Meetings
         where (i.UserInviterID == CurrentUserID) && i.MeetingStatus == true && !i.IsTex && DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value > dateWithTime
         //where (i.UserInviterID == CurrentUserID) && i.MeetingStatus == true && DbFunctions.TruncateTime(i.AllowedTime.AllowedDate.Day) >= date
         select new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp()
         {
             Name = i.UserInvited.FirstName + " " + i.UserInvited.LastName,
             //...
         };

Can I set this part to variable to use in all other extentions?

You'll need to give up on the LINQ query syntax, and call the Select method directly. That should be no big deal. If you do that, you can store the projection part of your query in a separate variable.

Expression<Func<Meeting, ITW2012Mobile.Core.DataTable.MeetingModel2Tmp>> projection = i =>
    new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp()
    {
        Name = i.UserInviter.FirstName + " " + i.UserInviter.LastName,
        Company = i.UserInviter.Company,
        Company2 = i.UserInvited.Company,
        MeetingID = i.MeetingID,
        Time = DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value,
        CreatedTime = i.dateCreated,
        Image = i.UserInviter.ProfileImage,
        TableNumber = i.TableNumber,
        Username = i.UserInviter.aspnet_User.UserName,
        Username2 = i.UserInvited.aspnet_User.UserName,
        UsernameInviter = i.UserInviter.aspnet_User.UserName,
        RequestText = i.RequestText,
        NoteInviter = i.NoteInviter,
        ResendInvitationCount = (i.ResendInvitationCount.HasValue) ? i.ResendInvitationCount.Value : 0,
        NoteInvited = i.NoteInvited,
        MeetingType = i.MeetingType.TypeName
    };

...

result =
   (from i in _dbContext.Meetings
    where i.UserInviterID == CurrentUserID
    && i.MeetingStatus == null
    && !i.IsTex
    && DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value > dateWithTime
    select i).Select(projection);

This keeps the entire part of the query server-side, exactly as if you had written it out in each query.

Yes, you can create a method that returns a ITW2012Mobile.Core.DataTable.MeetingModel2Tmp for you and call that method in the select.

Something like

private ITW2012Mobile.Core.DataTable.MeetingModel2Tmp MethodName(TypeOfI i)
{
   return new ITW2012Mobile.Core.DataTable.MeetingModel2Tmp() {
       //same stuff as in your question's initializer
   };
}

and call it with

    result = from i in _dbContext.Meetings
             where i.UserInvitedID == CurrentUserID && i.MeetingStatus == null && //!i.IsTex &&
             DbFunctions.AddMinutes(DbFunctions.AddHours(i.MeetingTime.Day, i.MeetingTime.Hour).Value, i.MeetingTime.Minute).Value > dateWithTime
             //where i.UserInvitedID == CurrentUserID && i.MeetingStatus == null && DbFunctions.TruncateTime(i.AllowedTime.AllowedDate.Day) >= date
             select MethodName(i);

The query will get compiled down into LINQ extension methods anyway, and .Select() takes in a Func<TSource, TResult> as an argument. A Func is just a delegate (method) that has one input parameter (of type TSource ) and returns a TResult object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM