At runtime I have a dynamic list of "Parent" ids i need to query against one of my entity tables, using LINQ how would I generate the query at run time? Currently am (VERY SLOWLY) looping over my list of ID's and performing a separate query to the database using the Where method. Is there an API that will allow me to build a single WHERE statement that in essence is appending "&& value = something" as I would have if I was writing the SQL myself?
Currently what i do looks like this
foreach(var parent in parents)
{
col.AddRange(context.LocalAuthorities.Where(c => c.Parent.ID == parent.ID).ToList());
}
If your goal is to replace multiple iterative queries by one query, you can use this approach:
var allParentIds = parents.Select(p=>p.ID).ToList();
var result = context.LocalAuthorities.Where(c=> allParentIds.Contains(c.Parent.ID));
col.AddRange(result);
Related
Greetings Everyone
I am using EF6 and VS13 Free Community.
I followed a database First Approach.
I currently have a project (.net mvc) that contains multiple databases and tables
i am using the Entities & Linq queries and i couldn't figure out how to use the result of the queries i create when it's inside an if statement i saw solution but it only works when i use a single table not multiple ones. Example :
var query = from varA in db1.table_name
from varB in db2.table_name
where
varA.X = varB.X
select new
{
varA.stuff,
varB.something
}
Resolved didn't search deep enough
a foreach did it for me
foreach (var result in query)
{
...
}
I'm using NHibernate 3.2 and I have a repository method that looks like:
public IEnumerable<MyModel> GetActiveMyModel()
{
return from m in Session.Query<MyModel>()
where m.Active == true
select m;
}
Which works as expected. However, sometimes when I use this method I want to filter it further:
var models = MyRepository.GetActiveMyModel();
var filtered = from m in models
where m.ID < 100
select new { m.Name };
Which produces the same SQL as the first one and the second filter and select must be done after the fact. I thought the whole point in LINQ is that it formed an expression tree that was unravelled when it's needed and therefore the correct SQL for the job could be created, saving my database requests.
If not, it means all of my repository methods have to return exactly what is needed and I can't make use of LINQ further down the chain without taking a penalty.
Have I got this wrong?
Updated
In response to the comment below: I omitted the line where I iterate over the results, which causes the initial SQL to be run (WHERE Active = 1) and the second filter (ID < 100) is obviously done in .NET.
Also, If I replace the second chunk of code with
var models = MyRepository.GetActiveMyModel();
var filtered = from m in models
where m.Items.Count > 0
select new { m.Name };
It generates the initial SQL to retrieve the active records and then runs a separate SQL statement for each record to find out how many Items it has, rather than writing something like I'd expect:
SELECT Name
FROM MyModel m
WHERE Active = 1
AND (SELECT COUNT(*) FROM Items WHERE MyModelID = m.ID) > 0
You are returning IEnumerable<MyModel> from the method, which will cause in-memory evaluation from that point on, even if the underlying sequence is IQueryable<MyModel>.
If you want to allow code after GetActiveMyModel to add to the SQL query, return IQueryable<MyModel> instead.
You're running IEnumerable's extension method "Where" instead of IQueryable's. It will still evaluate lazily and give the same output, however it evaluates the IQueryable on entry and you're filtering the collection in memory instead of against the database.
When you later add an extra condition on another table (the count), it has to lazily fetch each and every one of the Items collections from the database since it has already evaluated the IQueryable before it knew about the condition.
(Yes, I would also like to be the extensive extension methods on IEnumerable to instead be virtual members, but, alas, they're not)
I have two Entity Framework 4 Linq queries I wrote that make use of a custom class method, one works and one does not:
The custom method is:
public static DateTime GetLastReadToDate(string fbaUsername, Discussion discussion)
{
return (discussion.DiscussionUserReads.Where(dur => dur.User.aspnet_User.UserName == fbaUsername).FirstOrDefault() ?? new DiscussionUserRead { ReadToDate = DateTime.Now.AddYears(-99) }).ReadToDate;
}
The linq query that works calls a from after a from, the equivalent of SelectMany():
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count()
};
The query that does not work is more like a regular select:
from d in oc.Discussions
where d.Group.Name == "Student"
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count(),
};
The error I get is:
LINQ to Entities does not recognize the method 'System.DateTime GetLastReadToDate(System.String, Discussion)' method, and this method cannot be translated into a store expression.
My question is, why am I able to use my custom GetLastReadToDate() method in the first query and not the second? I suppose this has something to do with what gets executed on the db server and what gets executed on the client? These queries seem to use the GetLastReadToDate() method so similarly though, I'm wondering why would work for the first and not the second, and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different other LINQ queries.
Please note all these queries are sharing the same object context.
I think your better of using a Model Defined Function here.
Define a scalar function in your database which returns a DateTime, pass through whatever you need, map it on your model, then use it in your LINQ query:
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > myFunkyModelFunction(fbaUsername, p.Discussion)).Count()
};
and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different places LINQ queries.
A stored procedure would probably be one way to store that 'common query syntax"...EF, at least 4.0, works very nicely with SP's.
DynamicObject LINQ query with the List compiles fine:
List<string> list = new List<string>();
var query = (from dynamic d in list where d.FirstName == "John" select d);
With our own custom class that we use for the "usual" LINQ compiler reports the error "An expression tree may not contain a dynamic
operation":
DBclass db = new DBclass();
var query = (from dynamic d in db where d.FirstName == "John" select d);
What shall we add to handle DynamicObject LINQ?
Does DBClass implement IEnumerable? Perhaps there is a method on it you should be calling to return an IEnumerable collection?
You could add a type, against which to write the query.
I believe your problem is, that in the first expression, where you are using the List<>, everything is done in memory using IEnumerable & Link-to-Objects.
Apparently, your DBClass is an IQueryable using Linq-to-SQL. IQueryables use an expression tree to build an SQL statement to send to the database.
In other words, despite looking much alike, the two statements are doing radically different things, one of which is allowed & one which isn't. (Much in the way var y = x * 5; will either succeed or fail depending on if x is an int or a string).
Further, your first example may compile, but as far as I can tell, it will fail when you run it. That's not a particular good benchmark for success.
The only way I see this working is if the query using dynamic is made on IEnumerables using Link-to-Objects. (Load the full table into a List, and then query on the list)
I am trying to figure out how to dynamically specify the properties for my select clause in a linq query.
Lets say I have a collection of employee objects. At run time, the end user will be specifying which properties they would like to see for those employees, so I need to be able to dynamically construct my Linq select clause.
I have used the dynamic Linq library, but I prefer not to use that, because it requires me to build a string to pass to the select method. I'd like to understand how to do this via Expressions.
This looks like something that fits more with your requirements of not using dynamic linq.
Use Reflection to get the dynamic Column Values
//columns variable has column name as comma separated String which you
can save in DB //example string columns ="Name,Id,Age";
var strColumns =columns.split(,);
foreach(var myObject in MyObjectcollection)
{
for(int index =0;index<strColumns.count();index++)
{
//Create a collection of objects
mycollection.add(myObject.GetType().GetProperty(strColumns[index]).GetValue(myObject, null));
}
}