In one Linq Query get back data from multiple tables - asp.net

I have 3 tables:
sessions - This store information about trainings
xref_session_faculty - This cross references the trainings and the teacher
user - list of all teachers
In one(or more) LINQ query i want to get all the sessions and for each session the teachers that will be conducting the training. Each session can have zero or more teachers in the DB.
sessions = db.sessions
.Where(x => x.seminar_id == seminarId)
.ToList()
.Select((x, i) => new fees
{
id = x.id,
sessionTitle = x.title,
teacherNames = "By:" + String.Join(",",
x.xref_session_faculty.ToList()
.Select(q => db.users
.Where(m => m.id == q.user_id)
.Select(t => t.firstName).ToList()
)
)
})
.ToList();
With this the teacherNames prints out By:System.Collections.Generic.List1[System.String],System.Collections.Generic.List1[System.String].
WHat is the right query format here?

teacherNames = "By:" + String.Join(",",
x.xref_session_faculty.ToList()
.Select(q => db.users
.Where(m => m.id == q.user_id)
.Select(t => t.firstName).FirstOrDefault()
)
)
you need to change ToList to FirstOrDefault function to get correct result

private var sessions = (from session in db.sessions.Where(x => x.seminar_id == seminarId)
select new
{
id = session.id,
sessionTitle = session.title,
teacherNames = (from faculty in db.xref_session_faculty.
where (x => x.session_id == session.id)
join us in db.uses on faculty.user_id equals us.user_id
select new
{
us.firstName,
other_field_names
})
});

Related

Core EF Outer Join,Count & Group

I'm trying to convert this SQL Query into Core EF:
SELECT w.IdShippingBatch, w.BookingNumber, COUNT(c.IdShippingOrder) AS ShippingOrders, w.CreatedOn, w.ModifiedOn
FROM dbo.Shipping`enter code here`Batch AS w LEFT OUTER JOIN
dbo.ShippingOrders AS c ON w.IdShippingBatch = c.IdShippingBatch
WHERE (w.IdCompany = 2) AND (w.IdDealer = 1)
GROUP BY w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn
I have tried multiple solutions, including several here. My latest attempt looks like:
var data = (from w in _context.ShippingBatch
join c in _context.ShippingOrders on w.IdShippingBatch equals c.IdShippingBatch into t1
where w.IdCompany == idCompany && w.IdDealer == idDealer
from t2 in t1.DefaultIfEmpty()
group t2 by new { w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn } into t3
select new ShippingBatchDTO
{
IdShippingBatch = t3.Key.IdShippingBatch,
BookingNumber = t3.Key.BookingNumber,
ShippingOrders = t3.Count(),
CreatedOn = t3.Key.CreatedOn,
ModifiedOn = t3.Key.ModifiedOn
});
I have also tried adding t3.count(m => m.something != null), but that throws an error.
One major point of EF is to map the relationship between entities so that you can leverage LINQ and let EF compose an SQL query rather than trying to replace SQL with LINQ-QL.
If your ShippingBatch is mapped with a collection of ShippingOrders...
var batches = _context.ShippingBatch
.Where(x => x.IdCompany == idCompany && x.IdDealer == idDealer)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.IdShippingBatch,
BookingNumber = x.BookingNumber,
ShippingOrders = x.ShippingOrders.Count(),
CreatedOn = x.CreatedOn,
ModifiedOn = x.ModifiedOn
}).ToList();
If your ShippingBatch does not have a collection of ShippingOrders, but your ShippingOrder reference an optional ShippingBatch.
var batches = _context.ShippingOrder
.Where(x => x.ShippingBatch != null
&& x.ShippingBatch.IdCompany == idCompany
&& x.ShippingBatch.IdDealer == idDealer)
.GroupBy(x => x.ShippingBatch)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.Key.IdShippingBatch,
BookingNumber = x.Key.BookingNumber,
ShippingOrders = x.Count(),
CreatedOn = x.Key.CreatedOn,
ModifiedOn = x.Key.ModifiedOn
}).ToList();
That should hopefully get you moving in the right direction. If not, expand your question to include details of what you are seeing, and what you expect to see along with definitions for the applicable entities.

WHERE clauses in JOIN using LINQ with lambdas

I have this situation:
I have a form in ASP.NET and I need to extract data from a mssql db. The LINQ query is build from the values that are inserted in the form.
if (ddlRegion.SelectedIndex > 0)
{
query = query.Where(re => re.Region == ddlRegion.SelectedValue);
}
if (tbName.Text.Trim().Length > 0)
{
query = query.Where(na => na.Name.Contains(tbName.Text));
}
var result = query.Select(res => new
{
res.ColumnA,
res.ColumnB,
res.ColumnC
});
The problem is that I need to make a join with TableB
query = query.Join(TableB, tA => tA.Code, tB => tB.CodFiscal, (tA, tB) => tA);
The original SQL command is like this:
select tA.ColumnA, tA.ColumnB, tA.ColumnC from TableA tA join TableB tB on tA.Code=tB.Code where tB.ExpireDate>=getdate() and tB.datavalabil >=getdate()
The problem is where clauses from table tB join.
You can do something like this:
query = query.Join(TableB, tA => tA.Code, tB => tB.CodFiscal, (tA, tB) => new { tA, tB })
.Where(x => x.tB.ExpireDate >= DateTime.Now and x.tB.datavalabil >= DateTime.Now)
.Select(x => x.tA);
Or in query syntax:
query =
from tA in query
join tB in TableB on tA.Code equals tB.CodFiscal
where tB.ExpireDate >= DateTime.Now and tB.datavalabil >= DateTime.Now
select tA;

