IN Operator between 2 collection objects - c#

In Sql, I know we have the IN operator and the equivalent of that is .Contains() in LINQ but i am stuck on one problem here
Consider the following linq query:
_dbContext.Offices.Where(o => o.Id == policy.OfficeId).FirstOrDefaultAsync()
Suppose i were to introduce a policies (plural) object which is a collection object each policy in the collection has its own officeId, how do I check if the offices collection consists of the officesId from policies collection object? I would like to do this in method syntax if possible. Thanks in advance.

Without having access to your data model, your answer does seem plausible; however, you need to have a call to .ToListAsync() at the end for this to compile. Also, it's more efficient to use Any() (rather than .Select.Contains):
await _dbContext.Offices.Where(o => policies.Any(p => p.OfficeId == o.Id)).ToListAsync();
I'm not sitting in front of a compiler, but if you just want the first one, the following is even better IIRC:
await _dbContext.Offices.FirstOrDefaultAsync(o => policies.Any(p => p.OfficeId == o.Id));

I think the following might work:
await _dbContext.Offices.Where(o => policies.Select(p => p.OfficeId).Contains(o.Id))

Related

Clearing up many-to-many in Entity Framework 6 and Entity Framework Core querying

I have to eat humble pie and admit that I thought I understood many to many in EF6 and EFCore. I have your standard example, many students many subjects scenario, but the problem comes when I try to navigate the collections to get at specific properties during projections that I get stuck and can't figure out how to use either Select or SelectMany to get at properties in my projection.
So for example how would I use either Select or SelectMany to finish this?
I need to understand properly these two LINQ methods but can anyone help me?
Here is an example of where I'm stuck:
return await _db.Subjects
.Include(s => s.Teachers)
.Include(s => s.Students)
.Where(s => s.Students.Select(x => x.Class.ClassName).Contains(classname))
.Select(s => new SubjectViewModel
{
Class = s.Students.Select(p => p.Class.ClassName)
})
So how do I complete this, do I do a SelectMany or Select? Oh and can anyone point me to some content other than MSDN to properly understand Select and SelectMany? Also can anyone show me how this would be done in EFCore? I think I just need help.
Based on what we have to work with (as #Matthew Cawley said in the comment) if you use Select you get an object of type IEnuberable<IEnumerable<string>> or IQueryable<IQueryable<string>> which is a list of lists of strings.
If you need only one list of strings you can use SelectMany to iterate just like Select but flatten the results into one collection and then applies the selector you passed p => p.Class.ClassName.
If you want to concatenate them into a single string you can use string.Join(",", <collection>) but not directly in the projection if you are using linq-to-sql because it wouldn't know how to translate that into sql code.

When using LINQ to Entities, is there a better method than casting to list in order to use unsupported code/extensions?

I find myself needing to do things like this frequently, and I'm just curious if there is a better way.
Suppose I have a class that holds a snapshot of some data:
private List<Person> _people;
In some method I populate that list from a LINQ query using Entity Framework, and perhaps I need to, for example, run a custom IEqualityComparer on it. Since this isn't supported in LINQ to entities, I end up with something like this:
_people = db.People.Where(...)
.ToList()
.Distinct(new MyCustomComparer())
.ToList();
Another example might be using an extension method, which also is not supported in LINQ to entities:
_people = db.People.Where(...)
.ToList()
.Select(_ => new { Age = _.DOB.MyExtensionMethod() })
.ToList();
In order to use either of these I have to cast the database entities into regular memory objects with the first ToList(), and then since I ultimately want a list anyway, I have a final cast ToList() at the end. This seems inefficient to me, and I'm wondering if there's a better pattern for these types of situations?
You can use AsEnumerable():
_people = db.People.Where(...)
.AsEnumerable()
.Distinct(new MyCustomComparer())
.ToList();
Which is equivalent to:
IEnumerable<Person> _people = db.People.Where(...);
_people = _people.Distinct(new MyCustomComparer()).ToList();
This is not much of an improvement, but at least it doesn't create another List<T> and is better expressing that you want to switch to the realm of IEnumerable<T> (in-memory).
See MSDN

EntityFramework 5 filter an included navigation property

I would like to find a way using Linq to filter a navigation property to a subset of related entities. I know all answers around this subject suggest doing an anonymous selector such as:
query.Where(x => x.Users.Any(y => y.ID == actingUser.ID))
.Select(x => new
{
Event = x,
Discussions = x.Discussions.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>())
})
.OrderBy(x => x.Discussions.Count())
.ThenBy(x => x.Event.Name);
However, this is significantly less than ideal due to the general nature of our query generation and also yields significantly horrific sql queries if you throw up profiler.
I would like to be able to accomplish something like:
query.Include(x => x.Discussions.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>()))
.OrderBy(x => x.Discussions.Count())
.ThenBy(x => x.Name);
I realize that this is not supported in EF5 (or any version for that matter) but there has to be a way to accomplish constraining the result set through Linq without delving into anonymous type select statements.
I have attempted doing something to the tune of:
query.GroupJoin(discquqery,
x => x.ID,
x => x.Event.ID,
(evt, disc) => evt.Discussions = disc.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>())).ToList();
However you cannot have assignment inside a lambda expression and selecting an anonymous type here causes the same dilemma that it does using the select.
I guess I cannot comprehend why EF does not provide a way (that I can find) to generate:
SELECT
--Properties
FROM Event e
LEFT OUTER JOIN Discussions d
ON e.ID = d.EventID AND --Additional constraints
WHERE
--Where conditions
ORDER BY
--Order Conditions
It is so simple to constrain the join in SQL there HAS to be a way to do it through Linq as well.
PS: I have searched stack, MSDN, experts-exchange, etc. Please realize this is not a duplicate. Anything even touching on this subject either has a cop-out "It can't be done" answer or no answer at all. Nothing is impossible... including this.
Anything even touching on this subject either has a cop-out "It can't
be done" answer or no answer at all. Nothing is impossible...
including this.
Sure. It is possible. You can download EF source code and add this feature yourselves. It will be great contribution to open source project and the community. I believe EF team will gladly help you with your effort.
With the current version "it can't be done" is the answer. You can either use projection to anonymous or special unmapped type as you have described in the beginning of your question. Other options are separate explicit query to load related entities for single parent or separate query to load related entities for all parents.
Load relations for single parent:
context.Entry(event)
.Collection(e => e.Discussions)
.Query()
.Where(d => ...)
.Load();
Load relations for all parents (requires lazy loading to be turned off):
// load all parents
var events = query.Where(e => ...).ToList();
// load child filtered by same condition for parents and new condition for children
childQuery.Where(d => e.Event ... && d.Something ...).Load();
The second solution requires child to have navigation property back to parent (for constructing same query condition used initially to loads parent). If you have everything correctly configured and entities are attached EF should automatically fix your relations (collections) in parent entities (but it will not mark collection in dynamic proxy as loaded so that is the reason why you cannot use this together with lazy loading).

