How to Query and count an Employees table and Project table in one linq query in silverlight? - linq

I have two tables an employee table and a project table and I am looking to bring back a count of the number of employees assigned to each project. In the employee table I have employeeIDs and projectIDs, and in the projects table I have projectID, name, department, notes, etc. I am looking to bring back the following information and display it in one single DataGrid in silverlight with the number of employees assigned to each project as a Count.
Name Department Notes Count

There are many ways to do this, but the simplest is probably to do it like this:
var x =
from proj in db.Projects
select new
{
Name = proj.Name,
Department = proj.Department,
Notes = proj.Notes,
Count = db.Employees.Where(emp => emp.ProjectID == proj.ProjectID).Count()
};
Alternatively, if you created a foreign key between Projects and Employees on ProjectID (if not, you should strongly consider doing so), LINQ will kindly provide even cleaner syntax:
var x =
from proj in db.Projects
select new
{
Name = proj.Name,
Department = proj.Department,
Notes = proj.Notes,
Count = proj.Employees.Count()
};
It doesn't get any better than that!

I think you want something like this....
dbContext dbCon = new dbContext();
var projects = from project in dbCon.Projects
join employee in dbCon.Employees on project.ProjectID equals employee.projectid
group employee by new { employee.projectid, project.Name, project.Department, project.Notes } into grouping
select new {
//projectID = grouping.Key.projectid,
projectName = grouping.Key.Name,
projectDepartment = grouping.Key.Department,
projectNotes = grouping.Key.Notes,
count = grouping.Count()
};

Related

LINQ Left Outer Join only the first record

I'm working on a LINQ query that joins three tables. For the Orders and OrderInfo table I expect a single record in each table for a given order id. However for the ShipRate table, there could be 0, 1 or more records for a given order id. So for this table I am using a left outer join. The query shown below is working if 0 or 1 records exist in the ShipRate table, but for instances where the number of records is > 1, I need to select only the most recent ShipRate record. I tried to do this by replacing the line:
from shipRate in sr.DefaultIfEmpty()
with this:
from shipRate in sr.OrderByDescending(r => r.CreateDate).Take(1).DefaultIfEmpty()
but the query takes forever, as if it is loading the entire ShipRate table. Where have I gone wrong?
var query = (from order in db.Orders
join info in db.OrderInfo
on order.OrderId equals info.OrderId
join shipRate in db.ShipRate
on info.OrderId equals shipRate.OrderId
into sr
from shipRate in sr.DefaultIfEmpty()
where order.OrderId == orderId
select new
{
OrderId = order.OrderId,
OrderDetail = info.OrderDetail,
Carrier = shipRate.Carrier
}).SingleOrDefault();
With a proper model definition your query would be like:
var query = (from order in db.Orders
where order.OrderId == orderId
select new
{
OrderId = order.OrderId,
OrderDetail = order.OrderInfo.OrderDetail,
Carrier = order.OrderInfo.ShipRates.OrderBy(sr =>sr.CreateDate).FirstOrDefault()
}).SingleOrDefault();
I can't be sure though, because you didn't supply sample data and model.
Cetin Basoz's answer is a good one: ideally you'd set up your model in a way that allows you to use navigation properties. If you're using a model generated from your database schema, that typically means setting up foreign and primary keys properly.
If you can't do that, you should still be able to get a similar effect by writing SQL like this:
var query = (from order in db.Orders
where order.OrderId == orderId
let orderInfo = db.OrderInfo.FirstOrDefault(info => order.OrderId == info.OrderId)
let currentShipRate = db.ShipRate
.Where(shipRate => info.OrderId == shipRate.OrderId)
.OrderByDescending(shipRate => shipRate.CreateDate)
.FirstOrDefault()
select new
{
OrderId = order.OrderId,
OrderDetail = orderInfo.OrderDetail,
Carrier = currentShipRate.Carrier
}).SingleOrDefault();
However, LINQ to SQL isn't nearly as good at building advanced queries as Entity Framework, and the symptoms you're describing might be an indication that it's actually doing multiple database round-trips instead of a join. I'd recommend logging the query that you're producing (prior to the .SingleOrDefault()) either by calling .ToString() on the query or by executing your query in LINQPad and clicking on the SQL tab. That might give you a clue as to why the query is misbehaving.
There seems to be a one-to-one relation between Orders and OrderInfos: every Order has exactly one OrderInfo, and every OrderInfo is the info of exactly one Order, namely the Order that the foreign key OrderId refers to.
On the other hand, there seems to be a one-to-many relation between Orders and ShipRates. Every Order has zero or more ShipRates, every ShipRate is a ShipRate of exactly one Order, namely the Order that the foreign key OrderId refers to.
You want several properties of "Orders, each Order with its one and only OrderInfo and its zero or more ShipRates"
Whenever you have a one-to-many relation, and you want "items with their zero or more sub-items", like Schools with their Students, Customers with their Orders, or in your case: Orders with their ShipRates, consider to use one of the overloads of Queryable.GroupJoin
In the other direction: if you want an item with its one and only other item that the foreign key refers to, like Student with the School he attends, Order with the Customer who created the Order, or Order with its one and only OrderInfo, use Queryable.Join.
I mostly use the overload of GroupJoin that has a parameter resultSelector, so I can select exactly what properties I want.
int orderId = ...
var ordersWithShipRates = dbContext.Orders.GroupJoin(dbContext.ShipRates,
order => order.Id, // from every Order take the primary key
shipRate => shipRate.OrderId, // from every ShipRate take the foreign key to Order
// parameter resultSelector: from every Order, with its zero or more ShipRates
// make one new
(order, shipRatesOfThisOrder) => new
{
// Select the Order properties that you plan to use:
Id = order.Id,
Date = order.Date,
...
ShipRates = shipRatesOfThisOrder.Select(shipRate => new
{
// Select the ShipRate properties that you plan to use:
Id = shipRate.Id,
Value = shipRate.Value,
...
})
.ToList(),
// A simple join to get the one and only OrderInfo
OrderInfo = dbContext.OrderInfos.Where(orderInfo => orderInfo.Id == order.Id)
.Select(orderInfo => new
{
// Select the orderInfo properties that you plan to use
Name = orderInfo.Name,
...
})
.FirstOrDefault(),
});

