How do I group my LINQ query correctly? - c#

I am having an issue getting my LINQ query to output as I would like. I am unsure I am taking the right approach.
Tables:
I have two tables Contacts and Permissions with which I perform a LEFT OUTER JOIN.
Join Query:
from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId into permissionGrp
from p in permissionGrp.DefaultIfEmpty()
where (p==null && isAllowed) || (p!=null && /* ... further conditions */))
orderby /* ... ordering removed */
select new { contact, permission = p };
This matches the permissions to a contact where applicable, and null when no matching permission exists.
Desired
I don't wish to have duplicate contacts, I am only interested in the first Contact-Permission record. Like so:
Attempt:
So I assumed that I need to Group By my contact.Id and somehow select FirstOrDefault() on the permissions collection.
from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId into permissionGrp
from p in permissionGrp.DefaultIfEmpty()
where (p==null && isAllowed) || (p!=null && /* ... further conditions */))
orderby /* ... ordering removed */
group p by contact into contactPermissionsGrp
select new { contact = contactPermissionsGrp.Key, permission = contactPermissions.FirstOrDefault() };
Result:
Unfortunately this results in a NotSupportedException: Specific method is not supported.. But I am not sure if my approach is correct or a limitation of the LightSpeed ORM.
Any advise would be appreciated.

