Resultant LinQ Query to a new DataTable - c#

Refer to earlier post/Question:
LINQ to Swap few Columns to Rows of a DataTable using C#
I want the resultant of the query interms of a new dataTable directly instead of defining columns in the new datatable.
Refer to the above post question the LINQ Query newset is:
var newSet = dt.AsEnumerable()
.GroupBy(r => r.Field<string>("Location"))
.Select(g => new
{
Location = g.Key,
ppl_required_Q1 = g.Where(p => p.Field<string>("Quarter") == "Q1").Sum(p => p.Field<int>("ppl_required")),
ppl_required_Q2 = g.Where(p => p.Field<string>("Quarter") == "Q2").Sum(p => p.Field<int>("ppl_required")),
ppl_required_Q3 = g.Where(p => p.Field<string>("Quarter") == "Q3").Sum(p => p.Field<int>("ppl_required")),
ppl_required_Q4 = g.Where(p => p.Field<string>("Quarter") == "Q4").Sum(p => p.Field<int>("ppl_required")),
ppl_available_Q1 = g.Where(p => p.Field<string>("Quarter") == "Q1").Sum(p => p.Field<int>("ppl_available")),
ppl_available_Q2 = g.Where(p => p.Field<string>("Quarter") == "Q2").Sum(p => p.Field<int>("ppl_available")),
ppl_available_Q3 = g.Where(p => p.Field<string>("Quarter") == "Q3").Sum(p => p.Field<int>("ppl_available")),
ppl_available_Q4 = g.Where(p => p.Field<string>("Quarter") == "Q4").Sum(p => p.Field<int>("ppl_available")),
});
How to get the newset resultant collection in a new datatable directly without any loop through? Is it possible in LINQ??

Try this:
newset.CopyToDataTable();
Check this Link

Related

Return additional column in Linq Query?

I have this Linq query:
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new { Title = g.Key })
.Select(s => s.Title);
I want to return another column from the same table, its called: CodeId.
I am noob Linq programmer and quite lost in all those mish-mash things in C# so I can't really understand what should I do.
Can somebody help me how to return the another column from the same table with the same query call?
This may help you :
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new { Title = g.Key, CodeId = g.FirstOrDefault().CodeId });
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new {
Title = g.Key,
CodeId = g.Id,
OtherField = "Field"
})

Select multiple child columns with the same filter

I have this Linq lambda expression which generates abnormally complex SQL select to database. Is it somehow possibility to simplify it?
var devices = db.Devices
.Where(a => a.active == true)
.Select(a => new DeviceToDisplay
{
Id = a.Id,
serialNumber = a.serialNumber,
deviceRegion = a.deviceRegion,
activeIP = a.IPaddresses.Where(b => b.active == true).Select(b => b.IPaddress1).FirstOrDefault(),
Wip = a.IPaddresses.Where(b => b.active == true).Select(b => b.W_IP).FirstOrDefault(),
Sip = a.IPaddresses.Where(b => b.active == true).Select(b => b.S_IP).FirstOrDefault(),
model = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).Select(c => c.model).FirstOrDefault(),
firmware = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).Select(c => c.firmware).FirstOrDefault(),
lastMPteamActivity = a.activityLogs.OrderByDescending(c => c.updatedDate).Select(c => c.updatedDate).FirstOrDefault(),
country = a.MPPinformations.Select(c => c.country).FirstOrDefault()
});
For a start, your linq query looks very complicated. Imagine how you would implement this by writing a SQL query for example.
A suggestion: you are writing things like:
a.IPaddresses.Where(b => b.active == true).
and
a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).
in multiple places.
Instead you could create an anonymous type. For example,
var foo = from x in sb.Devices.Where(a=> a.active)
select new { Id = x.ID,
IPAddress = a.IPaddresses.Where(b => b.active), ... }
You can then use foo to create your Devices object.
See if this is any better:
var devices = db.Devices
.Where(a => a.active == true)
.Select(a => new DeviceToDisplay {
Id = a.Id,
serialNumber = a.serialNumber,
deviceRegion = a.deviceRegion,
activeIP = a.IPaddresses.Where(b => b.active == true).FirstOrDefault(),
SPdata = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).FirstOrDefault(),
lastMPteamActivity = a.activityLogs.OrderByDescending(c => c.updatedDate).Select(c => c.updatedDate).FirstOrDefault(),
country = a.MPPinformations.Select(c => c.country).FirstOrDefault()
})
.Select(a=> new DeviceToDisplay {
Id=a.Id,
serialNumber=a.serialNumber,
deviceRegion=a.deviceRegion,
activeIP=a.activeIP.IPaddress1,
Wip=a.activeIP.W_IP,
Sip=a.activeIP.S_IP,
model=a.SPdata.model,
firmware=a.SPdata.firmware,
lastMPteamActivity=a.lastMPteamActivity,
country=a.county
});

