Any vs Where clause in LINQ - linq

I always thought LINQ to SQL equivalent for an exists query is to use Any(). But i recently wrote a query in LINQ , which basically is trying to find if duplicate records exists in single table.
Anycontext.Contacts.Any(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email)))
matching criteria is simple to find contacts with same FirstName, LastName and AddressLine1 or same Email. This query times out in 30 sec(default), there are just 500K rows in this table.
Wherecontext.Contacts.Where(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email))).Count()>0
I was forced to use Where clause and then do count greater than 0 to find if any duplicate exists in the set. What i can not understand is, why LINQ to SQL on simple Any clause timing out.
Any explanation will be really great here.
EDIT
SQL From from LINQ Pad
ANY
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0) AND ((([t0].[FirstName] = #p1) AND ([t0].[LastName] = #p2) AND ([t0].[AddressLine1] = #p3) AND ([t0].[Zip] = #p4)) OR (([t0].[FirstName] = #p5) AND ([t0].[LastName] = #p6) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7) AND ([t1].[ContactID] = [t0].[ContactID])
))))
) THEN 1
ELSE 0
END) AS [value]
Where
SELECT [t0].[ContactID]
,[t0].[CompanyID]
,[t0].[CompanyTitle]
,[t0].[FirstName]
,[t0].[LastName]
,[t0].[AddressLine1]
,[t0].[AddressLine2]
,[t0].[City]
,[t0].[State]
,[t0].[Zip]
,[t0].[Email]
,[t0].[Salutation]
,[t0].[IsActive]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0)
AND (
(
([t0].[FirstName] = #p1)
AND ([t0].[LastName] = #p2)
AND ([t0].[AddressLine1] = #p3)
AND ([t0].[Zip] = #p4)
)
OR (
([t0].[FirstName] = #p5)
AND ([t0].[LastName] = #p6)
AND (
EXISTS (
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7)
AND ([t1].[ContactID] = [t0].[ContactID])
)
)
)
)

Not completely sure if this is what you want, but you could compare, I'm guessing you wont run the test often, as it would be better to test for existence before you input the data to the DB.
If you want to find the duplicates then
var queryA = from a in db.someTable
select a.value;
foreach(var row in queryA){
Console.Write(queryA.Where(b => b == row).Count() > 1 ? row: "");
}
If you just want to test if it exist then.
var queryA = from a in db.someTable
select a.value;
var queryB = queryA;
queryB.Distinct();
Console.Write(queryB.Count() != queryA.Count() ? "Yes" : "No");

Related

How to convert exists condition inside where clause in Linq

I want to add following where clause to Linq query. How subquery like below using linq
WHERE (Restaurants.[IsActive] = 1)
AND exists
(
select 1 from APIKeys
where ApiKey = 'on35e5xbt3m4cbcef4e4448t6wssg11o'
and (KeyType = 1
and fk_RestaurantsID = [t2].[RestaurantsID]
or KeyType = 2
and fk_RestaurantGroupID = RG.RestaurantGroupsID
and [t1].[fk_RestaurantsID] in
(SELECT RestaurantsID
FROM Restaurants
WHERE RestaurantGroupsID = RG.RestaurantGroupsID))
)
AND (0 = (COALESCE([t0].[fk_MembersID],0)))
AND (1 = [t0].[fk_BookingStatusID])
AND ([t0].[Email] = 'nike.s#gmail.com')
AND (([t0].[Phone] = '9999999990') OR ([t0].[MobilePhone] = '9999999990'))
Use Any() to produce subquery which translated to EXISTS. E.g. with AdventureWorks database sample:
from p in Products
where p.FinishedGoodsFlag &&
SalesOrderDetails.Any(od => od.ProductID == p.ProductID)
select new { p.ProductID, p.Name }
Will produce following query to database:
SELECT [t0].[ProductID], [t0].[Name]
FROM [Production].[Product] AS [t0]
WHERE ([t0].[FinishedGoodsFlag] = 1) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Sales].[SalesOrderDetail] AS [t1]
WHERE [t1].[ProductID] = [t0].[ProductID]
))

How to write lambda (linq) expression for sql?

I have an Sql statement for which I need go generate corresponding Lambda Expression (Linq).
Here is the SQL
Declare #CurrentUserId as int
Declare #CurrentDate as datetime
Set #CurrentDate = GetDate()
Set #CurrentUserId = 1
Select C.conferenceId,C.specialtyId,C.name,C.city,S.abbr as statebbbr,CTRY.name as countryname,C.startdate,C.enddate
from Conferences C
Inner join (
Select distinct SpecialtyId
from UserContent
Where UserId = #CurrentUserId and DeletedFlag = 0
) DT on C.SpecialtyId = DT.SpecialtyId
Left outer join State S on C.StateId = S.StateId
Inner join Country CTRY on C.CountryId = CTRY.CountryId
Where C.DisplayStartDate <= #CurrentDate
and C.DisplayEndDate >= #CurrentDate
and C.DeletedFlag = 0
and C.Publish = 1
Order by C.startdate ASC
What wolud be the lambda(linq) expression for this?
Assume data context is in variable context
from c in context.conferences
join ctry in context.country on c.CountryId equals ctry.CountryId
join s1 in context.State on c.StateId equals s.StateId into s2
from s in s2.DefaultIfEmpty()
where
c.DisplayStartDate <= System.DateTime.Now
&& c.DisplayEndDate >= System.DateTime.Now
&& c.DeletedFlag == 0 // or false if represented as a bool
&& c.Publish == 1 // or true if represented as a bool
&& context.UserContent.Any(
x => x.SpecialityId == c.specialityId
&& x.UserId == currentUserId
&& x.DeletedFlag == 0
// or if represented as a bool "&& !x.DeletedFlag"
)
select new {
c.ConferenceId,
c.SpecialtyId,
c.name,
c.city,
stateabbr = s.abbr,
countryname = ctry.name,
c.startdate,
c.enddate
}

How to write this LINQ Query in a better way

I have one Linq Query. When I run the query, Only for 10 records its taking 13 seconds to extract the data to the model. I need to know the query which I wrote is good for performance or not. Please guide me what i am doing wrong.
Code
var stocktakelist = (from a in Db.Stocktakes
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = (from admin in Db.AdminAccounts where admin.Id == a.Id select admin.Name).FirstOrDefault(),
CreatedOn = a.CreatedOn,
Status = (from items in Db.Items where items.ItemNo == a.ItemNo select items.ItemStatu.Description).FirstOrDefault(),
Title = (from tit in Db.BibContents where tit.BibId == (from bibs in Db.Items where bibs.ItemNo == a.ItemNo select bibs.BibId).FirstOrDefault() && tit.TagNo == "245" && tit.Sfld == "a" select tit.Value).FirstOrDefault() // This line of Query only makes the performance Issue
}
).ToList();
Thanks
The reason this is so slow is because it is running the 3 inner LINQ statements for every item in the outer LINQ statement.
Using LINQ joins will run only 4 queries and then link them together, which is faster.
To find out how to join, there are plenty of resources on the Internet depending on the type of LINQ you are using.
If you're retrieving this data from a SQL server, perhaps consider doing this intensive work in SQL - this is what SQL was designed for and it's much quicker than .NET. EDIT: As highlighted below, the work is done in SQL if using LINQ to SQL/Entities and using the correct join syntax.
I was trying to create the corresponding query with some joins for practice.
I cannot test it and i'm not 100% sure that this query will you get the result
you are hoping for but maybe at least it will give you a hint on how to write
joins with linq.
from a in Db.Stocktakes
join admin in Db.AdminAccounts
on a.Id equals admin.Id
into adminJoinData
from adminJoinRecord in adminJoinData.DefaultIfEmpty( )
join items in Db.Items
on a.ItemNo equals items.ItemNo
into itemsJoinData
from itemsJoinRecord in itemsJoinData.DefaultIfEmpty( )
join title in Db.BibContents
(
from subQuery in Db.BibContents
where subQuery.TagNo == "245"
where subQuery.Sfld == "a"
select subquery
)
on title.BibId equals itemsJoinRecord.BidId
into titleJoinData
from titleJoinRecord in titleJoinData.DefaultIfEmpty( )
select new ExportStock( )
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = adminJoinRecord.Name,
CreatedOn = a.CreatedOn,
Status = itemsJoinRecord.ImemStatu.Description,
Title = titleJoinRecord.Value
}
As others have said, you should use Left Outer Joins in your LINQ just as you would if writing it in SQL.
Your query above will end up looking roughly like this once converted (this is untested, but gives the basic idea):
var a = from a in Db.Stocktakes
join admin in Db.AdminAccounts on admin.Id equals a.Id into tmpAdmin
from ad in tmpAdmin.DefaultIfEmpty()
join item in Db.Items on item.ItemNo equals a.ItemNo into tmpItem
from it in tmpItem.DefaultIfEmpty()
join title in Db.BibContents on bib.BibId equals items.BibId into tmpTitle
from ti in tmpTitle.DefaultIfEmpty()
where ti.TagNo == "245"
&& ti.Sfld == "a"
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = ad == null ? default(int?) : ad.Id,
CreatedOn = a.CreatedOn,
Status = it == null ? default(string) : it.ItemStatus.Description,
Title = ti == null ? default(string) : ti.Value
};
Using lambda expressions your query will look like this:
Db.Stocktakes
.Join(Db.AdminAccounts, a => a.Id, b => b.Id, (a,b) => new { a, AdminId = b.Name })
.Join(Db.Items, a => a.ItemNo, b => b.ItemNo, (a,b) => new { a, Status = b.ItemStatus.Description, BidId = b.BibId })
.Join(Db.BibContents, a => a.BibId, b => b.BibId, (a,b) => new { a, Value = b.Value, TagNo = b.TagNo, Sfld = b.Sfld })
.Where(a => a.TagNo == "245" && a.Sfld == "a")
.Select(a =>
new ExportStock { Id = a.Id,
ItemNo = a.ItemNo,
AdminId = a.AdminId,
CreatedOn = a.CreatedOn,
Status = a.Status,
Title = a.Value
}
).ToList();

