Linq with entity Framework using a function to select columns - c#

I'm trying to reduce the amount of code in my application.
I want to turn this
return _db.SnapshotQueues
.Include(c => c.SnapshotDefinition)
.Include(c => c.SnapshotDefinition.Client)
.Include(c => c.Server)
.Select(s => new SnapshotQueueModel()
{
SnapshotQueueID = s.SnapshotQueueID,
SnapshotDefinitionID = s.SnapshotDefinitionID,
ScheduleID = s.ScheduleID,
DateCreated = s.DateCreated,
Protected = s.Protected,
StartTime = s.StartTime,
FinishTime = s.FinishTime,
Processed = s.Processed,
CoreSnapshotDatabaseName = s.CoreSnapshotDatabaseName,
Removed = s.Removed,
SnapshotID = s.SnapshotID,
EmailNotification = s.EmailNotification,
Email = s.Email,
ServerID = s.ServerID,
DateRequested = s.DateRequested,
Canceled = s.Canceled,
Active = s.Active,
LastSnapshotQueueActionID = s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate).ThenByDescending(o => o.SnapshotQueueActionID).FirstOrDefault().ActionID,
LastAction = s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate).ThenByDescending(o => o.SnapshotQueueActionID).FirstOrDefault().SnapshotAction.Description,
SnapshotLogCount = s.SnapshotGenerationLogs.Count(),
SnapshotDefinition = s.SnapshotDefinition.Name,
Server = s.Server.ServerName,
ScheduleName = s.Schedule.Name,
ClientName = s.SnapshotDefinition.Client.ClientName_Long
}
)
.Where(s => s.SnapshotDefinitionID == snapshotDefinitionID)
.OrderBy(sortFieldExpression);
into this
return _db.SnapshotQueues
.Include(c => c.SnapshotDefinition)
.Include(c => c.SnapshotDefinition.Client)
.Include(c => c.Server)
.Select(s => _snapshotQueueModelGet(s))
.Where(s => s.SnapshotDefinitionID == snapshotDefinitionID)
.OrderBy(sortFieldExpression);
private readonly Func<SnapshotQueue, SnapshotQueueModel> _snapshotQueueModelGet = s => new SnapshotQueueModel
{
SnapshotQueueID = s.SnapshotQueueID,
SnapshotDefinitionID = s.SnapshotDefinitionID,
ScheduleID = s.ScheduleID,
DateCreated = s.DateCreated,
Protected = s.Protected,
StartTime = s.StartTime,
FinishTime = s.FinishTime,
Processed = s.Processed,
CoreSnapshotDatabaseName = s.CoreSnapshotDatabaseName,
Removed = s.Removed,
SnapshotID = s.SnapshotID,
EmailNotification = s.EmailNotification,
Email = s.Email,
ServerID = s.ServerID,
DateRequested = s.DateRequested,
Canceled = s.Canceled,
Active = s.Active,
LastSnapshotQueueActionID =
s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate)
.ThenByDescending(o => o.SnapshotQueueActionID)
.FirstOrDefault()
.ActionID,
LastAction =
s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate)
.ThenByDescending(o => o.SnapshotQueueActionID)
.FirstOrDefault()
.SnapshotAction.Description,
SnapshotLogCount = s.SnapshotGenerationLogs.Count(),
SnapshotDefinition = s.SnapshotDefinition.Name,
Server = s.Server.ServerName,
ScheduleName = s.Schedule.Name,
ClientName = s.SnapshotDefinition.Client.ClientName_Long
};
The problem is that it passes in to SQL Server, and the database doesn't know what to do with the function. I get the error
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
I'm using the same select list in a few places, so it would stop bugs creeping in when field are added.