c# lambda reading each row with GROUP BY and SUM

This is the working query i was using in my management studio.
SELECT TOP 5 productCode, SUM(productSales) AS sales
FROM sellingLog
WHERE (salesYear = '2014')
GROUP BY productCode
ORDER BY sales DESC
I want to convert the query above into lambda, but i can't seems to make it works. the lambda still lacks of order by and select the productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => b.Sum(u => u.productSales)).Take(5)
.ToList();
foreach(var v in topProduct)
{
//reading 'productCode' and 'sales' from each row
}
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(g => new { productCode = g.Key, sales = g.Sum(u => u.productSales) })
.OrderByDescending(x => x.productCode)
.Take(5)
.ToList();
You can use the .Key with group by to get productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => new {u.Key, b.Sum(u => u.productSales)}).Take(5)
.OrderByDescending(b=>b.Sales)
.ToList();

Adding more parameters to a Linq query

I'm using this query to count number of orders by date. I'm trying to add one more parameter that counts total products for each order, however I can't get it to work atm.
This is the essential part of a method that is suposed to return a list of 3 parameters (Date, TotalOrders and TotalProducts). Im using a Linq query to get a list with total order for each date, im wondering how to add my third parameter to the list "TotalProducts" and if i can do by adding one more search parameter in the Query. The foreach part below do not work propertly, it will return a list of TotalProducts but CreationDate will be the same for ech item in the list. I also have a feeling putting a foreach inside a foreach dosn't seem optimal for this:
var orders = _orderService.SearchOrderStatistics(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid);
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new { Date = s.Key, Count = s.Count() });
List<GCOrdersModel> TotalOrdersPaid = new List<GCOrdersModel>();
foreach (var g in result)
{
foreach (var opv in orders)
{
GCOrdersModel _Om = new GCOrdersModel(g.Date, g.Count.ToString(), opv.OrderProductVariants.Count.ToString());
TotalOrdersPaid.Add(_Om);
}
}
return TotalOrdersPaid;
To access total products for every orders I must use OrderProductVariants.Count.ToString()
Can I add this parameter to the query?
Thx
You could try this:
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = opv.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count, opv.OrderProductVariants.Count.ToString()))
.ToList();
That way, you don't have to iterate over your result again. And it automatically creates your list of GCOrdersModel.
Edit
Does this work?
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = s.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count(), s.OrderProductVariants.Count.ToString()))
.ToList();
How about:
var opvCount =
opv
.OrderProductVariants
.Count
.ToString();
return
orders
.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new
{
Date = s.Key,
Count = s.Count()
})
.Select(x =>
new GCOrdersModelg(x.Date, g.Count.ToString(), opvCount));

Add correlated subqueries to Select statement using QueryOver

