LINQ doesn't work with a "select isnull" query..? [duplicate] - sql

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Equivalent of SQL ISNULL in LINQ?
Using IsNull or select COALESCE in Linq..?
I've tried this query in LINQ:
string query = #"SELECT ISNULL(P.firstname, s.firstname) AS Expr1,ISNULL(P.lastname,
s.lastname) AS Expr2 FROM comment AS C LEFT OUTER JOIN professor AS P ON P.ID =
C.PID LEFT OUTER JOIN student AS s ON s.ID = C.SID
WHERE (C.VID = 2)";
ArrayList allNames=null;
using (var context = new NewsReaderEntities())
{
ObjectQuery<string> results = context.CreateQuery<string>(query);
// ObjectQuery<string> results1 = context.CreateQuery<string>
(query1,parameters);
foreach (string result in results )
{
allNames.Add(result);
}
}
return allNames;
}
but it returns the error:
linq 'ISNULL' cannot be resolved into a valid type or function. Near
simple identifier,
I've also tried this query:
SELECT COALESCE(p.firstname, s.firstname), COALESCE(p.lastname, s.lastname)
FROM comment c
LEFT JOIN Professor p
ON c.pid = p.id
LEFT JOIN Student s
ON c.sid = s.id
WHERE c.vid = 2
This also raises an error.
Both work okay in SQL Management. Any ideas?

See this example:
var query = from p in Pets select p;
if (OwnerID != null) query = query.Where(x => x.OwnerID == OwnerID);
if (AnotherID != null) query = query.Where(x => x.AnotherID == AnotherID);
if (TypeID != null) query = query.Where(x => x.TypeID == TypeID);
Hope this help you

Related

SQL Statement with inner join to LINQ

I need to convert my SQL statement to LINQ.
SELECT
dbo.Transactions.TypeRefID,
dbo.TransactionItems.ItemRefID,
SUM(dbo.TransactionItems.Quantity) AS Qty
FROM
dbo.TransactionItems
LEFT OUTER JOIN
dbo.Transactions ON dbo.TransactionItems.TransactionRefID = dbo.Transactions.TransactionID
GROUP BY
dbo.Transactions.TypeRefID, dbo.TransactionItems.ItemRefID
HAVING
(dbo.Transactions.TypeRefID = 1)
AND (dbo.TransactionItems.ItemRefID = 5)
I tried converting the above statement into LINQ and this is what I've done.
var query = from t in db.Transaction
join i in db.TransactionItem on t.TransactionID equals i.TransactionRefID
where t.TypeRefID == 1 && i.ItemRefID == 5
group i by new
{
t.TypeRefID,
i.ItemRefID
} into g
select new
{
TypeRefID = g.Key.TypeRefID,
ItemRefID = g.Key.ItemRefID,
Quantity = g.Sum(q => q.Quantity)
};
When I run my code I get error "System.Linq.Queryable.FirstOrDefault(...) returned null"
I'm using it like this
if (query != null)
string qty = query.FirstOrDefault().Quantity.ToString();
The error is called on "query.FirstOrDefault().Quantity.ToString()"
How to avoid this error?

Linq to SQL - Query with multiple joins, sum, grouping, having