Declare your field as Expression<Func<SnapshotQueue, SnapshotQueueModel>>:
private readonly Expression<Func<SnapshotQueue, SnapshotQueueModel>> _snapshotQueueModelGet = s => new SnapshotQueueModel
{
SnapshotQueueID = s.SnapshotQueueID,
SnapshotDefinitionID = s.SnapshotDefinitionID,
ScheduleID = s.ScheduleID,
DateCreated = s.DateCreated,
Protected = s.Protected,
StartTime = s.StartTime,
FinishTime = s.FinishTime,
Processed = s.Processed,
CoreSnapshotDatabaseName = s.CoreSnapshotDatabaseName,
Removed = s.Removed,
SnapshotID = s.SnapshotID,
EmailNotification = s.EmailNotification,
Email = s.Email,
ServerID = s.ServerID,
DateRequested = s.DateRequested,
Canceled = s.Canceled,
Active = s.Active,
LastSnapshotQueueActionID =
s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate)
.ThenByDescending(o => o.SnapshotQueueActionID)
.FirstOrDefault()
.ActionID,
LastAction =
s.SnapshotQueueActions.OrderByDescending(o => o.ActionDate)
.ThenByDescending(o => o.SnapshotQueueActionID)
.FirstOrDefault()
.SnapshotAction.Description,
SnapshotLogCount = s.SnapshotGenerationLogs.Count(),
SnapshotDefinition = s.SnapshotDefinition.Name,
Server = s.Server.ServerName,
ScheduleName = s.Schedule.Name,
ClientName = s.SnapshotDefinition.Client.ClientName_Long
};

Related

Loop through dataset by row number

