I used entity framework with my example. I wanted to filter child entity but I am getting exception 'The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.'
public List<Notification> GetNotificationBySentDate(DateTime? dateTime)
{
if (dateTime == null)
{
return
_dbContext.Notifications.Include(x => x.Attachments.Select(a=>a.Clean==true))
.Where(x =>
x.Sent == null &&
x.FaultCount <= _appSettingsHelper.NotificationsFaultCountLimit &&
DbFunctions.AddSeconds(x.CreatedDate, x.DelaySeconds) < DateTime.UtcNow)
.OrderBy(a => DbFunctions.AddSeconds(a.CreatedDate, a.DelaySeconds))
.Take(_appSettingsHelper.NotificationsBySentStateSelectTop).ToList();
}
return _dbContext.Notifications.Include(x => x.Attachments).Where(x => x.Sent >= dateTime)
.OrderBy(a => a.CreatedDate)
.Take(_appSettingsHelper.NotificationsBySentStateSelectTop).ToList();
}
Any help would be much appreciated. Thanks.
It seems that the problem is with Select statement under the Include. You can try to remove it and add an additional clause to Where, something like && x.Attachements.Clean == true. Thus your code will be
_dbContext.Notifications.Include(x => x.Attachments)
.Where(x =>
x.Sent == null &&
x.FaultCount <= _appSettingsHelper.NotificationsFaultCountLimit &&
DbFunctions.AddSeconds(x.CreatedDate, x.DelaySeconds) < DateTime.UtcNow &&
x.Attachments.Clean == true)
.OrderBy(a => DbFunctions.AddSeconds(a.CreatedDate, a.DelaySeconds))
.Take(_appSettingsHelper.NotificationsBySentStateSelectTop).ToList();
Related
The following query is not returning the proper results, it will return properly for company, but not the other two parameters. For clarification this is inside a post method of a page taking the user's input for company, name, and/or state
var transporters = await _db.TransporterProfiles
.Include(x => x.TransportState)
.Where(x => x.Company == company || company == null &&
x => x.LastName == name || name == null &&
x => x.TransportState.Name == state || state == null)
.ToListAsync();
I've tried adding parentheses around each part of the query such as
.Where((x => x.Company == company || company == null) &&
(x => x.LastName == name || name == null) &&
(x => x.TransportState.Name == state || state == null))
but this produces an error
Operator '&&' cannot be applied to operands of type 'lambda expression'
There's no reason to include company == null in the query. If you don't want a search term, don't include it at all. You can build AND conditions by adding Where clauses to a query as needed, eg :
if(value1 != null)
{
query=query.Where(x=>x.Property1 == value1);
}
if(value2 != null)
{
query=query.Where(x=>x.Property2 == value2);
}
In the question's case you can write something like this:
var query=_db.TransporterProfiles.Include(x => x.TransportState).AsQueryable();
if(company!=null)
{
query=query.Where(x => x.Company == company);
}
if(name!=null)
{
query=query.Where(x => x.LastName == name);
}
if(state!=null)
{
query=query.Where(x => x.TransportState.Name == state);
}
var transporters=await query.ToListAsync();
You don't need to include TransportState to use x.TransportState.Name in the Where clause. Include is used to eagerly load related data, not tell EF to JOIN between related tables.
If you don't want Include you can start the query with :
var query=_db.TransporterProfiles.AsQueryable();
The issue with your syntax is you have multiple lambdas that should be one.
.Where(x => (x.Company == company || company == null) &&
(x.LastName == name || name == null) &&
(x.TransportState.Name == state || state == null))
That said the actual solution is to do what #PanagiotisKanavos posted as an answer, generate the query dynamically based on the input values.
I have a Model with List inside it, is there any way to filter that list?
What I'm trying is:
List<Booking> a = await _context.Set<Booking>().Include(u => u.BookingLine).Include(u => u.BookingStatus).ToListAsync();
Inside that Booking model, there is a List. I just want to get all the StatusId = 1 inside that BookingStatus.
Booking model and BookingStatus model has the same BookingId. I don't know where do I put the Where() inside that linq.
I tried like this but it returned an error:
_context.Set<Booking>().Include(u => u.BookingLine).Include(u => u.BookingStatus
.LastOrDefault(a => a.StatusId == 1 || a.StatusId == 7 || a.StatusId == 13)).ToListAsync();
Error:
System.InvalidOperationException: The expression 'u.BookingStatus.AsQueryable().LastOrDefault(a => (((a.StatusId == 1) OrElse (a.StatusId == 7)) OrElse (a.StatusId == 13)))' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations. For more information on including related data
I think you meant to use "Where" instead of "LastOrDefault".
something like:
_context.Set<Booking>().Include(u => u.BookingLine).Include(u => u.BookingStatus
.Where(a => a.StatusId == 1 || a.StatusId == 7 || a.StatusId == 13)).ToListAsync();
Microsoft example of Eager Loading:
using (var context = new BloggingContext())
{
var filteredBlogs = context.Blogs
.Include(
blog => blog.Posts
.Where(post => post.BlogId == 1)
.OrderByDescending(post => post.Title)
.Take(5))
.ToList();
}
Currently I have a LINQ query like this:
var policy = snapshotDate == null
? await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync()
: await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber)
&& (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
I would like to know if I can shorten it like this:
var policy = await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber))
.Where(p => snapshotDate != null && (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
But this doesn't work and I would like to know how I can condition this LINQ query in a proper way and shorten them without using the terenary operator.
Thanks in advance.
Try this:
var policy = await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber)
&& (snapshotDate == null ||
(p.PolicyEffectiveDate <= snapshotDate &&
p.PolicyExpirationDate > snapshotDate)))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
This query will apply conditions of PolicyEffectiveDate and PolicyExpirationDate if snapshotDate is not null otherwise only PolicyNumber condition will apply.
Seems like you want your condition to evaluate
snapshotDate == null || (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate)
Which says, give all dates when snapshotDate is null, or within when it's not.
Note : about multiple where clauses. In a memory based collection you are will get a performance increase combining them with an && (due to the extra delegate invocation, and potential multiple enumerations), however with most LINQ to Query providers it will evaluate in the exact same SQL. Though in general it's best combining these if you can.
What is wrong in this query? It's about 2 entities that can be logically deleted by inserting a delete date. So I must be sure I get a single Entity with is collection of SubEntities. All with DateDelete not null.
return DbContext.Entity
.AsNoTracking()
.Include(y => y.SubEntities.Select(sb => sb.DateDelete == null))
.Single(y => y.Name == entityName && y.DateDelete == null);
On runtime I get an exception
The Include path expression must refer to a navigation property
defined on the type. Use dotted paths for reference navigation
properties and the Select operator for collection navigation
properties. Parameter name: path
I also tried this with same error
return DbContext.Entity
.AsNoTracking()
.Include(y => y.SubEntities.Where(sb => sb.DateDelete == null))
.Single(y => y.Name == entityName && y.DateDelete == null);
After my own investigation I found it is impossible to filter on .Include() but there are workarounds by using .Select() method or the filter library.
Workaround 1
return DbContext.Entity
.AsNoTracking()
.Where(e => e.DateDelete == null)
.Select(e => new
{
e.Id,
e.Property,
e.DateDelete,
SubEntities = e.SubEntities.Where(se => se.DateDelete == null)
})
.ToList();
Workaround 2
The solution given by Gert Arnold here with EntityFramework.DynamicFilters. This workaround has some limitation. Read the documentation.
I am trying to order a list of products based on the zindex property of the cross reference table with the category table (in this case called 'Chassis'), but I get the following error:
Cannot order by type 'System.Collections.Generic.IEnumerable`1[System.Int32]'.
The following is the method I am using:
public IQueryable<E_Product> Product_GetList_ByChassisId(int chassisId)
{
return dc.E_Products
.Where(x => x.Deleted == false)
.Where(x => x.Published == true)
.Where(x => x.E_Product_Chassis
.Any(c => c.ChassisId == chassisId && c.Deleted == false))
.OrderBy(x => x.E_Product_Chassis.Select(c => c.Zindex));
}
I understand the .Select method returns an IEnumerable, but being a many-to-many relationship, x.E_Product_Chassis does not allow simple selection of its properties (e.g. x.E_Product_Chassis.Zindex).
Any help would be very appreciated...
FirstOrDefault(), Min(), Max() -- use one of these functions to select the appropriate z-index out of the set.
public IQueryable<E_Product> Product_GetList_ByChassisId(int chassisId)
{
return dc.E_Products
.Where(x => x.Deleted == false)
.Where(x => x.Published == true)
.Where(x => x.E_Product_Chassis
.Any(c => c.ChassisId == chassisId && c.Deleted == false))
.OrderBy(x => x.E_Product_Chassis.Min(c => c.Zindex));
}