Join 3 tables with a lambda expression? - c#

I basically want the following sql query as a lambda expression:
SELECT studentname, coursename, grade
FROM student S, course C, grade G
WHERE S.id = G.studentid AND C.coursecode = G.coursecode AND G.grade<='B';
I am having trouble as I have to join 3 tables together.

Well, that looks something like this as a query expression:
var q = from grade in db.Grades
where grade.grade <= 'B'
join student in db.Students on grade.studentid equals student.studentid
join course in db.Courses on grade.coursecode equals course.coursecode
select new { student.studentname, course.coursename, grade.grade };
(I'd normally use a variable name of query instead of q - I've just used q for formatting purposes here.)
You could translate this into explicit Join calls with lambda expressions, but I'd strongly advise you to use query expressions for complex queries like this.
Note that I've changed the order of the query to allow the "where" clause to be expressed as simply and efficiently as possible. In all likelihood a SQL query planner would optimize it anyway, but for something like LINQ to Objects this would help.

Related

Write an INNER JOIN in LINQ

I have the following SQL query. I would like to know how to write the same query in LINQ and C#.
select ph.Id,p.Id as projInfoId, ph.Title, ph.AdditionalHours, ph.AdditionalCost,
ph.InsertDate, ph.InsertBy, ph.LastUpdateDate, ph.LastUpdateBy, ph.TeamId,
ph.ProjInfoId
from tblTeamType t
join ProjInformation p on t.team_id = p.teamId
join projProject pj on p.projectId=pj.projectId
inner join ProjInfoAdditionalHrs ph on p.teamId = ph.teamId and p.Id = ph.proJinfoid
I think it is easier to translate SQL using query comprehension syntax instead of lambda syntax.
General rules:
Translate inner queries into separate query variables
Translate SQL phrases in LINQ phrase order
Use table aliases as range variables, or if none, create range
variables from table names abbreviations
Translate IN to Contains
Translate SQL functions such as DISTINCT or SUM into function calls
on the entire query.
Create anonymous objects for multi-column grouping or joining
Using these rules, you should get something like:
var ans = from t in tblTeamType
join p in ProjInformation on t.team_id equals p.teamId
join pj in projProject on p.projectId equals pj.projectId
join ph in ProjInfoAdditionalHrs on new { p.teamId, p.Id } equals new { ph.teamId, ph.proJinfold }
select new {
ph.Id,
projInfoId = p.Id,
ph.Title,
ph.AdditionalHours,
ph.AdditionalCost,
ph.InsertDate,
ph.InsertBy,
ph.LastUpdateDate,
ph.LastUpdateBy,
ph.TeamId,
ph.ProjInfoId
};

Concatenating a LINQ (To SQL) Query