Sql to linq convention

i have a problem to build my linq query and i need you help , the following code is what i have got so far
, it does has some errors as expected, so, this is my sql query :
*im new to linq and did searched over google.
select CAST(h.changedate as date) as 'RegDate' ,count (cast(h.changedate as date)) as 'Amount' from T_TalmidStatusHistory h
join T_talmid t on h.talmidid = t.talmidid
where t.talmidStatusID=16 and h.[statusid] != 16
and h.id =
(
select max(id) from T_TalmidStatusHistory
where T_TalmidStatusHistory.talmidid=h.talmidid and T_TalmidStatusHistory.[statusid] != 16
)
group by CAST(h.changedate as date)
and this is what i have right now in linq:
var res = from r in db.T_TalmidStatusHistories
from m in db.T_TalmidStatusHistories
join t in db.T_Talmids on r.TalmidID equals t.TalmidID
where t.TalmidStatusID == 16 && r.StatusID != 16
&& r.id == from l in db.T_TalmidStatusHistories
where m.TalmidID == r.TalmidID && m.StatusID != 16
select new{db.T_TalmidStatusHistories.OrderByDescending(tp => tp.id).FirstOrDefault().id }
group h by h.changedate as date
select new { h.changedate as date, count (cast(h.changedate as date))};
Edit:
i'm expecting to get the number of students that sign up on each date,
my error is :
Operator '==' cannot be applied to operands of type 'int' and 'System.Linq.IQueryable'
at line : r.id == from l in db.T_TalmidStatusHistories
ty.
The whole part
from l in db.T_TalmidStatusHistories ... count (cast(h.changedate as date))}
is one query which is compared to r.id by the == operator.
Change it to
...
r.id == (db.T_TalmidStatusHistories
.Where(m.TalmidID == r.TalmidID && m.StatusID != 16)
.OrderByDescending(tp => tp.id).FirstOrDefault().id)
group h by h.changedate as date
select new { h.changedate as date, count (cast(h.changedate as date))};