I have the following query that I would like to translate to linq.
SELECT
SUM(Credits.CreditAmount)
,Transactions.Id
,Person.FullName
,Person.Id
FROM
Person
JOIN
Transactions
ON Person.AccountId = Transactions.AccountId
JOIN Credits
ON Transactions.Id = Credits.TransactionId
WHERE
Person.Type = 'AccountHolder'
AND Person.Status = 'Active'
AND Transactions.CancelledDate IS NULL
AND Credits.CancelledDate IS NULL
GROUP BY Transactions.AccountId, Person.FullName, Person.Id
HAVING SUM(Credits.CreditAmount) > 20
This is what I came up with. It's an absolute pig... The SQL it generates must be awful.
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
let sumC = grp.Select(x => x.CreditAmount).Sum()
select new
{
TotalCredit = sumC,
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
The SQL query runs in approximately 3 seconds but I have yet to find the patience to let the Linq query finish. I was wondering if there is something different I should be doing to accomplish this "group, sum, having" query I'm trying to write? Is there something I can do to help Linq generate more performat SQL?
UPDATE
Turns out sgmoore had the right idea. The key to the performance issue was in his answer.
The difference between this
let sumC = grp.Select(x => x.CreditAmount).Sum()
and this
TotalCredit = grp.Sum(x => x.CreditAmount)
was the difference between a query that finishes and one that does not.
See my revised LINQ query below which completes in about the same time as the SQL (5.3 seconds for SQL vs 5.6 seconds for LINQ).
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
Thanks for all your help!
I don't disagree with WEI_DBA's comment but if you need to do this, then you might find it easier to break this into several queries, eg
var query1 = from p in Person
join t in Transactions on p.AccountId equals t.AccountId
join c in Credits on t.TransactionId equals c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
select new { c.CreditAmount, t.AccountID, p.FullName, p.Id};
var query2 = (from p in query1
group p by new { p.AccountId, p.FullName, p.Id } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
var query3 = (from p in query2 where p.TotalCredit > 20 select p);
Then you can let LINQ combine this into one sql command.
As always, it is a good idea to check and verify the actual TSQL generated.

how to convert left join SQL script to Linq script?

How can I convert left join to linq script. I have a T-SQL like this:
SELECT
es.StandardID,
COUNT(DISTINCT esc.StandardCourseID) AS CourseIDCount,
COUNT(DISTINCT esp.StandardPostID) AS PostIDCount
FROM EduStandards AS es
LEFT JOIN EduStandardCourses AS esc
ON es.StandardID = esc.StandardID
LEFT JOIN EduStandardPosts AS esp
ON es.StandardID = esp.StandardID
GROUP BY es.StandardID
That I want to convert this to linq.
Following is the query with left join that is replica of your query in linq.
var query = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
from esc in ssc.DefaultIfEmpty()
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
from esp in ssp.DefaultIfEmpty()
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() }).Distinct().ToList();
But I think we need not to apply left join in linq to calculate count. Following optimized linq query will return same result.
var query2 = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() });
This is what I've come up with
var query = from es in db.EduStandards
join esc1 in db.EduStandardCourses
on es.StandardId equals esc1.StandardId into esc
from c in esc.DefaultIfEmpty()
join esp1 in db.EduStandardPosts
on es.StandardId equals esp1.StandardId into esp
from p in esp.DefaultIfEmpty()
group new { es.StandardId, Course = c, Post = p } by es.StandardId into g
select new
{
StandardId = g.Key,
CourseIdCount = g.Where(x => x.Course != null).Count(),
PostIdCount = g.Where(x => x.Post != null).Count(),
};
However, I'm not entirely sure if it'll work for EF.
You could always do something like this:
var query = from es in db.EduStandards
select new
{
es.StandardId,
CourseIdCount = db.EduStandardCourses.Where(esc => esc.StandardId == es.StandardId).Distinct().Count(),
PostIdCount = db.EduStandardPosts.Where(esp => esp.StandardId == es.StandardId).Distinct().Count()
};
Also, I can't attest to the performance of either one of these queries due to the lack of knowledge of your database.

Left outter join linq