I have a online dataset that I am looping through to save it to a sqlite database. It works well, however the 'count' in which it is sequentially looping through is based on the ID column, however there are instances where the IDs (for the category that I am filtering on) are not sequential. I'd rather loop through row number or similar if possible - but I can't seem to find a way to do it. Below is my code:
Note the count starts at 793 because this is the ID of the first 'surface' categorised record
private async void updateAssetRegisterLocal()
{
try
{
var current = Connectivity.NetworkAccess;
if (current != NetworkAccess.Internet)
{
await DisplayAlert("No Internet Connectivity", "Move to a location with mobile coverage and try again", "OK");
}
else
{
UserDialogs.Instance.ShowLoading();
HttpClient client = new HttpClient();
var response = await client.GetStringAsync("https://XXXX.azurewebsites.net/api/assets");
var onlineAssets = JsonConvert.DeserializeObject<List<AssetRegister>>(response);
var assetsPrelim = onlineAssets
.Where(w => w.Asset_Category == "Surface")
.OrderBy(d => d.ID)
.ToList();
;
using (SQLiteConnection conn = new SQLiteConnection(App.FilePath))
{
try
{
conn.DropTable<AssetRegister>();
}
catch
{
await DisplayAlert("Unsuccessful", "Can't Access", "OK");
}
}
for (int count = 793; count <= (assetsPrelim.Count + 793); count++)
{
var assets = assetsPrelim.Where(x => x.ID == count);
var id = assets.Select(l => l.ID).FirstOrDefault();
var asset_ID = assets.Select(l => l.Asset_ID).FirstOrDefault();
var road_ID = assets.Select(l => l.Road_ID).FirstOrDefault();
var segmentString = assets.Select(l => l.AssetSegmentString).FirstOrDefault();
var hierarchy = assets.Select(l => l.Road_Hierarchy).FirstOrDefault();
var assetCategory = assets.Select(l => l.Asset_Category).FirstOrDefault();
var lat = assets.Select(l => l.Lat).FirstOrDefault();
var inspectionDue = assets.Select(l => l.Inspection_Due).FirstOrDefault();
var lon = assets.Select(l => l.Lon).FirstOrDefault();
var stdRoadId = assets.Select(l => l.StdRoadID).FirstOrDefault();
var assetType = assets.Select(l => l.Asset_Type).FirstOrDefault();
var inspectionDate = assets.Select(l => l.Last_Inspection_Date).FirstOrDefault();
using (SQLiteConnection con = new SQLiteConnection(App.FilePath))
{
con.CreateTable<AssetRegister>();
var assetsLocal = con.Table<AssetRegister>().ToList();
int arlID = assetsLocal.Count + 1;
AssetRegister arl = new AssetRegister()
{
ID = id,
Asset_ID = asset_ID,
Asset_Type = assetType,
Asset_Category = assetCategory,
Road_ID = road_ID,
Road_Hierarchy = hierarchy,
AssetSegmentString = segmentString,
Inspection_Due = inspectionDue,
StdRoadID = stdRoadId,
Lat = lat,
Lon = lon,
Last_Inspection_Date = inspectionDate,
};
using (SQLiteConnection conn = new SQLiteConnection(App.FilePath))
{
conn.CreateTable<AssetRegister>();
int rowsAdded = conn.Insert(arl);
conn.Close();
}
}
}
await DisplayAlert("Success", "Asset Register Updated on Device", "OK");
UserDialogs.Instance.HideLoading();
}
}
catch
{
await DisplayAlert("Error", "Could not get data - Report to System Adminstrator", "OK");
UserDialogs.Instance.HideLoading();
}
}
It looks like you can loop simply iterating using foreach
Instead of
for (int count = 793; count <= (assetsPrelim.Count + 793); count++)
{
var assets = assetsPrelim.Where(x => x.ID == count);
var id = assets.Select(l => l.ID).FirstOrDefault();
var asset_ID = assets.Select(l => l.Asset_ID).FirstOrDefault();
var road_ID = assets.Select(l => l.Road_ID).FirstOrDefault();
var segmentString = assets.Select(l => l.AssetSegmentString).FirstOrDefault();
var hierarchy = assets.Select(l => l.Road_Hierarchy).FirstOrDefault();
var assetCategory = assets.Select(l => l.Asset_Category).FirstOrDefault();
var lat = assets.Select(l => l.Lat).FirstOrDefault();
var inspectionDue = assets.Select(l => l.Inspection_Due).FirstOrDefault();
var lon = assets.Select(l => l.Lon).FirstOrDefault();
var stdRoadId = assets.Select(l => l.StdRoadID).FirstOrDefault();
var assetType = assets.Select(l => l.Asset_Type).FirstOrDefault();
var inspectionDate = assets.Select(l => l.Last_Inspection_Date).FirstOrDefault();
...
you can have
foreach (var asset in assetsPrelim)
{
var id = asset.ID;
var asset_ID = asset.Asset_ID;
var road_ID = assets.Road_ID;
var segmentString = asset.AssetSegmentString;
var hierarchy = asset.Road_Hierarchy;
var assetCategory = asset.Asset_Category;
var lat = asset.Lat;
var inspectionDue = asset.Inspection_Due;
var lon = asset.Lon;
var stdRoadId = asset.StdRoadID;
var assetType = asset.Asset_Type;
var inspectionDate = asset.Last_Inspection_Date;
...
Simply use foreach() instead of for() loop,
for (var asset in assetsPrelim)
{
var id = asset.Id;
var asset_ID = asset.Asset_ID;
var road_ID = assets.Road_ID;
//...
}

Push multiple objects with dynamic data into a DTO and return it

So I'm trying to use a DTO to reshape and return data, it's not working because I'm trying to push in an array of objects (as an IQueryable - which I don't think works) into the DTO, I'm also trying to push in dynamic data into one of the properties, as seen below in the 'hasCurrentUserLiked' property. I need to figure out How to change the objects from IQueryable, into actual objects so they can all be pushed into the DTO and the dynamic data can be worked out.
This is the code
public async Task<PagedList<UserPhoto>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
// this doesn't work because 'feeds' is an IQueryable, not an object
var like = await hasCurrentUserLiked(user.Id, feeds.id);
// this has the same problem as above
var feedsToReturn = new FeedsForReturnDto
{
Id = feeds.Id,
PhotoUrl = feeds.photoUrl,
Username = feeds.Username,
Description = feeds.Description,
DateAdded = feeds.DateAdded,
IsImage = feeds.IsImage,
hasCurrentUserLiked = like,
Likes = feeds.Likes
}
return await PagedList<UserPhoto>.CreateAsync(feedsToReturn, userParams.PageNumber, userParams.PageSize);
}
I thought that I might be able to get each image.id in a similar way the 'followerIds' are worked out but I couldn't figure out how to get this to work
[EDIT]
As per Enas Osamas answer, I've changed the code to this and I've debugged it, feedsToReturn has the correct info, so it is doing what its supposed to do. The problem I'm having now is that I'm unable to return it as it can't convert the IEnumerable to an IQueryable. I tried adding an explicit cast but that didn't work, I also tried removing the PagedList, and replacing the type to but this didn't work. My is an IQueryable which might be the problem, I tried changing that to an IEnumerable but this would mess up the code in other places.
This is my new code (still returning 'feeds' instead of 'feedsToReturn', will change when it works)
public async Task<PagedList<UserPhoto>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
var feedToReturn = feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.Id),
Likes = feed.Likes
});
return await PagedList<UserPhoto>.CreateAsync(feeds, userParams.PageNumber, userParams.PageSize);
}
I also tried changing some of the types around and this is what I came up with. The problem here is this:
'System.Collections.Generic.IEnumerable<cartalk.api.Dtos.feeds.FeedsForReturnDto>' to 'System.Linq.IQueryable<System.Collections.IEnumerable>'
and this problem is with the 'feedsToReturn' in the last line
public async Task<PagedList<IEnumerable>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
var feedToReturn = feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.Id),
Likes = feed.Likes
});
return await PagedList<IEnumerable>.CreateAsync(feedToReturn, userParams.PageNumber, userParams.PageSize);
}
PagedList code
public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source,
int pageNumber, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
return new PagedList<T>(items, count, pageNumber, pageSize);
}
[EDIT]
This is the hasCurrentUserLiked function, it works here
public bool checkCurrentUserLiked(int currentUserId, int imageId)
{
var doesCurrentUserLike = _context.PhotoLikes.Where(x => x.LikerId == currentUserId && x.ImageId == imageId);
var value = true;
if (doesCurrentUserLike == null)
{
value = false;
}
else
{
value = true;
}
return value;
}
You can try something like
feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.id),
Likes = feed.Likes
});
This would return an IEnumerable containing all the feeds mapped to your DTO after being enumerated to avoid performing operations against the database
[EDIT]
you can maybe do a left join with the _context.PhotoLikes.
Like this
feeds.GroupJoin(_context.PhotoLikes,
f => new { Id = f.Id, UserId = user.Id },
p => new { Id = p.ImageId, UserId = p.LikerId },
(f, p) => new { feed = f, photoLike = p })
.SelectMany(f => f.photoLike.DefaultIfEmpty(),
(f, p) => new FeedsForReturnDto
{
Id = f.feed.Id,
PhotoUrl = f.feed.photoUrl,
Username = f.feed.Username,
Description = f.feed.Description,
DateAdded = f.feed.DateAdded,
IsImage = f.feed.IsImage,
hasCurrentUserLiked = p != null,
Likes = feed.Likes
});
Just note that in this part
f => new { Id = f.Id, UserId = user.Id },
p => new { Id = p.ImageId, UserId = p.LikerId },
the datatypes of properties in both objects must match or it won't compile

