EF Core: Take() also limits results of include - entity-framework

I have following query:
var query = this.DbContext.Products.AsNoTracking()
.WhereIf(publishedFrom.HasValue, x => x.Erscheinen.Value >= publishedFrom)
.WhereIf(publishedTo.HasValue, x => x.Erscheinen.Value < publishedTo)
.WhereIf(!string.IsNullOrEmpty(publisherCode), x=> x.VerlagCode == publisherCode)
.OrderByDescending(x => x.GeplantesErscheinen)
.Take(maxResultCount)
.Include(x => x.SubjectAreas)
.Include(x => x.ProductPrices)
.Include(x => x.ProductOriginators);
;
The query should return the Product-Entity based on 3 where conditions and a order by. Related entities should be included. Afterwards only the First maxResultCount of the product query result should be returned. For the products ALL related entities should be loaded.
HOWEVER, Take() also has an impact on the query of the related entities. When I look into the sql server profiler I see followign query executed:
exec sp_executesql N'SELECT [a0].[ProductId], [a0].[SubjectAreaId], [t].[Id]
FROM (
SELECT TOP(#__p_3) [a].[Id], [a].[GeplantesErscheinen]
FROM [AppProducts] AS [a]
WHERE ((((#__ef_filter__p_0 = CAST(1 AS bit)) OR ([a].[IsDeleted] = CAST(0 AS bit))) AND ([a].[Erscheinen] >= #__publishedFrom_0)) AND ([a].[Erscheinen] < #__publishedTo_1)) AND ([a].[VerlagCode] = #__publisherCode_2)
ORDER BY [a].[GeplantesErscheinen] DESC
) AS [t]
INNER JOIN [AppProductSubjectArea] AS [a0] ON [t].[Id] = [a0].[ProductId]
ORDER BY [t].[GeplantesErscheinen] DESC, [t].[Id]',N'#__p_3 int,#__ef_filter__p_0 bit,#__publishedFrom_0 datetime2(7),#__publishedTo_1 datetime2(7),#__publisherCode_2 nvarchar(4000)',#__p_3=3,#__ef_filter__p_0=0,#__publishedFrom_0='2022-04-22 00:00:00',#__publishedTo_1='2022-07-13 00:00:00',#__publisherCode_2=N'NOM'
Furthermore, I find the generated query very strange, because it also contains the sorting, which I need, however, only for the product.
Can anyone tell me how to get all the related entities without applying the other conditions?

Related

Easiest way to delete all records except the last 10 by date using EFCore [duplicate]

Let's say that I have a table like:
Id Name Category CreatedDate
1 test test 10-10-2015
2 test1 test1 10-10-2015
...
Now, I would like to delete all rows and leave only the top 10 from all categories (by top 10 I mean the 10 newest according to createdDate).
Using raw SQL, it would be like:
DELETE FROM [Product]
WHERE id NOT IN
(
SELECT id FROM
(
SELECT id, RANK() OVER(PARTITION BY Category ORDER BY createdDate DESC) num
FROM [Product]
) X
WHERE num <= 10
How is this done when using the DbContext in Entity Framework?
// GET all products
var list = ctx.Products.ToList();
// GROUP by category, ORDER by date descending, SKIP 10 rows by category
var groupByListToRemove = list.GroupBy(x => x.Category)
.Select(x => x.OrderByDescending(y => y.CreatedDate)
.Skip(10).ToList());
// SELECT all data to remove
var listToRemove = groupByListToRemove.SelectMany(x => x);
// Have fun!
ctx.Products.RemoveRange(listToRemove);
Guessing it will take a whil if you have a lot of data but.
var oldItems = efContext.Products
.GroupBy(x => x.Category,
(c,p) => p.OrderByDescending(x => p.createdDate).Skip(10))
.SelectMany(p => p);
efContext.Products.RemoveRange(oldItems);
Will do the trick
(Written in notepad)

EF core .any not filtering results

I have the following sql, which I'm trying to translate to linq:
SELECT *
FROM [Service] s
inner join vendor v on vendorid=v.id
inner join VendorLocation vl on vl.VendorId=v.id
where s.active=1 and v.active=1 and vl.City = 'toronto' and vl.Active=1
I have a Service that belongs to a Vendor and the Vendor has Locations. I'm trying to filter the locations based on city, but the query returns results that don't satisfy the conditions in the ".Any" clause
var service = await _context.Service
.Where(s => s.Active && s.Vendor.Active)
.Include(s => s.Vendor)
.ThenInclude(s => s.VendorLocations)
.Where(s => s.Vendor.VendorLocations.Any(l => l.City == City && l.Active))
.ToListAsync();
The sql statement returns the correct results but the linq is not.
Any help is appreciated, thanks! Ben
You can try with query notation:
var query = from v in _context.Vendors
join s in v.Services on v.Id equals s.VendorId
join l in v.ServiceLocations on v.Id equals l.VendorId
where v.Active && s.Active && l.City=="Toronto"
select new {v,s,l};
var result= await query.ToLinqAsync();
Hi your using EF Core now , But
I suggest Use LINQ because its simplest
Please read this page for more
and this is sample code
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
the query returns results that don't satisfy the conditions in the ".Any" clause
Those queries just aren't the same. The SQL Query returns one row per VendorLocation with additional columns from joined tables, and projects all the columns.
SELECT *
FROM [Service] s
inner join vendor v on vendorid=v.id
inner join VendorLocation vl on vl.VendorId=v.id
where s.active=1 and v.active=1 and vl.City = 'toronto' and vl.Active=1
In LINQ this would be something like
from vl in VendorLocation
where vl.Vendor.Active
&& vl.Vendor.Service.Active
&& vl.Active
&& vl.City = 'toronto'
select new
{
ServiceName = vl.Vendor.Service.Name,
ServiceDescription = vl.Vendor.Service.Description,
. . .
VendorName = vl.Vendor.Name,
VendorWhatever = vl.Vendor.Whatever,
. . .
vl.Name,
. . .
};

Linq to entities subquery

How can I write the following subquery in Linq:
Context.Set<Process>()
.Include(...)
.Where(x => x.Activity.Name.CompareTo(Context.Set<Activity>().Where(a => a.Id == activityId).Select(c => a.Name)) > 0)
.Take(1);
This is a simplifed version of query, WHERE clause only includes the part that is not working. If I change Context.Set().... subquery to a string constant, then the query works. As it is, it gives NotSupportedException
LINQ to entities does not recognize method Set<Activity>
Try this:
(from p in context.Set<Process>().Include(...)
from a in context.Set<Activity>()
where a.Id == activityId
where p.Activity.Name.CompareTo(a.Name) > 0
select p).Take(1);

EF 1.0 flattening a left join query

I'm trying to execute a linq to entites query in (Visual Studio 3.5 /EF 1.0) for 3 entities with the following relationships:
xcCRMCounterparty * => 0..1 CSIDsInUse
CSIDsInUse 1 => * xcCIFToCSID
Previously in T SQL I used:
select distinct CIF, xcCIFToCSID.xcCSID, CounterpartyName
from xcCIFToCSID
left join CSIDsInUse
on xcCIFToCSID.idCSID = CSIDsInUse.Id
left join xcCRMCounterparty
on CSIDsInUse.Id = xcCRMCounterparty.IdCSID
order by CounterpartyName
Now with EF I'm tried to flatten the result set as below, but I don't know how to flatten the xcCRMCounterparty item i.e. it's a collection rather than a single field
var query = from cifto in entities.xcCIFToCSIDSet.Include(x => x.CSIDsInUse).Include(x => x.CSIDsInUse.xcCRMCounterparty)
select new
{
cifto.CIF,
cifto.xcCSID,
cifto.CSIDsInUse.xcCRMCounterparty
};
How can I modify my query so that I can generate flattened results?
Try this:
var query = from cifto in entities.xcCIFToCSIDSet
from x in cifto.CSIDsInUse.xcCRMCouterparty
select new
{
cifto.CIF,
cifto.xcCSID,
x.Name
};

sql query into Linq

Please anyone can help me to write this sql query into Linq.
select
P.ID,
P.Name,
Set_selected=
case when exists(
select C.ClassifierID
from dbo.ProductClassifiers C
where C.ProductID=130 and C.ClassifierID=P.ID)
then 'Yes' else 'No' end
from dbo.Classifier P
var retVal = (from s in dataContext.ProductClassifiers
join k in dataContext.Classifier
on s.ClassifierId equals k.Id
where s.ProductId == 30
select new {write here what values you want to get like s.Id,k.Name etc}).ToList();
Here's an attempt:
var query = from p in dataContext.Classifiers
select new {
p.ID,
p.Name,
p.Selected = dataContext.ProductClassifiers
.Where(c => c.ProductID == 130 &&
c.ClassifierID == p.ID)
.Any()
};
(That will make the Selected property Boolean rather than Yes/No, but that's usually going to be easier to work with.)
You should look at what the translated SQL looks like though, and in particular what the query plan is like compared with your original.
Untested, but hopefully works:
var q = classifier.Select(
p => new {
p.ID,
p.Name,
Set_selected = productClassifiers
.Select(c => c.ProductID == 130 && c.ClassifierID == p.ID)
.Any() ? "Yes" : "No"
}
);
The code assumes that you have two IEnumerable<T> representing the Classifier and ProductClassifiers tables.