I am building a LINQ query, which will have comparisons attached to the 'where' section (the number of these comparisons depends on the user's selections).
In the code-behind, I want something like this:
var builtQuery =
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
where
Here, in between the 'from' and 'select' parts, I will add a number of comparisons (depending on the user's selection of checkboxes).
And Finally:
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
In PHP (using MySQL) I could simply concatenate a number of strings, which make up the query. But, in c#/LINQ To SQL, the query is not a string and so I have no idea how to do this...There were a couple similar questions on SO, but they're not quite the same thing.
Any ideas??
Thanks!
I would do it in the following way
var intermediateQuery=
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
and then add some filters considering user input
if(SomeUserProductFilter)
{
var result = intermediateQuery.Where(p=>p.ProductName = 'UserProductName');
}
Do not be afraid that this approach will retrieve all data and than filters it in memory. LINQ sends query to database only when you call ToList(), ToArray() or use result in foreach loop

Append string to linq-to-sql query

I have a form with some indexes based on a document type.
I want to build my linq-to-sql query based on those index. The user might fill just some indexes or all of then.
I would need somenthing like that
Gedi.Models.OperacoesModel.indexMatrix[] IndexMatrixArr = (from a in context.sistema_Documentos
join b in context.sistema_Indexacao on a.id equals b.idDocumento
join c in context.sistema_Indexes on a.idDocType equals c.id
join d in context.sistema_DocType_Index on c.id equals d.docTypeId
where d.docTypeId == idTipo and "BUILT STRING"
orderby b.idIndice ascending
select new Gedi.Models.OperacoesModel.indexMatrix {
idDocumento = a.id,
idIndice = b.idIndice,
valor = b.valor
}).Distinct().ToArray();
This built string should be buit early in the code something like
field1 == a and field2 == b
Is this possible?
Your goal is to create expression dynamicaly, as far as I can see. And there are no way just to put string in linq query and make it work in simple linq world - that's the bad news. But I also have a good news for you - there are some way exist to create your query dynamicaly:expression tree, dynamic LINQ.

LINQ Group by and having where clause

Below is the SQL Query I am trying to translate
SELECT dbo.Contracts.Supplier
FROM dbo.Contracts INNER JOIN dbo.Products ON dbo.Contracts.Product = dbo.Products.Product
where dbo.Products.ProductGroup='Crude'
GROUP BY dbo.Contracts.Supplier
Am I doing something wrong because I do not get same results with the following LINQ
var result = from c in context.Contracts
join p in context.Products on c.Product equals p.Product1
where p.Product1.Equals("Crude")
group c by c.Supplier into g
select new { supplier = g.Key };
It is generating a weird statement
SELECT
1 AS [C1],
[Distinct1].[Supplier] AS [Supplier]
FROM ( SELECT DISTINCT
[Extent1].[Supplier] AS [Supplier]
FROM [dbo].[Contracts] AS [Extent1]
WHERE N'Crude' = [Extent1].[Product]
) AS [Distinct1]
Using distinct would work but to get same results, LINQ should be generating a statement like so (it's like it is ignoring the join):
SELECT distinct dbo.Contracts.Supplier
FROM dbo.Contracts INNER JOIN dbo.Products ON dbo.Contracts.Product = dbo.Products.Product
where dbo.Products.ProductGroup='Crude'
I'm assuming that you are using 'EntityFramework' or 'Linq To SQL'. If so, you should be able to use navigation properties to navigate to product and filter invalit results out. This way your query might look something like this:
var result = (from c in context.Contracts
where c.Products.Any(p => p.ProductGroup == "Crude")
select c.Supplier).Distinct();
It will automatically convert into correct query (in this case possibly without join even, just using Exists sql keyword) and return distinct suppliers. This is if I understand your objective correctly - you want to obtain all suppliers assigned to contracts that contain product from 'Crude' product group.
Basically you should try to avoid using joins from linq to sql or linq to entities as much as possible when you can use navigation properties. System will probably be better at converting them into specific sql.

Trouble converting a bit of TSQL to LINQ to Entities

Sorry about the vague title, not sure what verbage I should be using. I have a query similar to this (re-worked to save space):
SELECT
*
FROM
Publishers p
INNER JOIN Authors a
ON p.AuthorID = a.AuthorID
INNER JOIN Books b
ON a.BookID = b.BookID
WHERE
p.PublisherName = 'Foo'
ORDER BY
b.PublicationDate DESC
I tried to re-write it as such:
var query =
from publisher in ctx.Publishers
from author in publisher.Authors
from books in author.Books
...
but got the following error:
Error 1 An expression of type 'Models.Books' is not allowed in a
subsequent from clause in a query expression with source type
'System.Linq.IQueryable<AnonymousType#1>'. Type inference failed in the
call to 'SelectMany'.
I can re-write the LINQ to make it work by just joining the tables, as I would in SQL, but I thought I could accomplish what I want to do by their relationships - I'm just a bit confused why I can get publisher.Authors, but not author.Books.
Check that you have a relationship in your DB from Authors to Books.
Try this...
var result = (from pItem in ctx.Publishers
join aItem in ctx.Authors on pItem.AuthorId equals aItem.AuthorId
join bItem in ctx.Books on pItem.BookId equals bItem.BookId
where pItem.PublisherName== "Foo"
select new {
// Fields you want to select
}
).ToList();
i don't know exact relationship of the tables but you can an idea from this one.

Categories