LINQ select row with max value after group by

I have following sql statement:
Select
tsl.Transaction_Id,
tsl.State_Id,
MAX(tsl."Timestamp")
from TransactionStatesLog tsl
group by tsl.Transaction_Id
How this statement can be translated to LINQ? I just want to select the whole row, where Timestamp is maximum of the group.
With this code i am able just to select TransactionId and max Timestamp from the group.
var states = (from logs in _context.TransactionStatesLog
group logs by new { logs.TransactionId } into g
select new
{
TransactionId = g.Key,
Timestamp = g.Max(x => x.Timestamp)
}).ToList();
I am working with ef core 3.1
Assuming you forgot to add tsl.State_Id to your SQL as grouping key as follows(otherwise that SQL does not work either):
Select
tsl.Transaction_Id,
tsl.State_Id,
MAX(tsl."Timestamp")
from TransactionStatesLog tsl
group by tsl.Transaction_Id, tsl.State_Id
If I understood you correctly you need to add StateId to grouping statement as well so that you will be able to select StateId and TransactionId.
So this should work:
var states = (from logs in _context.TransactionStatesLog
group logs by new { logs.TransactionId, logs.StateId } into g
select new
{
TransactionId = g.Key.TransactionId,
StateId = g.Key.StateId,
Timestamp = g.Max(x => x.Timestamp)
}).ToList();
See: Group by with multiple columns using lambda

How to perform LINQ To SQL for Database in Windows Phone

Say, I have the following tables in SQLCe Database:
Table Country Table Cities
----------- -------------
Pkey countryname Pkey Fkey cityname
1. USA 1. 1. LA
2. Canada 2. 2. Toronto
3. 1. NYC
4. 1. Chicago
Here the code to get the cities:
public IList GetCities(){
IList cityList = null;
using (CountryDataContext context = new CountryDataContext(ConnectionString))
{
IQueryable query = from c in context.Cities select c;
cityList = query.ToList();
}
return cityList;
}
Questions are :
How do I select using normal Select-statement : Select cityname where country = USA?
How do I select the country and get the primary key ?
Select ID, Countryname
then, I can pass the Pkey and do a select again
Select cityname where Fkey = "1";
would apreciate any help or sample on LinqToSQL for normal Databse operation.
Thanks
This should get you your first question:
var query = from c in context.Cities
join y in context.Country
on c.Pkey equals y.Fkey
where y.countryname.Equals("USA")
select c.cityname;
I'm not sure I understand what you're asking in the second question, but I think this may be it:
var query = from c in context.Cities
join y in context.Country
on p.Pkey equals y.Fkey
where y.Pkey.Equals(1)
select new
{
c.Pkey,
c.cityname
};

LINQ: Inner join to the First row in a sub query?

I have two classes, basically one holds Members and the other Sessions.
They are joined together with a common field called "name". There is one member but can be many Sessions.
So if I do a standard join I get back 1 member and many sessions. I just want to get back the first row of sessions.
The session has field called SessioEndTime. So I need to order by DESC on this to pick out the first record.
This is my linq; I have returns too many. I think I need a subquery but I am a little confused.
var sessions = from m in this.members
join s in this.sessions
on m.Name equals s.Name
select new { MemberName = m.Name, SessionTime = s.SessioEndTime};
Edit
To make it clear, imagine I have five members, each member has NUMEROUS sessions. I just wish to receive my five members but with only one session each, that session is the LATEST session which can be got from the SessioEndTime.
Try this:
var sessions =
from m in this.members
join s in
(
from se in this.sessions
group se by se.Name into g
select new {Name = g.Key, SessioEndTime = g.Max(a=>a.SessioEndTime)}
)
on m.Name equals s.Name
select new { MemberName = m.Name, SessionTime = s.SessioEndTime}

Linq databinding issue....data doesnt show up in gridview ...I get the message that number and name field are not found in the data source

List<Emp> employees = new List<Emp>();
Emp e1 = new Emp();
e1.number = 2;
e1.name = "Dinesh";
employees.Add(e1);
Emp e2 = new Emp();
e2.number = 3;
e2.name = "Vishal";
employees.Add(e2);
var query = from n in employees
orderby n.name descending
select n;
GridView1.DataSource = query;
GridView1.DataBind();
You should try to debug the situation as possibly some settings in GridView are not exactly matching DataSource.
Easily you could bind your grid in design time to type Emp, which would generate all the columns for you:
In YourGridFile.Designer.cs add:
this.GridView1.AutoGenerateColumns = true;
this.GridView1.DataSource = typeof(Emp);
somewhere before ResumeLayout lines.
Then you will be able to compare what you have set up manually and what should be in columns definitions.

Resources