Error in SQL to LINQ conversion, how to solve that? - sql

I have a SQl query working fine, I need to convert it to LINQ and got some problems.
My working SQL query:
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
where d.UserID = 2
/* friends */
Union
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
join Friends as fr
on d.UserID = fr.FriendID
where fr.UserID = 2
/* following */
Union
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
join Followers as fl
on d.UserID = fl.UserID
where fl.FollowerID = 2
/* ordenando por UpdateTime desc */
order by 3 desc
What I tried based on my own previous question:
var friends = (from u in db.User
join f in db.Friends
on u.ID equals f.FriendID
where f.UserID == userset.ID
orderby u.Nickname
select new FriendsSet { ID = u.ID, Nickname = u.Nickname, Thumbnail = u.Thumbnail }).ToList();
var followers = (from u in db.User
join f in db.Followers
on u.ID equals f.FollowerID
where f.UserID == userset.ID
orderby u.Nickname
select new FriendsSet { ID = u.ID, Nickname = u.Nickname }).ToList();
var diaryPosts = (from d in db.DiaryPosts
join e in db.EstadosDeAlma
on d.EstadosDeAlmaID equals e.ID
join u in db.User
on d.UserID equals u.ID
where d.UserID == userset.ID
select new DiaryPostsSet {
PostID = d.ID,
EstadoDeAlmaID = e.ID,
EstadoDeAlma = e.Title,
Author = u.Nickname,
Thumbnail = u.Thumbnail,
UserID = u.ID,
IsDuplicated = d.IsDuplicated,
FriendID = d.FriendID,
FriendName = u.Nickname,
Time = d.UpdateTime,
MessagesCount = d.FriendMessages.Count(m => m.DiaryPostsID == d.ID)
}).Take(6).ToList();
var diaryPostsUnion = diaryPosts.Union(friends).Union(followers).OrderBy(d => d.UpdateTime);
The errors I get:
'System.Collections.Generic.List<MvcWebRole1.Models.DiaryPostsSet>' does not contain a definition for 'Union' and the best extension method overload 'System.Linq.ParallelEnumerable.Union<TSource>(System.Linq.ParallelQuery<TSource>, System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments
Instance argument: cannot convert from 'System.Collections.Generic.List<MvcWebRole1.Models.DiaryPostsSet>' to 'System.Linq.ParallelQuery<MvcWebRole1.Models.FriendsSet>'

You're trying to union a sequence of one type with a sequence of another type. That doesn't make sense - unions have to be over the same types, basically.
It's not really clear what you're trying to do here, but I suspect you don't want a union.
Oh, and if you want all of this to happen in the database, get rid of the ToList calls.
EDIT: Okay, it's hard to see exactly how your LINQ queries correspond to your SQL queries, but basically your "select" clauses should be something like:
from d in db.DiaryPosts
// stuff here
select new { UserID = d.ID, d.UpdateTime, d.Content }
Use the exact same anonymous type in each query - the same property names and types, in the same order - and you should be able to use the Union method.

Related

Select clause inside IN with TypeORM

I have a pretty simple sql query:
select * from comments c
inner join users u on u.id = c.user_id
where user_id = 1 OR (c.user_id IN (select user_id_one from friends f where user_id_two = 1))
I am having a lot of trouble getting this translated into TypeORM, specifically this part:
c.user_id IN (select user_id_one from friends f where user_id_two = 1)
No where is it clear on how to use the IN operator along with a inner select statement.
You can add a Where statement and inside that add something like this:
query.where((queryBuilder: SelectQueryBuilder<YOUR_ENTITY>) => {
queryBuilder.where('alias.id in' +
queryBuilder.subQuery()
.select('a.id')
.from(YOUR_ENTITY, 'a')
.getQuery(),
)
})
// ...

SQL to Linq converting using where in contains

I have written this SQL statement:
select id,ProductAbbr
from Product
where id in (Select max(id) from Product group by ProductAbbr)
My linq query is :
var prod = (from t in _context.Product
group t by t.ProductAbbr
into g
select new
{
Id = (from t2 in g select t2.Id).Max()
}).ToList();
// int idlist = Int32.Parse(prod);
var request = (from p in _context.Product
where(p => prod.Contains(p.Id))
select new
{
p.Id, p.ProductAbbr
}).ToList().Distinct();
I get this error
CS0136 C# A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
Isn't it just
var prod = (from t in _context.Product
group t by t.ProductAbbr
into g
select new
{
Id = (from t2 in g select t2.Id).Max()
}).ToList();
//int idlist = Int32.Parse(prod);
var request = (from p in _context.Product
join p1 in prod on p1.Id equals p.Id
select new
{
p.Id,
p.ProductAbbr
}).ToList().Distinct();
?
Note that I have changed
where(p=> prod.Contains(p.Id))
To
join p1 in prod on p1.Id equals p.Id
Note that this will make your query syntaxically valid, but it seems to also be possible to rework it in many other ways according to what I see.
The second query doesn't seem to bring anything useful, at least in your example.