How to avoid complexity while joining more 3 tables in Linq Lambda expressions

Coming from SQL background I am used to joining 5-8 tables in single query.
I can not imagine doing the same with Linq lambda expression syntax.
Here I am joining 4-5 tables/collections.
EG:
var viewmodel = logs.Join(CargoElements.lstContainerLoadStatus.ToList(), l => l.LoadStatus, ls => ls.Value, (x, ls) =>
new
{
log = x,
LoadStatusDesc = ls.Text
})
.Join(db.CargoContainerSize, log => log.log.CargoContainerSizeID, ccsize => ccsize.Id, (log, ccsize) => new
{
log = log,
CargoContainerSizeIDDesc = ccsize.Size
}).Join(db.CargoContainerType, log => log.log.log.CargoContainerTypeID, cct => cct.Id, (log, cct) => new
{
log = log,
CargoContainerTypeIDDesc = cct.Name
}).GroupJoin(db.CargoFrom, log => log.log.log.log.CargoFromID, cf => cf.ID, (log, cf) => new
{
log = log,
cf = cf
}).SelectMany(temp => temp.cf.DefaultIfEmpty(), (temp, cf) => new
{
log = temp,
CargoFromIDDesc = cf.Description
}
)
.Select(x => new ContainerInLogsVM
{
ContainerInLogID = x.log.log.log.log.log.ContainerInLogID,
ContainerInID = x.log.log.log.log.log.ContainerInID,
CargoID = x.log.log.log.log.log.CargoID,
LoadStatus = x.log.log.log.log.log.LoadStatus,
LoadStatusDesc = x.log.log.log.log.LoadStatusDesc,
Shipper = x.log.log.log.log.log.Shipper,
CnFAgentName = x.log.log.log.log.log.CnFAgentName,
ShippingBill = x.log.log.log.log.log.ShippingBill,
ContainerNo = x.log.log.log.log.log.ContainerNo,
CargoContainerSizeID = x.log.log.log.log.log.CargoContainerSizeID,
CargoContainerSizeIDDesc = x.log.log.log.CargoContainerSizeIDDesc,
CargoContainerTypeID = x.log.log.log.log.log.CargoContainerTypeID,
CargoContainerTypeIDDesc = x.log.log.CargoContainerTypeIDDesc,
OtherType = x.log.log.log.log.log.OtherType,
VesselNo = x.log.log.log.log.log.VesselNo,
ShipperBillNo = x.log.log.log.log.log.ShipperBillNo,
SealOTLNo = x.log.log.log.log.log.SealOTLNo,
VoyageNo = x.log.log.log.log.log.VoyageNo,
BLNumber = x.log.log.log.log.log.BLNumber,
Purpose = x.log.log.log.log.log.Purpose,
CargoFromID = x.log.log.log.log.log.CargoFromID,
CargoFromIDDesc = x.CargoFromIDDesc,
OtherFrom = x.log.log.log.log.log.OtherFrom,
Status = x.log.log.log.log.log.Status,
Remark = x.log.log.log.log.log.Remark,
StatusChangedOn = x.log.log.log.log.log.StatusChangedOn,
StatusChangedBy = x.log.log.log.log.log.StatusChangedBy,
StatusChangedByDesc = "",
SysRemark = x.log.log.log.log.log.SysRemark
}
).ToList();
This is ridiculous! Or am I doing it wrong? There has to be a better way in LINQ.
I am looking for answers preferably in lambda expressions.