How do i change the training events into a left outer join in training events im very basic at linq so excuse my ignorance its not retrieve records that don't have any trainnevent reference attached to it
var q = from need in pamsEntities.EmployeeLearningNeeds
join Employee e in pamsEntities.Employees on need.EmployeeId equals e.emp_no
join tevent in pamsEntities.TrainingEvents on need.TrainingEventId equals tevent.RecordId
where need.EmployeeId == employeeId
where need.TargetDate >= startdate
where need.TargetDate <= enddate
orderby need.TargetDat
It's best to use where in combination with DefaultIfEmpty.
See here: LEFT JOIN in LINQ to entities?
var query2 = (
from users in Repo.T_Benutzer
from mappings in Repo.T_Benutzer_Benutzergruppen.Where(mapping => mapping.BEBG_BE == users.BE_ID).DefaultIfEmpty()
from groups in Repo.T_Benutzergruppen.Where(gruppe => gruppe.ID == mappings.BEBG_BG).DefaultIfEmpty()
//where users.BE_Name.Contains(keyword)
// //|| mappings.BEBG_BE.Equals(666)
//|| mappings.BEBG_BE == 666
//|| groups.Name.Contains(keyword)
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
Which is equivalent to this select statement:
SELECT
T_Benutzer.BE_User
,T_Benutzer_Benutzergruppen.BEBG_BE
-- etc.
FROM T_Benutzer
LEFT JOIN T_Benutzer_Benutzergruppen
ON T_Benutzer_Benutzergruppen.BEBG_BE = T_Benutzer.BE_ID
LEFT JOIN T_Benutzergruppen
ON T_Benutzergruppen.ID = T_Benutzer_Benutzergruppen.BEBG_BG

Complex SQL to LINQ conversion with subquery

I am trying to convert this expression into LINQ from SQL, but a bit too difficult for me, maybe you can help me with this!
SELECT TOP (2) RecipeID, UserID, Name, Servings, PreparationTime, TotalTime, DifficultyLevelID, CuisineID, DishID, MainIngredientID, PriceLevelID, FlavourID, Instructions,
Notes, Thumbnail, VideoLink
FROM dbo.Recipes
WHERE (RecipeID NOT IN
(SELECT DISTINCT Recipes_1.RecipeID
FROM dbo.Allergies INNER JOIN
dbo.UsersAllergies ON dbo.Allergies.AllergyID = dbo.UsersAllergies.AllergyID INNER JOIN
dbo.IngredientsAllergies ON dbo.Allergies.AllergyID = dbo.IngredientsAllergies.AllergyID INNER JOIN
dbo.Ingredients ON dbo.IngredientsAllergies.IngredientID = dbo.Ingredients.IngredientID INNER JOIN
dbo.RecipesIngredients ON dbo.Ingredients.IngredientID = dbo.RecipesIngredients.IngredientID INNER JOIN
dbo.Recipes AS Recipes_1 ON dbo.RecipesIngredients.RecipeID = Recipes_1.RecipeID INNER JOIN
dbo.Users ON dbo.UsersAllergies.UserID = dbo.Users.UserID INNER JOIN
dbo.AllergyFactors ON dbo.IngredientsAllergies.AllergyFactorID = dbo.AllergyFactors.AllergyFactorID
WHERE (dbo.Users.UserID = 3) AND (dbo.AllergyFactors.AllergyFactorID < 3)))
It would be easier to help you if you showed us what you have already tried, but a Linq expression like this should give you the same result set
var query = (from rec in context.Recipes
where !(from al in context.Allergies
from ua in context.UsersAllergies.Where(x => al.AllergyID == x.AllergyID)
from ia in context.IngredientsAllergies.Where(x => al.AllergyID == x.AllergyID)
from in in context.Ingredients.Where(x => ia.IngredientID == x.IngredientID)
from ri in context.RecipesIngredients.Where(x => in.IngredientID == x.IngredientID)
from re in context.Recipes.Where(x => ri.RecipeID == x.RecipeID)
from us in context.Users.Where(x => ua.UserID == x.UserID)
from af in context.AllergyFactors.Where(x => ia.AllergyFactorID == x.AllergyFactorID)
where us.UserID == 3 && af.AllergyFactorID < 3
select re.RecipeID)
.Distinct()
.Contains(rec.RecipeID)
select new
{
rec.RecipeID,
rec.UserID,
rec.Name,
rec.Servings,
rec.PreparationTime,
rec.TotalTime,
rec.DifficultyLevelID,
rec.CuisineID,
rec.DishID,
rec.MainIngredientID,
rec.PriceLevelID,
rec.FlavourID,
rec.Instructions,
rec.Notes,
rec.Thumbnail,
rec.VideoLink
}).Take(2);