Why the order of LINQ to objects methods counts

I read this question's answers that explain the order of the LINQ to objects methods makes a difference. My question is why?
If I write a LINQ to SQL query, it doesn't matter the order of the LINQ methods-projections for example:
session.Query<Person>().OrderBy(x => x.Id)
.Where(x => x.Name == "gdoron")
.ToList();
The expression tree will be transformed to a rational SQL like this:
SELECT *
FROM Persons
WHERE Name = 'gdoron'
ORDER BY Id;
When I Run the query, SQL query will built according to the expression tree no matter how weird the order of the methods.
Why it doesn't work the same with LINQ to objects?
when I enumerate an IQueryable all the projections can be placed in a rational order(e.g. Order By after Where) just like the Data Base optimizer does.
Why it doesn't work this way with LINQ to objects?
LINQ to Objects doesn't use expression trees. The statement is directly turned into a series of method calls, each of which runs as a normal C# method.
As such, the following in LINQ to Objects:
var results = collection.OrderBy(x => x.Id)
.Where(x => x.Name == "gdoron")
.ToList();
Gets turned into direct method calls:
var results = Enumerable.ToList(
Enumerable.Where(
Enumerable.OrderBy(collection, x => x.Id),
x => x.Name = "gdoron"
)
);
By looking at the method calls, you can see why ordering matters. In this case, by placing OrderBy first, you're effectively nesting it into the inner-most method call. This means the entire collection will get ordered when the resutls are enumerated. If you were to switch the order:
var results = collection
.Where(x => x.Name == "gdoron")
.OrderBy(x => x.Id)
.ToList();
Then the resulting method chain switches to:
var results = Enumerable.ToList(
Enumerable.OrderBy(
Enumerable.Where(collection, x => x.Name = "gdoron"),
x => x.Id
)
);
This, in turn, means that only the filtered results will need to be sorted as OrderBy executes.
Linq to objects's deferred execution works differently than linq-to-sql's (and EF's).
With linq-to-objects, the method chain will be executed in the order that the methods are listed—it doesn't use expression trees to store and translate the whole thing.
Calling OrderBy then Where with linq-to-objects will, when you enumerate the results, sort the collection, then filter it. Conversely, filtering results with a call to Where before sorting it with OrderBy will, when you enumerate, first filter, then sort. As a result the latter case can make a massive difference, since you'd potentially be sorting many fewer items.
Because, with LINQ for SQL, the SQL grammar for SELECT mandates that the different clauses occur in a particular sequence. The compiler must generate grammatically correct SQL.
Applying LINQ for objects on an IEnumerable involves iterating over the IEnumerable and applying a sequence of actions to each object in the IEnumerable. Order matters: some actions may transform the object (or the stream of objects itself), others may throw objects away (or inject new objects into the stream).
The compiler can't divine your intent. It builds code that does what you said to do in the order in which you said to do it.
It's perfectly legal to use side-effecting operations. Compare:
"crabapple"
.OrderBy(c => { Console.Write(c); return c; })
.Where(c => { Console.Write(c); return c > 'c'; })
.Count();
"crabapple"
.Where(c => { Console.Write(c); return c > 'c'; })
.OrderBy(c => { Console.Write(c); return c; })
.Count();
Linq to Objects does not reorder to avoid a would-be run-time step to do something that should be optimized at coding time. The resharpers of the world may at some point introduce code analysis tools to smoke out optimization opportunities like this, but it is definitely not a job for the runtime.

Can I use array in the LINQ where expression?

Would it be possible to use something like .Where(u => u.License_ID == ID) with ID being an array?
The code
Where(u => IDs.Contains(u.License_ID))
could work, but it depends on your database provider whether it supports that. If this is not a database query, but LINQ to objects, it will certainly work.
If the array contains custom objects, you could always write an extension method like
Equals(this Array[] _Array)
And define in there what are the requirements for equality.
Then your code becomes:
.Where(u => u.License_ID.Equals(ID))
And it would be highly reusable =)

Categories

Resources