c# DataTable Linq Group by Multiple column sum int and timespan

I want to sum of all Volume & TotalTimes Column after Group BY from DataTable Alias as Temp_DT. Remember Volume & All TotalTimes Column may have null or blank value.
Can anyone help me to get the code through Linq Method
Sample Temp_DT:
Result should be in this format
I have tried the below code, but Temp_DT result is Null.
var Temp_DT = tempdt.AsEnumerable().Select(x =>
new
{
UID = x.Field<string>("UID"),
EMPNAME = x.Field<string>("Emp Name"),
EMPROLE = x.Field<string>("Role"),
SUPID = x.Field<string>("Sup ID"),
SUPNAME = x.Field<string>("Sup Name"),
DESIGNATION = x.Field<string>("Designation"),
VOLUME = x.Field<int>("Volume"),
LOGINTIME = x.Field<TimeSpan>("Login Time"),
BREAKTIME = x.Field<TimeSpan>("Break Time"),
HANDLETIME = x.Field<TimeSpan>("Handle Time"),
ACTIVETIME = x.Field<TimeSpan>("Active Time"),
HOLDTIME = x.Field<TimeSpan>("Hold Time"),
ACWTIME = x.Field<TimeSpan>("ACW"),
IDLETIME = x.Field<TimeSpan>("Idle"),
PRODUCTIVE = x.Field<TimeSpan>("Productive"),
NONPRODUCTIVE = x.Field<TimeSpan>("Non Productive"),
USERERROR = x.Field<TimeSpan>("User Error Time")
}).GroupBy(s => new { s.UID, s.EMPNAME, s.EMPROLE, s.SUPID, s.SUPNAME, s.DESIGNATION })
.Select(g => new
{
g.Key.UID,
g.Key.EMPNAME,
g.Key.EMPROLE,
g.Key.SUPID,
g.Key.SUPNAME,
g.Key.DESIGNATION,
VOLUME = g.Sum(x => Convert.ToInt16(x.VOLUME)),
LOGINTIME = new TimeSpan(g.Sum(x => x.LOGINTIME.Ticks)),
BREAKTIME = new TimeSpan(g.Sum(x => x.BREAKTIME.Ticks)),
HANDLETIME = new TimeSpan(g.Sum(x => x.HANDLETIME.Ticks)),
ACTIVETIME = new TimeSpan(g.Sum(x => x.ACTIVETIME.Ticks)),
HOLDTIME = new TimeSpan(g.Sum(x => x.HOLDTIME.Ticks)),
ACWTIME = new TimeSpan(g.Sum(x => x.ACWTIME.Ticks)),
IDLETIME = new TimeSpan(g.Sum(x => x.IDLETIME.Ticks)),
PRODUCTIVE = new TimeSpan(g.Sum(x => x.PRODUCTIVE.Ticks)),
NONPRODUCTIVE = new TimeSpan(g.Sum(x => x.NONPRODUCTIVE.Ticks)),
USERERROR = new TimeSpan(g.Sum(x => x.USERERROR.Ticks)),
});
You have to Parse the TimeSpan and Sum by using Ticks, like below.
var Temp_DT = tempdt.AsEnumerable().Select(x =>
new
{
UID = x["UID"],
EMPNAME = x["Emp Name"],
EMPROLE = x["Role"],
SUPID = x["Sup ID"],
SUPNAME = x["Sup Name"],
DESIGNATION = x["Designation"],
VOLUME = x["Volume"],
ERRORTIME = x["Error_Time"],
ACWTIME = x["ACW"],
BREAKTIME = x["Break Time"],
IDLETIME = x["Idle"],
NONPRODUCTIVE = x["Non Productive"],
}).GroupBy(s => new { s.UID, s.EMPNAME, s.EMPROLE, s.SUPID, s.SUPNAME, s.DESIGNATION })
.Select(g => {
var grouped = g.ToList();
return new
{
UID = g.Key.UID,
EMPNAME = g.Key.EMPNAME,
EMPROLE = g.Key.EMPROLE,
SUPID = g.Key.SUPID,
SUPNAME = g.Key.SUPNAME,
DESIGNATION = g.Key.DESIGNATION,
VOLUME = grouped.Sum(x => Convert.ToInt16(x.VOLUME)),
Error_Time = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.ERRORTIME.ToString())).ToList().Sum(r=> r.Ticks)),
ACW = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.ACWTIME.ToString())).ToList().Sum(r=> r.Ticks)),
Break = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.BREAKTIME.ToString())).ToList().Sum(r=> r.Ticks)),
Idle = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.IDLETIME.ToString())).ToList().Sum(r=> r.Ticks)),
NonProductive = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.NONPRODUCTIVE.ToString())).ToList().Sum(r=> r.Ticks))
};
}).ToList();
The Conversion method is,
private static TimeSpan ConvertTimeSpan(string str)
{
TimeSpan outputValue;
TimeSpan.TryParse(str, out outputValue);
return outputValue;
}
C# Fiddle with sample data.

