Are there any way to get the following expression to work in EF Core 3.1?
_db.Customers
.Where(customer => customer.IsFavorite(userId))
.ToList();
IsFavorite is a simple expression that compares multiple properties with the userId. This could obviously be rewritten as
_db.Customers
.Where(customer => customer.Prop1 == userId || customer.Prop2 == userId)
.ToList();
But i'd like to avoid duplicating this logic. Other uses are when filtering on child properties, such as:
_db.Orders
.Where(order => order.Customer.IsFavorite(userId))
.ToList();
Any suggestions?
Related
I am trying to generate a List<Object> using Where clause with properties from a different List<Object>. I know that I could use a .Include(), similar to a SQL join if I were using Entity Framework but I am not using Entity Framework so I don't think it would work. I have:
List<Problem> problems = MethodToCallDbAndGenerateList(); //ado.net
problems = problems.Where(x => x.Property1 == "value").ToList();
//remaining logic
List<Solved> solved = MethodToCallDb()
.Where(x => x.SolvedId == problems.ProblemId)
.ToList();
//error happens in Where(...problems.ProblemId);
//List<Problem> does not contain a definition for ProblemId
The error says the List<Problem> does not contain ProblemId but I do have that property in my class. So I am unsure of why I am getting that error.
How can I generate my List<Solved> based on filtered results from
.Where(x => x.SolvedId == problems.SolvedId);
Using LINQ to Objects, you can use the Enumerable.Join method to create a join between two List<T>s and just return the matching members:
List<Problem> problems = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.ToList();
List<Solved> solved = MethodToCallDb()
.Join(problems, s => s.SolvedId, p => p.ProblemId, (s,p) => s)
.ToList();
However, if there are a lot of problems and solved, or if you frequently check the same list of problems, or if you are only creating problems to use in the join, you'd be better off creating a HashSet:
var problemIDs = problems.Select(p => p.ProblemId).ToHashSet();
List<Solved> solved = MethodToCallDb()
.Where(s => problemIDs.Contains(s.SolvedId))
.ToList();
NOTE: If you are only creating problems to use in the join, better to skip creating the List<Problem> and just do:
var problemIDs = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.Select(p => p.ProblemId)
.ToHashSet();
I've a structure based of list containing other list. I need to filter the list based on the value of a property based in the deepest part of the list.
Right now I'm doing this:
queryable = queryable
.Include(x => x.Carriers)
.ThenInclude(c => c.CarrierActions)
.ThenInclude(ca => ca.Action)
.ThenInclude(ac => ac.ActionFacts);
queryable = queryable
.Where(x => x.Carriers.Any(
carriers => carriers.CarrierActions.Any(
carrieractions =>
carrieractions.Action.ActionTypeId ==
ActionTypeEnum.DosemeterCalculateDeepDose)));
I join the needed tables, then I filter them based on the ActionTypeId based 3 levels below the top list.
First off all, is it possible to do this in 1 step ( include the filtering with the joins ), second of all, the second part is not working as my list gets empty, but I'm certain that actions with that type get values.
Using .NET Core 2.0.3 btw!
To answer your first part, you can do this
queryable = queryable
.Include(x => x.Carriers)
.ThenInclude(c => c.CarrierActions)
.ThenInclude(ca => ca.Action)
.ThenInclude(ac => ac.ActionFacts)
.Where(x => x.Carriers.Any(
carriers => carriers.CarrierActions.Any(
carrieractions =>
carrieractions.Action.ActionTypeId ==
ActionTypeEnum.DosemeterCalculateDeepDose)))
To your second part, it should be working, id check your data, as this is pretty straight forward
I am using new .net core and EF.
I need help with include linq command. I have some 1:N models and if the collection contais some data marked like deleted I do not want to include them.
How to do it?
var company = await _context.Company
.Include(y => y.Administrators)
.Include(y => y.CompanyPartTimers)
.Include(z => z.WorkPlaces)
.Include(z => z.Requirements)
.FirstAsync(x => x.Id == id);
If I add the condition
.Include(z => z.WorkPlaces).Where(x=>x.WorkPlaces.Where(x=>!x.IsDeleted))
It doesn't work. How to write this correctly?
Next thing is I have IDeletable Interface and it would be better if I had some custom linq expression and could do for ex.
.Include(z => z.WorkPlaces).GetNonDeleted()
Does anyone know how to do it?
I tryed something like this
public static class LinqExtension
{
public static IEnumerable<T> GetActive<T>(this IEnumerable<T> source) where T : class, IDeletable
{
return source.Where(x => x.IsDeleted);
}
}
Thanks guys.
You can configure a Query Filter in your DbContext.
modelBuilder.Entity<Administrator>()
.HasQueryFilter(admin => !EF.Property<boolean>(admin, "IsDeleted"));
should do the trick
Reference link: https://learn.microsoft.com/en-us/ef/core/querying/filters
You should change the inner condition using Any instead of Where, as:
.Include(z => z.WorkPlaces)
.Where(x => x.WorkPlaces.Any(y => !y.IsDeleted))
I have an entity with a few ordinary 1 to many relationships and one collection with implicit 1 to many relationship without any relationship defined.
What I'm trying to do is to make it work together like:
IQueryable<Employee> leftJoin =
_dbContext.EmployeeList
.GroupJoin(
inner: _dbContext.ContactList.Where(x => x.TableType == TableType.Employee),
outerKeySelector: employee => employee.EmployeeId,
innerKeySelector: contact => contact.TableId,
resultSelector: (employee, contacts) => new { employee, contacts = contacts.DefaultIfEmpty() }
)
.AsEnumerable()
.Select(x =>
{
x.employee.ContactList = x.contacts;
return x.employee;
})
.AsQueryable()
.Include(x => x.EmployeeRoleMapList);
The main hassle is I need to somehow init Employee.ContactList from joined set, within IQuerable it's not possible, I'm made to cast it to the IEnumerable but after that ordinary include doesn't work which is logical as well. Is there some workaround or some different way I could use to achieve this?
I am able to use the strongly typed LINQ Extension : .Include
result = (from A in context.Transactions.Include(_ => _.TransactionDetails)
where A.TransactionId == transactionId
select A).SingleOrDefault();
However I cannot go further within TransactionDetails. My TransactionDetails also have a navigation named User however I don't know how to put it. The available options I have inside TransactiomDetails are the regular extensions for Collections (e.g First ; FirstOrDefault,etc).
I was able to do it using the regular string method (That I want to avoid) :
result = (from A in context.Transactions.Include(_ => _.TransactionDetails)
.Include("TransactionDetails.User")
where A.TransactionId == transactionId
select A).SingleOrDefault();
Thanks
Use this:
result = context.Transactions
.Where(t => t.TransactionId == transactionId)
.Include(t => t.TransactionDetails.Select(u => u.User))
.FirstOrDefault();