Use of where in multiple joins to remove rows - linq

I have a table of orders. the status is on the soilorders which is joined to the orders.
I only want to return orders where the joined soilorder does not have status "Removed".
I had thought that
join sso in db.SoilSamplingOrders on ord.order_id equals sso.order_id
where sso.status.Equals("Removed")!=true
but then no records are returned!
thanks for any help (query below)
var query =
from ord in db.Orders
join sso in db.SoilSamplingOrders on ord.order_id equals sso.order_id
where sso.status.Equals("Removed")!=true
join cust in db.Customers on ord.customer_id equals cust.customer_id
select new Listing
{
assigned_to = sso.assigned_to,
company = cust.company,
order_id = ord.order_id,
order_created = ord.order_created,
customer_id = ord.customer_id,
order_created_by_employ_id = ord.order_created_by_employ_id,
first_farm_on_order = (from f in db.SoilSamplingSubJobs
where f.order_id == ord.order_id
select new ListingSubJob { first_farm_on_order = f.farm }).
AsEnumerable().First().first_farm_on_order,
total_fields = (from f in db.SoilSamplingSubJobs
where f.order_id == ord.order_id
select new { f.sssj_id }).AsEnumerable().Count(),
total_area = (float?) (from f in db.SoilSamplingSubJobs
where f.order_id == ord.order_id && f.area_ha != null
select f.area_ha ).Sum() ?? 0 ,
total_area_ph_density = (float?)(from f in db.SoilSamplingSubJobs
where f.order_id == ord.order_id && f.ph != null
select f.ph).Sum() ?? 0,
};
DOH! Just as nature abhors a vacuum, anything Null cannot be included in the select. Added values to the status field and bom it works.

Resources