How to define in the lambda expression as another function in LINQ Select Method

I am creating Azure Mobile app.
In the api I created following list with Entity Framework 6.1.
The problem is that it is too big in the Select methods,
public IHttpActionResult GetAllQABundle(string qAUser_id, int offset = 0, int limit = 20)
{
List<QABundleWithCommentDto> qABundleWithCommentDtos = context.QABundles
.Where(b => b.TeamId == null)
.OrderByDescending(b => b.UpdatedAt)
.Skip(offset)
.Take(limit)
.Select(b => new QABundleWithCommentDto()
{
Id = b.Id,
TagForFreeFormat = b.TagForFreeFormat,
MovieUrl = b.Movie.MovieUrl,
MovieThumbnailUrl = b.Movie.MovieThumbnailUrl,
MovieStreamUrl = b.Movie.MovieStreamUrl,
NumberOfViews = b.Movie.NumberOfViews,
Title = b.Title,
Description = b.Description,
QuestionType = b.QuestionType,
WannaKnowId = b.WannaKnows.Where(w => w.QAUserId == qAUser_id).FirstOrDefault().Id,
WannaKnowCount = b.WannaKnows.Count,
QAUserThumbnailUrl = b.QAUser.ThumbnailUrl,
QAUserId = b.QAUser.Id,
UserName = b.QAUser.UserName,
UpdatedAt = b.UpdatedAt,
GenereDtos = b.Generes.Select(t => new GenereDto() { GenereId = t.Id, GenereName = t.Name }).ToList(),
CommentDtos = b.Comments.OrderByDescending(c => c.UpdatedAt).Take(20).Select(c => new CommentDto()
{
Id = c.Id,
Text = c.Text,
MovieUrl = c.Movie.MovieUrl,
MovieThumbnailUrl = c.Movie.MovieThumbnailUrl,
QAUserId = c.QAUserId,
UserName = c.QAUser.UserName,
QAUserBelongsTo = c.QAUser.BelongsTo,
QAUserThumbnailUrl = c.QAUser.ThumbnailUrl,
CommentCreatedAt = c.CreatedAt,
Likes = c.Likes.Count,
LikeId = c.Likes.Where(x => x.QAUserId == qAUser_id).FirstOrDefault().Id,
UpdatedAt = c.UpdatedAt,
QABundleId = c.QABundleId
}).ToList(),
TeamDto = new TeamDto()
{
Id = b.TeamId,
Name = b.Team.Name,
FollowedDtos = b.Team.QAUsers.Select(u => new FollowedDto()
{
Id = u.Id,
UserName = u.UserName,
ThumbnailUrl = u.ThumbnailUrl,
}).ToList()
},
BestAnswerDto = new BestAnswerDto() { Id = b.BestAnswerId, CommentId = b.BestAnswer.CommentId }
})
.ToList();
return Json(qABundleWithCommentDtos);
}
I would like to define following part as another function, but I do not know how I implement that.
Does anyone have good idea?
b => new QABundleWithCommentDto()
{
Id = b.Id,
TagForFreeFormat = b.TagForFreeFormat,
MovieUrl = b.Movie.MovieUrl,
MovieThumbnailUrl = b.Movie.MovieThumbnailUrl,
MovieStreamUrl = b.Movie.MovieStreamUrl,
NumberOfViews = b.Movie.NumberOfViews,
Title = b.Title,
Description = b.Description,
QuestionType = b.QuestionType,
WannaKnowId = b.WannaKnows.Where(w => w.QAUserId == qAUser_id).FirstOrDefault().Id,
WannaKnowCount = b.WannaKnows.Count,
QAUserThumbnailUrl = b.QAUser.ThumbnailUrl,
QAUserId = b.QAUser.Id,
UserName = b.QAUser.UserName,
UpdatedAt = b.UpdatedAt,
GenereDtos = b.Generes.Select(t => new GenereDto() { GenereId = t.Id, GenereName = t.Name }).ToList(),
CommentDtos = b.Comments.OrderByDescending(c => c.UpdatedAt).Take(20).Select(c => new CommentDto()
{
Id = c.Id,
Text = c.Text,
MovieUrl = c.Movie.MovieUrl,
MovieThumbnailUrl = c.Movie.MovieThumbnailUrl,
QAUserId = c.QAUserId,
UserName = c.QAUser.UserName,
QAUserBelongsTo = c.QAUser.BelongsTo,
QAUserThumbnailUrl = c.QAUser.ThumbnailUrl,
CommentCreatedAt = c.CreatedAt,
Likes = c.Likes.Count,
LikeId = c.Likes.Where(x => x.QAUserId == qAUser_id).FirstOrDefault().Id,
UpdatedAt = c.UpdatedAt,
QABundleId = c.QABundleId
}).ToList(),
TeamDto = new TeamDto()
{
Id = b.TeamId,
Name = b.Team.Name,
FollowedDtos = b.Team.QAUsers.Select(u => new FollowedDto()
{
Id = u.Id,
UserName = u.UserName,
ThumbnailUrl = u.ThumbnailUrl,
}).ToList()
},
BestAnswerDto = new BestAnswerDto() { Id = b.BestAnswerId, CommentId = b.BestAnswer.CommentId }
Its type is Expression<Func<QABudle, QABundleWithCommentDto>> so if you write:
Expression<Func<QABudle, QABundleWithCommentDto>> selector = b => new
{
//rest of the code
}
now you can use selector like this: .Select(selector)

Categories