EF6, Linq to entities queries all columns with select new clause - sql-server

Not sure what is going on here, but my query is using every column even though I'm using a projection.
var students = (from x in db.vStudentProfiles
where x.strLegalFirstName == searchDTO.FirstName &&
x.strLegalMiddleName == searchDTO.MiddleName &&
x.strLegalLastName == searchDTO.LastName &&
x.datBirthDate == searchDTO.DateOfBirth &&
x.intStudentStatusCd != 3
orderby x.intStudentStatusCd ascending, x.datCreated descending
select new
{
x.strLegalFirstName,
x.strLegalLastName,
x.strLegalMiddleName,
x.datBirthDate,
x.intStudentStatusCd,
x.datCreated,
x.strNBEN
}
).ToList();
which results in all columns getting queried:
SELECT
[Project1].[C1] AS [C1],
[Project1].[strLegalFirstName] AS [strLegalFirstName],
[Project1].[strLegalLastName] AS [strLegalLastName],
[Project1].[strLegalMiddleName] AS [strLegalMiddleName],
[Project1].[datBirthDate] AS [datBirthDate],
[Project1].[intStudentStatusCd] AS [intStudentStatusCd],
[Project1].[datCreated] AS [datCreated],
[Project1].[strNBEN] AS [strNBEN]
FROM ( SELECT
[Extent1].[strNBEN] AS [strNBEN],
[Extent1].[strLegalFirstName] AS [strLegalFirstName],
[Extent1].[strLegalMiddleName] AS [strLegalMiddleName],
[Extent1].[strLegalLastName] AS [strLegalLastName],
[Extent1].[datBirthDate] AS [datBirthDate],
[Extent1].[datCreated] AS [datCreated],
[Extent1].[intStudentStatusCd] AS [intStudentStatusCd],
1 AS [C1]
FROM (SELECT
[vStudentProfile].[intStudentId] AS [intStudentId],
[vStudentProfile].[strStudentStatusDescE] AS [strStudentStatusDescE],
[vStudentProfile].[strSPID] AS [strSPID],
[vStudentProfile].[strSPIDPart1] AS [strSPIDPart1],
[vStudentProfile].[strSPIDPart3] AS [strSPIDPart3],
[vStudentProfile].[strSPIDPart4] AS [strSPIDPart4],
........ bunch of other columns
[vStudentProfile].[strStreetDirection] AS [strStreetDirection],
[vStudentProfile].[strProvince] AS [strProvince],
[vStudentProfile].[intStudentStatusCd] AS [intStudentStatusCd],
[vStudentProfile].[intSiteId] AS [intSiteId]
FROM [dbo].[vStudentProfile] AS [vStudentProfile]) AS [Extent1]
WHERE (([Extent1].[strLegalFirstName] = #p__linq__0) OR (([Extent1].[strLegalFirstName] IS NULL) AND (#p__linq__0 IS NULL))) AND (([Extent1].[strLegalMiddleName] = #p__linq__1) OR (([Extent1].[strLegalMiddleName] IS NULL) AND (#p__linq__1 IS NULL))) AND (([Extent1].[strLegalLastName] = #p__linq__2) OR (([Extent1].[strLegalLastName] IS NULL) AND (#p__linq__2 IS NULL))) AND ([Extent1].[datBirthDate] = #p__linq__3) AND (3 <> [Extent1].[intStudentStatusCd])
) AS [Project1]
ORDER BY [Project1].[intStudentStatusCd] ASC, [Project1].[datCreated] DESC
I've also tried
var students = (from x in db.vStudentProfiles
let Child = new
{
x.strLegalFirstName,
.....
orderby x.intStudentStatusCd ascending, x.datCreated descending
select Child
).ToList();
but as I expected didn't make a difference.
Use edmx with a single SQL Server View mapped.

Not sure what is going on here, but my query is using every column even though I'm using a projection.
That's just the way EF generates queries. EF expects the database engine to be smart enough to ignore the columns that are not used. SQL Server is smart enough.

Related

EF6 query that behaves strangely using contains

I have an EF6 SQL Server query that behaves strangely when it is supplied with a List<int> of IDs to use. If bookGenieCategory = a value it works. If selectedAges is empty (count = 0) all is well. If the selectedAges contains values that exist in the ProductCategory.CategoryId column, the contains fails and NO rows are returned.
Note: AllocationCandidates is a view, which works properly on its own.
CREATE VIEW dbo.AllocationCandidate
AS
SELECT
p.ProductID, p.SKU as ISBN, p.Name as Title,
pv.MSRP, pv.Price, pv.VariantID, pv.Inventory,
ISNULL(plt.DateLastTouched, GETDATE()) AS DateLastTouched,
JSON_VALUE(p.MiscText, '$.AgeId') AS AgeId,
JSON_VALUE(p.MiscText, '$.AgeName') AS AgeName
FROM
dbo.Product AS p WITH (NOLOCK)
INNER JOIN
dbo.ProductVariant AS pv WITH (NOLOCK) ON pv.ProductID = p.ProductID
LEFT OUTER JOIN
dbo.KBOProductLastTouched AS plt WITH (NOLOCK) ON plt.ProductID = p.ProductID
WHERE
(ISJSON(p.MiscText) = 1)
AND (p.Deleted = 0)
AND (p.Published = 1)
AND (pv.IsDefault = 1)
GO
Do I have a typo here or a misplaced parenthesis in the following query?
var returnList = (from ac in _db.AllocationCandidates
join pc in _db.ProductCategories on ac.ProductID equals pc.ProductID
where (bookGenieCategory == 0
|| bookGenieCategory == pc.CategoryID)
&&
(selectedAges.Count == 0 ||
selectedAges.Contains(pc.CategoryID))
orderby ac.AgeId, ac.DateLastTouched descending
select ac).ToList();
Firstly, I would recommend extracting the conditionals outside of the Linq expression. If you only want to filter data if a value is provided, move the condition check outside of the Linq rather than embedding it inside the condition. This is generally easier to do with the Fluent Linq than Linq QL. You should also aim to leverage navigation properties for relationships between entities. This way an AllocationCandidate should have a collection of ProductCategories:
var query = _db.AllocationCandidates.AsQueryable();
if (bookGenieCategory != 0)
query = query.Where(x => x.ProductCategories.Any(c => c.CategoryID == bookGenieCategory);
The next question is what does the selectedAges contains? There is an Age ID on the AllocationCandidate, but your original query is checking against the ProductCategory.CategoryId??
If the check should be against the AllocationCandidate.AgeId:
if (selectedAges.Any())
query = query.Where(x => selectedAges.Contains(x.AgeID));
If the check is as you wrote it against the ProductCategory.CategoryId:
if (selectedAges.Any())
query = query.Where(x => x.ProductCategories.Any(c => selectedAges.Contains(c.AgeID)));
Then add your order by and get your results:
var results = query.OrderBy(x => x.AgeId)
.ThenByDescending(x => x.DateLastTouched);
.ToList();

Why does LINQ generated SQL include multiple "IS NULL" conditions for the same column

The following query against a SQL Server 2012 database, using Entity Framework Core 3.1:
var tows = await _context.DataEntryTow
.Where(t => _context.DataEntrySample
.Any(s => s.TowId==t.TowId && (s.MicroscopeId != "0" || s.MicroscopeId == null)))
.Select (t => new { text = t.TowId, value = t.TowId });
generates this SQL:
SELECT d.tow_id AS text
FROM data_entry_tow AS d
WHERE EXISTS (
SELECT 1
FROM data_entry_sample AS d0
WHERE (d0.tow_id = d.tow_id) AND (((d0.microscope_id <> '0') OR (d0.microscope_id IS NULL)) OR (d0.microscope_id IS NULL)))
I don't think I've done anything wrong, and I'm fairly sure the query optimizer will eliminate the second (d0.microscope_id IS NULL), but it still seems like an error in the LINQ code.
MicroscopeId is defined:
public string MicroscopeId { get; set; }
Field MicroscopeId declared as nullable. So, to mimic LINQ to Objects behaviour when null != "0" is true but in SQL null <> '0' is false, EF Core generates additional OR condition.
To disable this geneeration you have to specify that when building DbContextOptions:
optionsBuilder.UseSqlServer(constr, b => b.UseRelationalNulls(true) );
Additional info: https://learn.microsoft.com/en-us/ef/core/querying/null-comparisons#using-relational-null-semantics

EF Core 3.1 produces incorrect query translation

I have the following EF Core 3.1 statement:
var orders = await _dbContext.Orders.Include(o => o.OrderReceivers)
.Where(o => o.BooleanFlag1 && o.OrderState == OrderState.SomeState && o.OrderReceivers.Any(o => o.BooleanFlag2))
.ToListAsync(cancellationToken);
and this is the generated SQL Server query:
SELECT /*All column names here*/
FROM [Schema].[Orders] AS [o]
LEFT JOIN [Schema].[OrderReceivers] AS [o0] ON [o].[Id] = [o0].[OrderId]
WHERE (([o].[ShouldSendBlackList] = CAST(1 AS bit)) AND ([o].[OrderState] = 2)) AND EXISTS (
SELECT 1
FROM [Schema].[OrderReceivers] AS [o1]
WHERE ([o].[Id] = [o1].[OrderId]) AND ([o1].[BooleanFlag2] = '1'))
ORDER BY [o].[Id], [o0].[Id]
The problem with the generated SQL Query is this part:
([o1].[BooleanFlag2] = '1')
Because this causes the second where clause to be always false!
Any ideas on what is wrong here? Thanks in advance.

Linq - Query on 2 Lists Optimization

I am having 2 Lists & I am querying on this 2 List. Both the List are populated with huge data. So the query is taking long time.
When I usually face this performance issue, I simply convert SQL queries & run them directly & get the result in a datatable. But this time I cannot do this as these 2 are not tables but Lists of Models.
How to Optimize this Query or what else should i do?
Code :-
List<TempInOut> listTempInOut = new List<TO_TempInOut>();
List<ShiftSchedule> tempShiftSch = new List<TO_TempInOut>();
var data = (from B in tempShiftSch
from C in listTempInOut
where
B.CompanyId == companyId &&
C.CompanyId == companyId &&
B.EmployeeId == C.EmployeeId &&
C.InDate >= StrOutStart &&
C.InDate <= StrOutEnd &&
B.ShiftId == item.ShiftCode &&
B.ShiftDate == tempInputDate
select new
{
C.EmployeeId,
C.InDate,
C.Time_Date1
}).ToList();
Implement an IEqualityComparer for your types, use HashSet for each collection, and use the HashSet.Intersect method to get your output.
You can simplify your query to two stepsand compare time.
I am thinking of something like that.
var listTempInOutResult = listTempInOut.Where(C => C.CompanyId == companyId
&& C.InDate >= StrOutStart
&& C.InDate <= StrOutEnd);
var employessIds = listTempInOutresult.Select(x => x.EmployeeId).ToList();
var data = tempShiftSch.Where(B => employessIds.Contains(B.EmployeeId)
&& B.CompanyId == companyId
&& B.ShiftDate == tempInputDate
&& B.ShiftId == item.ShiftCode)
.Select(C=> new
{
C.EmployeeId,
C.InDate,
C.Time_Date1
}).ToList();
if you are working with iqueryable it would be better to use joins.
see this StackOverflow question

Can Any one help me to convert this sql query into linq

I need to convert this SQL Query to Link :
"Select * FROM [Register]
where RegisterId IN (SELECT MyId
FROM Friends
WHERE FriendId='" + Session["CurrentProfileId"] + "'
AND Status=1
UNION
SELECT FriendId
FROM Friends
WHERE MyId='" + Session["CurrentProfileId"] + "'
AND Status=1) ";
It may be look like this??? but this is incorrect and having errors
(from u in db.Register
where RegisterId).Contains
(from f in db.Freinds
where f.MyId == Id && m.Status == 1
select new { m.MyId })
.Union(from m in db.Freinds
where f.FreindId == Id && m.Status == 1
select new { m.CreateDate } ));
You have a few problems with the linq above and here are a few:
In the query in the Union you select the CreateDate whereas in the top on you select the MyId. I assume you meant to select FreindId.
In these 2 queries you create an anonymous class instance with the field but then compare it to the RegisterId which is probably a guid/string/int - but for sure not of the type you just created.
You are using the Contains method wrong. Linq syntax can be similar to sql but it is not the same. Check here for Contains
The correct Linq way of doing it is:
var idsCollection = ((from f in db.Freinds
where f.StatusId == 1 && f.MyId == Id
select f.MyId)
.Union(from m in db.Friends
where m.StatusId == 1 && f.FreindId == Id
select m.FriendId)).ToList();
var result = (from u in db.Register
where idsCollection.Contains(u.RegisterId)
select u).ToList();
Notice that the .ToList() is not a must and is here just to ease in debugging. For more information about this .ToList() and Linq in general check MSDN

Resources