convert Sql with inner select to Linq - c#

How to convert this Sql query to LinQ
SELECT *
FROM
users
JOIN products
ON users.id = products.user_id
WHERE users.id IN (
SELECT id
FROM users
WHERE users.status = 'Online'
)

Well, your sql is too complicated (the subquery is useless), so simplify it, and you'll get an easy linq...
from u in users
join p in products on u.id equals p.user_id
where u.status == "Online"
select new{u, p};
your sql could just be
select *
from users u
join products p on u.id = p.user_id
where u.status = 'Online'

You don't need an inner SELECT at all
SELECT *
FROM
users
JOIN products
ON users.id = products.user_id
WHERE
users.status = 'Online'
Now, converting this to a LINQ query is a piece of cake.
Note: You would need an IN-clause with a nested SELECT if you were querying another table that, when joined, would produce more output rows, because it has an 1 : n relation to one of the tables already included in the query.

I assume you have these entities:
class User {
public int Id { get; set; }
public string Status { get; set; }
public IList<Product> Products { get; set; }
}
class Product {
public int Id { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
which there is a one-to-many relationship from user to product. So we have:
var result =
from user in users
join product in products on user.Id equals product.UserId
where user.Status == "online"
select new { user, product };

Related

Convert complex SQL query to LINQ

Please see my below SQL query and I need to convert it in LINQ, I tried several way but I can not get it working.
This is my SQL query
SELECT SL_Transactions.TransID, SL_Trans_Details.TransDetID AS Expr2, SL_Transactions.PAY, SL_Transactions.Allocated, SL_Debits.INV, SL_Debits.ADR, SL_Debits.RFD
FROM SL_Trans_Details AS SL_DebitDetails LEFT OUTER JOIN
SL_Transactions AS SL_Debits ON SL_DebitDetails.TransID = SL_Debits.TransID RIGHT OUTER JOIN
SL_Trans_Allocation_History ON SL_DebitDetails.TransDetID = SL_Trans_Allocation_History.DebitTransDetID RIGHT OUTER JOIN
SL_Transactions INNER JOIN
SL_Trans_Details ON SL_Transactions.TransID = SL_Trans_Details.TransID ON SL_Trans_Allocation_History.CreditTransDetID = SL_Trans_Details.TransDetID
WHERE (SL_Transactions.PAY = 254)
I have tried below way but not solved yet.
C# class
public class InvoiceReturnValue
{
public int TransID { get; set; }
public int? INV { get; set; }
public int? RFD { get; set; }
}
LINQ Query
var Invoiedata = from SL_DebitDetails in Db.SL_Trans_Details
join SL_Debits in Db.SL_Transactions on SL_DebitDetails.TransID equals SL_Debits.TransID
join SL_Trans_All in Db.SL_Trans_Allocation_History on SL_DebitDetails.TransDetID equals SL_Trans_All.DebitTransDetID
join SL_Trans in Db.SL_Transactions on SL_DebitDetails.TransID equals SL_Trans.TransID
where SL_Trans.PAY == 250
select new InvoiceReturnValue
{
TransID= SL_Trans.TransID,
INV= SL_Debits.INV,
RFD= SL_Debits.RFD
};
Table relation below.

Left Join Linq query conditions not filtering

I'm trying to do a left join that is 1 user record has 1 (if it's there) contact Record associated with it. When this runs, it still pull multiple contacts ignoring my condition of 'where c.RecordType == "USR"'.
public class Users
{
public int Id { get; set; }
... other properties
public Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public int RecordID { get; set; }
public string RecordType { get; set; }
[ForeignKey("RecordID")]
public Users User { get; set; }
}
Linq Query
var query3 = (from c in db1.Contacts
join u in db1.Users
on c.RecordID equals u.Id
into a
from b in a.DefaultIfEmpty(new Models.Users())
where c.RecordType == "USR"
&& b.Lastname.Contains(name)
&& b.Active == 1
select new
{
b.Id,
b.FirstName,
b.Lastname,
b.FullName,
b.Contact
}).ToList();
Any help with where I'm going wrong would be much appreciated.
Thanks,
Adam
You can do a join in linq without using the join keyword. I use the following construct for left joins and do not have any issues.
var query3 = (from c in db1.Contacts
from u in db1.Users.Where(x => c.RecordID == x.Id).DefaultIfEmpty()
where (c.RecordType == "USR")
&& u.Lastname.Contains(name) && (u.Active == 1)
select new
{
u.Id,
u.FirstName,
u.Lastname,
u.FullName,
u.Contact
}).ToList();
As per information in question
1 user record has 1 (if it's there) contact Record associated with it
that means, a user can have zero or more contacts, so you suppose to use User as main entity and then left join on Contacts. Also you should apply Contact type filter during JOIN itself, like below
var query3 = ( join u in db1.Users
from c in db1.Contacts
on new { Record = c.RecordID, Type = c.RecordType } equals new { Record = u.Id, Type = "USR"} into b
from cont in b.DefaultIfEmpty(new Models.Contacts())
where u.Lastname.Contains(name)
&& u.Active == 1
select new
{
u.Id,
u.FirstName,
u.Lastname,
u.FullName,
cont.Contact
}).ToList();

Inner Join Between Many to Many Relationship Models

I have two model like below that are configured as many to many relationship:
public class Permission
{
public int PermissionId { get; set; }
public string PermissionName { get; set; }
public virtual List<Role> Roles { get; set; }
}
public class Role
{
public int RoleId { get; set; }
public string Name { get; set; }
public string ID { get; set; }
public virtual List<Permission> Permissions { get; set; }
}
I want to do an Inner Join with Linq. I can do that easily in SQL since the join table is present there. But how can I do this with linq? Below is what I could do so far:
from pr in Permissions
join role in Roles on pr.Roles.Select(s => s.RoleId).FirstOrDefault() equals role.RoleId
select new { pr.PermissionName, role.RoleId }
As you can see above the FirstOrDefault will ruin the result but other than that I cannot get to compile the query without errors.
Below is the query I am trying to write in Linq:
SELECT P.PermissionName, R.RoleId
FROM Permissions AS P
INNER JOIN PermissionRoles AS PR ON P.PermissionId = PR.Permission_PermissionId
INNER JOIN Roles AS R ON PR.Role_RoleId = R.RoleId
As you can see, an inner join is made with the join table thus query works as expected
Any help is appreciated.
The easiest syntax is
from p in context.Permissions
from r in p.Roles // notice the p !
select new { p.PermissionName, r.RoleId, Role = r.Name, etc... }
EF will produce SQL with the required inner joins.
The fluent equivalent is
Products.SelectMany(p => p.Roles,
(p, r) => new
{
p.PermissionName,
r.RoleId,
...
})
You'll probably agree that the first form, "comprehensive syntax", wins.
var x = from pr in Permissions
from role in Roles
where pr.Roles.Exists(r => r.RoleId == role.RoleId)
select new { pr.PermissionName, role.RoleId };

Force inner join with many-to-many relationship entity framework

I have a many-to-many relationship setup in my database like so:
User
-------
Id (PK, Identity)
First
Last
...various other fields
Skill
-------
Id (PK, Identity)
Description
UserSkill
-----------
UserId (PK, FK on User.Id)
SkillId (PK, FK On Skill.Id)
When I run this LINQ query on the DbContext:
from u in Users
from s in u.Skills
where s.Id == 5
select new
{
u.Id,
s.Description
})
The SQL generated contains all inner joins which is what I want:
SELECT
[Extent1].[UserId] AS [UserId],
[Extent2].[Description] AS [Description]
FROM [dbo].[UserSkill] AS [Extent1]
INNER JOIN [dbo].[Skill] AS [Extent2] ON [Extent1].[SkillId] = [Extent2].[Id]
WHERE 5 = [Extent2].[Id]
However, when I add a simple extra where clause:
from u in Users
from s in u.Skills
where s.Id == 5
&& u.Last == "test"
select new
{
u.Id,
s.Description
})
The SQL generated now uses a sub-query:
[Extent1].[Id] AS [Id],
[Filter1].[Description] AS [Description]
FROM [dbo].[User] AS [Extent1]
INNER JOIN (SELECT [Extent2].[UserId] AS [UserId], [Extent3].[Description] AS [Description]
FROM [dbo].[UserSkill] AS [Extent2]
INNER JOIN [dbo].[Skill] AS [Extent3] ON [Extent3].[Id] = [Extent2].[SkillId]
WHERE 5 = [Extent3].[Id] ) AS [Filter1] ON [Extent1].[Id] = [Filter1].[UserId]
WHERE 'test' = [Extent1].[Last]
Maybe I am missing something, but I would think EF would just add another join back to the User table for this query and be able to do a where on User.Last instead of doing a sub-query. Is there any way to force this kind of behavior? Am I doing something wrong?
Thanks.
UPDATE
Cosmin, I am wanting the query to come out like this:
SELECT u.Id, s.Description
FROM [User] u INNER JOIN
[UserSkill] us ON u.Id = us.UserId INNER JOIN
[Skill] s ON us.SkillId = s.Id
WHERE s.Id = 2 AND u.Last = 'test'
Looks like this is an optimization that EF does not currently do. Personally, I'd stick with the sub query it generates unless performance becomes a problem.
But if you are willing to lose the direct navigation properties for User and Skill, you can model the intermediate table to get the query you are looking for.
public class User
{
public int Id { get; set; }
public string First { get; set; }
public string Last { get; set; }
public virtual ICollection<UserSkill> UserSkills { get; set; }
}
public class UserSkill
{
public int Id { get; set; }
[Required]
public User User { get; set; }
[Required]
public Skill Skill { get; set; }
}
public class Skill
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<UserSkill> UserSkills { get; set; }
}
Then the following query will produce a join instead of subquery
from x in db.UserSkills
where x.Skill.Id == 5 && x.User.Last == "test"
select new {x.User.Id, x.Skill.Description};
#ryanulit, your issue is valid and it is an issue for all Linq to Entities. Please check the posted MS Forum's URL
MS Forum's URL