How do I create a followup LINQ .join() if an additional filter item is presented?

If I have a lystId, I want to include the MemberProductLyst object and filter by the LystId.
Any suggestions for the proper way to implement the follow up Lamba code inside of the
if (!string.IsNullOrEmpty(lystId)) {} block below the initial query???
products = (from p in dc.Products
join t in dc.Tags on p.TagId equals t.TagId
join pi in dc.ProductImages on p.ProductId equals pi.ProductId
join i in dc.Images on pi.ImageId equals i.ImageId
where p.IsActive == true
where t.TagId == new Guid(brandId)
orderby p.CreatedOn descending
select new ProductItem
{
productImage = i.FileName,
productId = p.ProductId,
description = p.Description,
name = p.Name,
adImage = t.AdImage
}).Skip(totalItemCount).Take(pageSize);
if (!string.IsNullOrEmpty(lystId))
{
//Include MemberProductLyst table to Filter by lystId if LystId is available
var memberLysts = from mpl in dc.MemberProductLysts
where mpl.LystId == new Guid(lystId)
select new { mpl.LystId, mpl.ProductId };
products = (IQueryable<ProductItem>)products.Join(memberLysts, p => p.productId, mpl => mpl.ProductId, (p, mpl) => new {ProductItem = p, MemberProductLyst = mpl });
}
It largely depends on the intent of your Join, but I suspect this may yield the results you're looking for:
products = products.Where(
p => memberLysts.Any(mpl => mpl.ProductId == p.productId));

Summing linq data by year

I've seen dozens of posts similar to this, but I just can't get it to work.
Using asp.net MVC framework, I have a table named Contributions that contains a "ContributionDate" column and an "Amount" column. I'm loading the dates and amounts to display in a chart:
var results = db.Contributions.Where(c => c.Amount > 0);
ArrayList xValue = new ArrayList();
ArrayList yValue = new ArrayList();
results.ToList().ForEach(c => xValue.Add(c.ContributionDate));
results.ToList().ForEach(c => yValue.Add(c.Amount));
The above works. Now I'd liked to sum (i.e., total) the Amounts for each year. I've seen examples that are similar to the following, but I'm clearly clueless (in this example, the compiler doesn't like the "c.ContributionDate" in the new{} statement):
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate )
.Select(c => new {Amount = c.Sum(b => b.Amount), Date=c.ContributionDate});
Thanks for your help!
When you perform a GroupBy, the key by which you're grouping elements is represented by the Key property.
Try this:
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate )
.Select(c => new { Amount = c.Sum(b => b.Amount), Date = c.Key });
But this will group items by the entire ContributionDate value, not just by the year. To do that, you'd have to do something like this:
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate.Year)
.Select(c => new
{
Amount = c.Sum(b => b.Amount),
Date = new DateTime(c.Key, 1, 1)
});
But since this appears to be Entity Framework, you probably need to use the CreateDateTime function:
using System.Data.Entity;
...
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate.Year)
.Select(c => new
{
Amount = c.Sum(b => b.Amount),
Date = EntityFunctions.CreateDateTime(c.Key, 1, 1, 0, 0, 0)
});

Entity Framework query syntax

I having a trouble with a query
I need to take out the SHIPMENT from GetAllOrderData - the same place where you can find POD_DATE and RECEIVE_NAME...but I get an error
Error 1 The name 'x' does not exist in the current context
My code is:
public IEnumerable<ReportItemDTO> GetTaskProgress(DateTime targetDate)
{
try
{
var startDate = targetDate.Date;
var endDate = startDate.AddDays(1);
OrderDataRepository rep = new OrderDataRepository();
var query = rep.GetAllOrderData()
.Where(x => x.POD_DATE >= startDate && x.POD_DATE <= endDate)
.GroupBy(o => o.User)
.Select(g => new ReportItemDTO
{
DriverId = g.Key.Id,
PdriverName = g.Key.Name,
OrderCount = g.Count(),
ReportedOrdersCount = g.Count(o => o.RECEIVE_NAME != null),
SHIPMENT = (x.SHIPMENT)
} );
return query;
SHIPMENT = (x.SHIPMENT)
Well you are within a grouping when you try to make that assignment - there are many shipments in each grouping not just one - in fact all shipments for that particular user. Assuming you want a collection of them you could do:
Shipments = g.Select( x=> x.SHIPMENT)
Edit:
If you just want the first shipment for each user (somewhat illogical but fits your data model):
SHIPMENT = g.Select( x=> x.SHIPMENT).First()

Resources