I'm attempting to convert a SQL statement to use QueryOver (in hopes of pre-fetching the entities part of the response) but I'm having trouble figuring out how to add a correlated subquery to the Select statement (all the examples I found have only shown using a subquery in the Where clause).
This is the query I'm trying to convert:
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending");
var projectWhereClause = project != null ? "AND f1.project_id = " + project.Id : "";
var query = Session.CreateSQLQuery(string.Format(#"
SELECT
ft.id as FEEDBACK_TYPE_ID,
(SELECT COUNT(*) FROM FEEDBACK f1 WHERE ft.id = f1.feedback_type_id AND f1.archive_ind = 0 {0}) as ALL_FEEDBACK_COUNT,
(SELECT COUNT(*) FROM FEEDBACK f1 WHERE ft.id = f1.feedback_type_id AND f1.archive_ind = 0 {0} AND feedback_status_id = {1}) as PENDING_FEEDBACK_COUNT
FROM feedback f
RIGHT JOIN feedback_type ft on f.feedback_type_id = ft.id WHERE ft.RESTRICTED_IND = 0
GROUP BY ft.id, ft.sort_order
ORDER BY ft.sort_order",
projectWhereClause,
pendingFeedbackStatus.Id
))
.SetResultTransformer(Transformers.AliasToEntityMap);
var results = query.List<IDictionary>();
return results.Select(r =>
new FeedbackTypeSummary
{
Type = Get(Convert.ToInt32(r["FEEDBACK_TYPE_ID"])),
AllFeedbackCount = Convert.ToInt32(r["ALL_FEEDBACK_COUNT"]),
PendingFeedbackCount = Convert.ToInt32(r["PENDING_FEEDBACK_COUNT"])
}).ToList();
and here is what I have so far (which is mostly everything minus the correlated subqueries and some additional filtering added to the subqueries):
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending");
Feedback feedbackAlias = null;
FeedbackType feedbackTypeAlias = null;
var allFeedback = QueryOver.Of<Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived);
var pendingFeedback = QueryOver.Of<Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived)
.Where(f => f.Status.Id == pendingFeedbackStatus.Id);
var foo = Session.QueryOver<Feedback>(() => feedbackAlias)
.Right.JoinAlias(f => f.Type, () => feedbackTypeAlias, ft => !ft.IsRestricted)
.SelectList(list => list
// TODO: Add correlated subqueries here?
.SelectGroup(() => feedbackTypeAlias.Id)
.SelectGroup(() => feedbackTypeAlias.SortOrder)
)
.OrderBy(() => feedbackTypeAlias.SortOrder).Asc;
var test = foo.List<object[]>();
I'd also like to find a way to return a full FeedbackType entity of from the statement, instead of returning feedbackTypeAlias.Id and then having to perform Type = Get(Convert.ToInt32(r["FEEDBACK_TYPE_ID"])) in a loop as I do in the original.
I felt like I looked for this 10 times, but I overlooked the .SelectSubQuery() method which provided the desired correlated subqueries. This answer tipped me off - https://stackoverflow.com/a/8143684/191902.
Here is the full QueryOvery version:
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending").SingleOrDefault();
Domain.Feedback.Feedback feedbackAlias = null;
FeedbackType feedbackTypeAlias = null;
var allFeedback = QueryOver.Of<Domain.Feedback.Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived);
var pendingFeedback = QueryOver.Of<Domain.Feedback.Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived)
.Where(f => f.Status.Id == pendingFeedbackStatus.Id);
if (project != null)
{
allFeedback.Where(f => f.Project.Id == project.Id);
pendingFeedback.Where(f => f.Project.Id == project.Id);
}
FeedbackTypeSummary result = null;
var query = Session.QueryOver<Domain.Feedback.Feedback>(() => feedbackAlias)
.Right.JoinAlias(f => f.Type, () => feedbackTypeAlias, ft => !ft.IsRestricted)
.SelectList(list => list
.SelectSubQuery(allFeedback.ToRowCountQuery()).WithAlias(() => result.AllFeedbackCount)
.SelectSubQuery(pendingFeedback.ToRowCountQuery()).WithAlias(() => result.PendingFeedbackCount)
.SelectGroup(() => feedbackTypeAlias.Id).WithAlias(() => result.TypeId)
.SelectGroup(() => feedbackTypeAlias.Name).WithAlias(() => result.TypeName)
.SelectGroup(() => feedbackTypeAlias.NamePlural).WithAlias(() => result.TypeNamePlural)
.SelectGroup(() => feedbackTypeAlias.SortOrder)
)
.OrderBy(() => feedbackTypeAlias.SortOrder).Asc
.TransformUsing(Transformers.AliasToBean<FeedbackTypeSummary>());
var results = query.List<FeedbackTypeSummary>();
return results;
I also was able to populate my FeedbackTypeSummary DTO from a single query, although I couldn't find a way to alias an entity and ended up extracting a few of the needed properties from FeedbackType into FeedackTypeSummary (which is probably a better thing to do anyways).

Categories