Retrieving the username from MembershipUser for a join query

I'm newer using C#, linq. I'm trying to add the UserName into a query to show it as part of a DataSource of a ListView, I have tested several way to joined, but always I m'receiving next error:
"Unable to create a constant value of type 'Web.Admin.system.User'. Only primitive types or enumeration types are supported in this context."
My code is:
//Entities
public class Category
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Order
{
public Guid Id { get; set; }
public string Description { get; set; }
public Guid CategoryId { get; set; }
public Guid UserId { get; set; }
}
//class added just for getting the user list (possibly, I do not need)
public class User
{
public Guid Id { get; set; }
public String Name { get; set; }
}
Here is my code preparing the filter
//retrieve the data from Order and Category
IQueryable<Order> orders = orderService.GetAllOrders();
IQueryable<Category> category = categoryService.GetAllCategories();
//obtain the users
MembershipUserCollection members = Membership.GetAllUsers();
// 1st option for managing users directly with memberShip variable
var memberShip = members.Cast<MembershipUser>().ToDictionary(m => m.ProviderUserKey, m => m.UserName).AsQueryable();
// 2nd option, I have added this code to see if I could manage the users as a list
List<User> users = new List<User>();
foreach (var _member in memberShip)
{
users.Add(new User { Id = (Guid)_member.Key, Name = _member.Value });
}
//Getting information to fill a listview
var DDLsource = from i in orders
join c in category on i.CategoryId equals c.Id
join u in users on i.UserId equals u.Id // 1st I tried to use memberShip directly but gave me error of types
select new
{
i.Id,
i.Description,
CategoryName = c.Name,
UserName = u.Name
};
ListViewOrders.DataSource = DDLsource.ToList();
Here is where the Error is triggered, I'm trying to understand the error and do other solution, I tested the query like:
Example 2
var DDLsource = from i in orders
join c in category on i.CategoryId equals c.Id
select new
{
i.Id,
i.Description,
CategoryName = c.Name,
UserName = (from u in users where u.Id == i.UserId select u.Name)
};
Example 3
var DDLsource = from i in orders
join c in category on i.CategoryId equals c.Id
join u in Membership.GetAllUsers().Cast<MembershipUser>() on i.UserId equals ((Guid)u.ProviderUserKey)
select new
{
i.Id,
i.Description,
CategoryName = c.Name,
UserName = u.UserName
};
all with the same results, could someone give me a hand with my mistake will surely be very obvious. Thanks in advance
I would do something like this (sorry, untested code...):
var DDLsource =
from i in orders
join c in category on i.CategoryId equals c.Id
select new
{
i.Id,
i.Description,
CategoryName = c.Name,
i.UserId,
UserName = ""
};
foreach(var ddl1 in DDLsource)
ddl1.UserName = Membership.GetUser(ddl1.UserId).Name;

Categories

Resources