HQL Query to check if size of collection is 0 or empty

I try to generate a HQL query that include user with a empty appoinment collections(mapped by OneToMany):
SELECT u FROM User u JOIN u.appointments uas WHERE u.status = 1 AND (uas.time.end < :date OR size(uas) = 0)
I tries it on several manners (NOT EXIST ELEMENT(), IS NULL)
also see: How to check if the collection is empty in NHibernate (HQL)? (This doesn't work for me)
but still not the result I want to see or some error in HQL or SQL SERVER
Note:
the query without the JOIN works:
"FROM User u WHERE u.status = 1 AND size(u.appointments) = 0"
Solved
Another JOIN solved the problem:
SELECT u FROM User u LEFT JOIN u.appointments pas1 LEFT JOIN pas1.slot t WHERE u.status = 1 AND t.end <= :date1 OR t.end IS NULL ORDER BY u.name asc
Using IS EMPTY should work (I would favor a JPQL syntax):
SELECT u FROM User u WHERE u.status = 1 AND u.appointments IS EMPTY
If it doesn't, please show the generated SQL.
References
Hibernate Core Reference Guide
14.10. Expressions
JPA 1.0 specification
Section 4.6.11 "Empty Collection Comparison Expressions"
Have you taken a look at your generated SQL? Your method works fine here:
// Hibernate query:
const string hql = "from User u where u.Id = 101 and size(u.Appointments) = 0";
// Generates this working SQL:
select user0_.Id as Id20_,
user0_.Name as Name2_20_
from User user0_
where user0_.Id = 101
and (select count(appointment1_.Id_Solicitud)
from Appointment appointment1_
where user0_.Id = appointment1_.Id_User) = 0
// Hibernate query:
const string hql = "from User u where u.Id = 101 and size(u.Appointments) = 0";
The following query will work. The trick is using the LEFT join.
SELECT u FROM User u LEFT JOIN u.appointments uas
WHERE u.status = 1 AND
(uas.time.end < :date OR size(u.appointments) = 0)

How to convert multiple SQL left joins to Linq-To-SQL

I have a user table, a user_items table, a user_to_group table and a group table.
How would I convert the following SQL query to the correct Linq-to-sql query?
select user.username, user.email, user_items.item_number, item_types.desc, [group].name from user
left join user_items on user.user_id = user_items.user_id
left join item_types on user_items.item_type_id = item_types.item_type_id
left join user_to_group on user.user_id = user_to_group.user_id
left join [group] on user_to_group.group_id = [group].group_id
I have tried using group joins and joining with DefaultIfEmpty, but I'm unable to return the exact same results as my SQL query.
Thank you.
#ChrisF,
Sure, I could break it down into:
select user.username, user.email, user_items.item_number from user
left join user_items on user.user_id = user_items.user_id
Which I have in linq2sql as:
var users = (from u in db.users
join ui in db.user_items on u.user_id equals ui.user_id into useritems from ui in useritems.DefaultIfEmpty()
select new { user = u, item_number = useritems == null ? string.Empty : useritems.FirstOrDefault().item_number});
However, it still doesn't return all the results it should, and I can't see where I'm going wrong.
You will need to look at the join ... into ... construct.
Here is an example on MSDN
... Something else to consider ...
LINQ will allow you to turn your simple table structure into a complex hierarchy. Another option beyond the left joins would be nested queries. Maybe something like this...
var selected = from user in users
select new
{
user,
items = from item in user_items
where item.user_id == user.user_id
join it in item_types
on item.item_type_id equals it.item_type_id
select it,
groups = from ug in user_to_groups
where ug.user_id == user.user_id
join #group in groups
on ug.group_id equals #group.group_id
select #group.name,
};
I found my problem, I was selecting
useritems.FirstOrDefault().item_number
Which is what I selected into (and FirstOrDefault!), instead of what I used for my join:
ui.item_number
So my complete linq query is
var users = (from u in db.users
join ug in db.user_to_groups on p.user_id equals pg.user_id into pgrp
from ug in pgrp.DefaultIfEmpty()
join g in db.groups on pg.group_id equals g.group_id into groups
from g in groups.DefaultIfEmpty()
join ui in db.user_items on u.user_id equals ui.user_id into useritems
from ui in useritems.DefaultIfEmpty()
select new { user = u, item_number = ui == null ? string.Empty : ui.item_number, usergroup = g == null ? string.Empty : g.name});
Thanks for the help!
You query could be written more tersely if you define some associations between your objects:
from u in db.Users
from ug in u.User_To_Groups.DefaultIfEmpty()
let g = ug.Group
from ui in u.UserItems.DefaultIfEmpty()
select new
{
user = u,
item_number = ui == null ? string.Empty : ui.item_number,
usergroup = g == null ? string.Empty : g.name
});