Answer question with more questions
Is your query possible in raw SQL in the database you are targeting? If the answer is No then what hope have you of replicating it in LINQ?
I personally don't think that what you are trying to achieve is possible to do via LINQ against MySQL. It would be possible in MS SQL in raw T-SQL by defining an expression and attaching a RANK() column to it then doing a query on that expression.
I feel that your available solutions are:
Find out how to write this query using raw SQL in your native dialect. Lightspeed will let you execute raw SQL and it will even (where you return enough columns) rehydrate that custom query into Entitys (however I don't think that is what you are after in this case).
Give up on reducing the "duplicates" efficiently in the database. Pull the duplicates into memory and then reduce them in memory with LINQ queryies against the IEnumerable set that you get back.
Change your database architecture so you can have a simpler query. Sometimes in situations like this I will find honour in having a column on the Contact table such as "MostSignificantPermssion". That has a number of advantages:
Simpler query to get the Contact and the ONE significant Permission record.
Makes it more obvious to other developers that one of the Permissions has a special significance.
Options!
Appendix - Example of implementing (1) in MS SQL
WITH LastUsagePerPerson AS (
SELECT
ULE.PersonId,
ULE.[Device],
ULE.[AppVersion],
ULE.[CreatedOn],
ROW_NUMBER() OVER(PARTITION BY ULE.PersonId ORDER BY ULE.CreatedOn DESC) AS rk
FROM [dbo].[UsageLogEntry] ULE
)
SELECT
[FirstName]
,[LastName]
,[EmailAddress]
,[EmailAddressUnverified]
,[MobileNumber]
,[MobileNumberUnverified]
,[LastDeviceUsed] = LastUsagePerPerson.Device
,[LastAppVersion] = LastUsagePerPerson.AppVersion
,[LastDeviceUsage] = LastUsagePerPerson.CreatedOn
,[LastLoggedInOn]
FROM [dbo].[Person] P
LEFT JOIN LastUsagePerPerson ON P.Id = LastUsagePerPerson.PersonId
WHERE rk = 1
ORDER BY [Id]

I don't know what Lightspeed can or can't. Try to simplify you LINQ Query
In EF i would do something like this.
from c in Contacts
let p = (from p in permission where p.ObjectId == c.Id select p).FirstOrDefault()
select new { ContactID = c.Id,
Name = c.Name,
Permission = p.PermissionId,
Permitted = p.Permitted};

I have understood what you are trying to get and I have solved your problem,just follow the below code what I did...
select * from contacts as a
left join permissions as b
on a.ContactId = b.ContactId
group by a.ContactId ;
I have got the requeried result using the above code which you were trying to get.Just try that,your problem will be solved.

Related

How to write EF query for Common Table Expression

This Sql query returns the expected data. I need to do the same in EF Query. I am not sure how to do it all in one EF query.
WITH cteproductactions (productkey, actionid) AS (
SELECT productkey, count(*) FROM productactions
GROUP BY productkey
HAVING count(*)>0
)
SELECT p.name,p.productkey,p.imageurl
FROM product p
INNER JOIN cteproductactions c on p.ProductKey=c.productkey
WHERE p.profileid=100
EF Query
var products = productRepo.Where(x => x.profileid=100);
var productkeys = products.Select(x => x.ProductKey).ToList();
var productActions = productActionsRepo.Where(x => productkeys.Contains(x.ProductKey));
You'll tie yourself in knots trying to write an SQL then "converting" it into LINQ or forcing EF to generate an SQL that is the same.. It's better to start from a place where you express what you want in high level (English) and write the LINQ for it; forget the SQL unless there's a real problem
The SQL as written doesn't really make sense, or need a CTE, the HAVING clause is pointless and none of the columns from the CTE are used in the output. The only purpose the CTE serves is to filter the product list down to those that have at least one productkey, so write an EF from that - "all products Where profile is is 100 and a related product key exists" - don't get bogged down in "how do I make EF do a cte?" because these SQL express the same sentiments without a CTE:
SELECT p.name,p.productkey,p.imageurl
FROM product p
INNER JOIN (SELECT DISTINCT productKey FROM productactions) c on p.ProductKey=c.productkey
WHERE p.profileid=100
SELECT DISTINCT p.name,p.productkey,p.imageurl
FROM product p
INNER JOIN productactions c on p.ProductKey=c.productkey
WHERE p.profileid=100
SELECT p.name,p.productkey,p.imageurl
FROM product p
WHERE p.profileid=100
AND EXISTS(SELECT null FROM productactions c WHERE p.ProductKey=c.productkey)
Assuming product and productactions are in a 1:M relationship connected by productKey, consider something like:
var products = productRepo
.Where(p => p.profileid==100 && p.ProductActions.Any())
.Select(p => new {p.Name, p.ProductKey, p.ImageUrl)
Main message here is "don't start from an SQL mindset and think "how can I make EF do this sql", start from a "What do I want and how can I make EF do it" - forget the SQL unless EF is generating something horrifically underperformant.

linq query displaying result twice

pd is my page ;
ProductDetail pd = new ProductDetail();
fetching data and strong it in data
var data =
from product in db.Products
from orders in db.Orders
from od in db.OrderDetails
from dpt in db.Dpts
where orders.CId.Equals(
(from name in db.Companies
where name.Cname.Equals(selectedcomp)
select name.CId).FirstOrDefault())
&& od.OrdId.Equals(orders.OrdId)
&& product.PId.Equals(od.PId)
select new
{
orders.Billno ,
orders.Date,
orders.pharm ,
product.Pname,
product.Purchasedate,
product.Purchaserate,
product.Salesrate,
product.Supplier,
od.Quantity,
od.Amount
};
it displays the value of data twice in listbox.
pd.ProductDescription.ItemsSource =
(from dat in data
select dat).ToList();
I think your problem is the cross join to the Dpts table. You don't use the results from that table in the where or select, so I don't think you need it. Try removing from dpt in db.Dpts and see if that fixes your problem. My guess is that you are getting n duplicates where n is the total number of rows in db.Dpts.
#juharr is right. You don't use db.Dbts in where clause, so you cross join duplicates results. Probably in db.Dbts table you have 2 records.
I think that you should work on your query.
Few tips:
We don't use cross joins, rather we use join statement
You should get CId before executing your main query
Probably You don't have foreign keys in your database, you should consider that
When getting duplicate items from a query in LINQ or SQL, first check for bad data, then investigate it as a bad join. Your best bet is to strip it down to one table, then add the joins in one-by-one until you get your duplication. Then make that join specific enough that it stops duplicating.

Simple Example Subquery Linq

T-SQL Query
Select * from dbo.User_Users
Where UserID IN (Select UserID from Course_Enrollments)
LINQ to Entities alternative of Above Query
var innerquery = from en in Course_Enrollments
select en.UserID;
var query = from u in User_Users
where innerquery.Contains(u.UserID)
select u;
There are alot of complex subqueries on stackoverflow, i just want to see a simple example of how a simple subquery is done via linq.This is how i done it, however its not good because it sends 2 queries to the database.
Simple answer is use the "let" keyword and generate a sub-query that supports your conditional set for the main entity.
var usersEnrolledInCourses = from u in User_Users
let ces = from ce in Course_Enrollments
select ce.UserID
where ces.Contains(u.UserID)
select u;
This will create an exists block in TSQL similar to
SELECT [Extent1].*
FROM dbo.User_Users AS Extent1
WHERE EXISTS (SELECT 1 AS [C1]
FROM dbo.Course_Enrollements AS Extent2
WHERE (Extent2.UserID = Extent1.UserId))
It's close to what you've asked for and will generally create the same query plan on SQL Server.
Hope this helps!
from u in User_Users
where u.Course_Enrollments.Any()
select u
if you have the foreign keys set up. If not you can do this
from u in User_Users
join cu in Course_Enrollments on u.UserId equals cu.UserId
select u
You also should wrap any of these with .Distinct() call

Linq to Entities many to many selection: How to force the generation of a JOIN instead of a subselect clause?

Using EF DB first I have two entities (Supplier, Product) that have a many-to-many relationship. Entity Framework does not create an entity for the associated table (SupplierProduct) as the associated table contains only the primary keys of the strong entities.
I have been getting all Suppliers that do not supply a given product with the following query:
var q1 = context.Suppliers.Where(s=>!s.Products.Any(p=>p.Id == 1));
The SQL produced uses an EXISTS dependent subquery similar to this:
SELECT *
FROM Suppliers s
WHERE NOT EXISTS
(SELECT 1
FROM SupplierProduct sp WHERE sp.SupplierId = s.Id && sp.ProductId = 1)
Is it possible, using Linq to Entities method syntax, to produce a query that uses joins on the associated table instead?
ie:
SELECT DISTINCT s.*
FROM SupplierProduct sp
JOIN Supplier s ON s.Id = sp.SupplierId;
WHERE sp.ProductId != 1
Update
As pointed out by JoeEnos my queries above don't do the same thing. The NOT EXISTS subquery is probably the best way to go here. What if I was trying to get all suppliers who did supply a product? I would change my linq to entities query slightly to:
var q1 = context.Suppliers.Where(s => s.Products.Any(p=>p.Id == 1));
And the SQL generated would be:
SELECT *
FROM Suppliers s
WHERE EXISTS
(SELECT 1
FROM SupplierProduct sp WHERE sp.SupplierId = s.Id && sp.ProductId = 1)
Which is fine, I get the result I want. However if I was writing SQL in this case I would normally do:
SELECT s.*
FROM SupplierProduct sp
JOIN Supplier s ON s.Id = sp.SupplierId;
WHERE sp.ProductId = 1
Can my linq to entities query be changed to produce the above SQL?
To generate SQL where a join is used instead of EXISTS when selecting an entity based on its m:n association with another entity SelectMany() can be used. Eg:
var q1 = context.Suppliers.Where(s => s.Products.Any(p=>p.Id == 1));
Can be rewritten to:
var q1 = context.Products.Where(p => p.Id == 1).SelectMany(p => p.Suppliers);
Your two queries do very different things. Your Any/EXISTS query gets suppliers who do not have product 1 at all. Your JOIN query gets all suppliers who have any products other than 1, regardless of whether or not they also have product 1.
I don't think you can do what you're looking for with just a JOIN and WHERE - you can do it with an IN clause, but I think the EXISTS query is the most correct way of looking for your data.
In any case, one of the wonderful things about Entity Framework is that you don't have to worry about what gets generated - as long as the LINQ statement is ok, then it will find the best way of writing the query, and you should never have to look at it. That's especially true when you do paging and other things like that, where the LINQ is simple, but the generated SQL is horribly ugly.

How to determine whether to use join in linq to sql?

I am just wondering about how we can determine whether to use join or not in linq to sql.
Eg. let say if we have two tables like this
Table 1 Customer
id
name
Table 2 addresstype
id
address1
customerid
and
var address = from cu in Customer
from ad in addresstype
where cu.id == ad.customerid
select ad;
or
var address = from cu in Customer
join ad in addresstype on cu.id equals ad.customerid
select de;
Is both way are the same. Is there any difference in performance?
Also the second method, will it come up with an error if there isn’t any matching?
Are you using linq to entities or linq to SQL? If its the former then you can avoid both of these by defining your relationships in the model and using navigation properties. This would be the clearest way of doing things
Basically, these two LINQ queries are equivalent to the following SQL queries:
select ad.*
from Customer cu, AddressType ad
where cu.ID == ad.CustomerID -- I assume this was meant by the OP
and
select ad.*
from Customer cu
inner join AddressType ad on cu.id = ad.CustomerID;
The difference between these two queries is mostly semantic, since the database will do the same thing in both cases and return a same result set for both queries.
I would prefer the join syntax in both SQL and LINQ since it defines an explicit relationship between the two tables/entities, that is only implied in the join-less version.
These are seems same query, they return same result but I don't know which one can be a faster, it should be bench marked.
But, In the case of linq2sql I prefer correlated subquery over join, because currently if you want t check the equation two element you should use syntax of:
new {X,Y} equals new {X',Y'}
in join and if you have more than this equations you should convert it to nested query. So I Prefer to have a more readable code which uses minimum differences in difference actions.
To throw a third and more prefered method into the mix with LINQ to SQL, use associations between the tables (even if you don't have them set up in your database). With that in place, you can navigate the object graph rather than using joins:
var query = from cu in Customer
from ad in cu.Addresses
select ad;
Note: when querying the object graphs, LINQ to SQL translates the join into a left outer join where-as the join/where syntax by default is an inner join.
Joins in LINQ should be used when there isn't a natural relationship between the objects. For example, use a join if you want to see the the listing of stores that are in the same city as your customers. (Join Customer.Address.City with Store.Address.City).
There should not be a difference between these two queries. I actually wondered this question myself a few months ago. I verified this through LINQPad. It's a free tool that you can download and actually see the generated SQL of any LINQ query (this is the query that is sent to the database).
The generated SQL should be the same for these two queries.
If you're doing this through Visual Studio, there is also a way you can see the generated SQL as well.

Categories