LEFT OUTER JOIN in Linq - How to Force

I have a LEFT OUTER OUTER join in LINQ that is combining with the outer join condition and not providing the desired results. It is basically limiting my LEFT side result with this combination. Here is the LINQ and resulting SQL. What I'd like is for "AND ([t2].[EligEnd] = #p0" in the LINQ query to not bew part of the join condition but rather a subquery to filter results BEFORE the join.
Thanks in advance (samples pulled from LINQPad) -
Doug
(from l in Users
join mr in (from mri in vwMETRemotes where met.EligEnd == Convert.ToDateTime("2009-10-31") select mri) on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
where l.LastName.StartsWith("smith") && l.DeletedDate == null
select g)
Here is the resulting SQL
-- Region Parameters
DECLARE #p0 DateTime = '2009-10-31 00:00:00.000'
DECLARE #p1 NVarChar(6) = 'smith%'
-- EndRegion
SELECT [t2].[test], [t2].[MAHCPID] AS [Mahcpid], [t2].[FirstName], [t2].[LastName], [t2].[Gender], [t2].[Address1], [t2].[Address2], [t2].[City], [t2].[State] AS [State], [t2].[ZipCode], [t2].[Email], [t2].[EligStart], [t2].[EligEnd], [t2].[Dependent], [t2].[DateOfBirth], [t2].[ID], [t2].[MiddleInit], [t2].[Age], [t2].[SSN] AS [Ssn], [t2].[County], [t2].[HomePhone], [t2].[EmpGroupID], [t2].[PopulationIdentifier]
FROM [dbo].[User] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[MAHCPID], [t1].[FirstName], [t1].[LastName], [t1].[Gender], [t1].[Address1], [t1].[Address2], [t1].[City], [t1].[State], [t1].[ZipCode], [t1].[Email], [t1].[EligStart], [t1].[EligEnd], [t1].[Dependent], [t1].[DateOfBirth], [t1].[ID], [t1].[MiddleInit], [t1].[Age], [t1].[SSN], [t1].[County], [t1].[HomePhone], [t1].[EmpGroupID], [t1].[PopulationIdentifier]
FROM [dbo].[vwMETRemote] AS [t1]
) AS [t2] ON ([t0].[MAHCPID] = [t2].[MAHCPID]) AND ([t2].[EligEnd] = #p0)
WHERE ([t0].[LastName] LIKE #p1) AND ([t0].[DeletedDate] IS NULL)
ORDER BY [t0].[LastName], [t0].[FirstName]
I'm not sure if it will change the result set with "AND ([t2].[EligEnd] = #p0" as part of the subquery rather than the join condition. One thing I like to do with complex queries might help you here. I like to break them into smaller queries before combining them. The deferred execution of LINQ lets us do multiple statements with one eventual call to the database. Something like this:
var elig = from mri in vwMETRemotes
where met.EligEnd == Convert.ToDateTime("2009-10-31")
select mri;
var users = from l in Users
where l.LastName.StartsWith("smith")
where l.DeletedDate == null
var result = from l in users
join mr in elig on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select g
Breaking it down like that can make it easier to debug, and perhaps it can tell LINQ better what you intend.
Code ended up looking like this. RecodePopulation and RecordRegistration are just methods to translate values from the query.
var elig = from mri in db.MetRemote
where mri.EligEnd == Convert.ToDateTime(ConfigurationManager.AppSettings["EligibilityDate"])
orderby mri.EligEnd
select mri;
var users = from l in db.Users
where l.LastName.StartsWith(filter)
where l.DeletedDate == null
select l;
var results = (from l in users
join m in elig on l.MahcpId equals m.MAHCPID into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select new UserManage()
{
Username = l.Username,
FirstName = l.FirstName,
LastName = l.LastName,
DateOfBirth = l.DOB,
Gender = l.Gender,
Status = RecodePopulation(g.Population, l.CreatedDate),
UserId = l.Id,
WellAwardsRegistered = RecodeRegistration(l.Id, 1)
}).Distinct().OrderBy(a => a.LastName).ThenBy(n => n.FirstName).Skip((currentPage - 1) * resultsPerPage).Take(resultsPerPage);