I am using linq to select a bunch of objects by Id through a facade object. This facade has a function GetObjectById(string id) which returns a MyObject. I select a bunch of object in one query based on a list of ids:
IEnumerable<MyObject> objects =
from id in ids
select facade.GetObjectById(id);
Then later I set some value on my objects like so:
foreach(MyObject object in objects)
{
object.someValue = "banaan";
}
Later when I inspect the objects IEnumerable, someValue is not set to "banaan".
It looks like it has something to do with the deferred execution of linq because when I put .ToList() behind the first query I does work. However, I thought I should be able to do something like this. What am I doing wrong here? Or is my understanding of how you should use linq wrong?
Thanks in advance.
Sure it is the problem of deferred execution. If the query is executed again it will again call your facade method during and if the facade method loads data from somewhere (= create new instances) your former changes are lost. Your foreach is first execution and inspection outside of the first foreach is second execution.
You must call ToList if you want to operate on the same instances in such scenario.
When you inspect the objects the second time, do you re-evaluate the objects enumerable? Because that would make it call facade.GetObjectById(id) again.
Try to materialize the enumerable instead. Something like this:
IEnumerable<MyObject> objects =
(from id in ids
select facade.GetObjectById(id)).ToArray();
I'm assuming you're running a SQL server somewhere from which the data comes from?
The query will remain in LINQ to SQL space until, as suggested in both previous answers, you call ToList() or ToArray() or similar. Only then does it actually become LINQ to Object, and is the data instantiated and will it persist in your program's memory space.
In this way, after your changes to your list, you can execute the same query again and get a different list which does not have your changes in it.
Maybe a better explanation is the following:
(from id in ids select facade.GetObjectById(id)).Where(o=>string.IsNullOrEmpty(o.Name))
This will give an error because there is no translation from string.IsNullOrEmpty to SQL.
(from id in ids select facade.GetObjectById(id)).ToList().Where(o=>string.IsNullOrEmpty(o.Name))
This will not give an error, because after the ToList() you are in object space.
Related
In one of my Doctrine record classes, I have a preSave method that performs a check. In this check, a query is done on the same table that my record belongs to. This query will fetch one record from the table, and I use the hydrated result to compare to the current record represented by the class.
In some cases, the fetched hydrated result will be the same record as the one I'm working with in the preSave check. However, when this happens, any changes that I've made to the first record are reverted once the query is completed.
Why does this happen? Is there a workaround?
Doctrine might be maintaining a single reference to the record object instance, and not creating a whole new instance in your preSave() method. So when the object is hydrated, any other variables of the same type in your code are 'refreshed'.
To verify this, inspect the object ID's of variables in your code using spl_object_hash() function.
Without seeing your code, workaround suggestions can vary, but one possible workaround is to hydrate an array in preSave():
$query = Doctrine_Query::create()
->select('foo')
->from('Bar b')
->where('b.id = ?', $id);
$results = $query->execute(array(), Doctrine::HYDRATE_ARRAY);
You will lose the ability to use the result as an object, but you will be able to use the contents of the array for comparisons.
I've noticed that depending on how I extract data from my Entity Framework model, I get different types of results. For example, when getting the list of employees in a particular department:
If I pull directly from ObjectContext, I get an IQueryable<Employee>, which is actually a System.Data.Objects.ObjectQuery<Employee>:
var employees = MyObjectContext.Employees.Where(e => e.DepartmentId == MyDepartment.Id && e.SomeCondtition)
But if I use the Navigation Property of MyDepartment, I get an IEnumerable<Employee>, which is actually a System.Linq.WhereEnumerableIterator<Employee> (private class in System.Linq.Enumerable):
var employees = MyDeparment.Employees.Where(e => e.SomeCondtition)
In the code that follows, I heavily use employees in several LINQ queries (Where, OrderBy, First, Sum, etc.)
Should I be taking into consideration which query method I use? Will there be a performance difference? Does the latter use deferred execution? Is one better practice? Or does it not make a difference?
I ask this because since installing ReShaper 6, I'm getting lots of Possible multiple enumeration of IEnumerable warnings when using the latter method, but none when using direct queries. I've been using the latter method more often, simply because it's much cleaner to write, and I'm wondering if doing so has actually had a detrimental effect!
There is very big difference.
If you are using the first approach you have IQueryable = exression tree and you can still add other expressions and only when you execute the query (deferred execution) the expression tree will be converted to SQL and executed in the database. So if you use your first example and add .Sum of something you will indeed execute operation in the database and it will transfer only single number back to your application. That is linq-to-entities.
The second example uses in memory collection. Navigation property doesn't represent IQueryable (expression tree). All linq commands are treated as linq-to-objects = all records representing related data in navigation property must be first loaded from database to your application and all operations are done in memory of your application server. You can load navigation property eagerly (by using Include), explicitly (by using Load) or lazily (it is just done automatically when you access the property for the first time if lazy loading is enabled). So if you want to have sum of something this scenario requires you to load all data from database and then execute the operation locally.
I am using an IList<Employee> where i get the records more then 5000 by using linq which could be better? empdetailsList has 5000
Example :
foreach(Employee emp in empdetailsList)
{
Employee employee=new Employee();
employee=Details.GetFeeDetails(emp.Emplid);
}
The above example takes a lot of time in order to iterate each empdetails where i need to get corresponding fees list.
suggest me anybody what to do?
Linq to SQL/Linq to Entities use a deferred execution pattern. As soon as you call For Each or anything else that indirectly calls GetEnumerator, that's when your query gets translated into SQL and performed against the database.
The trick is to make sure your query is completely and correctly defined before that happens. Use Where(...), and the other Linq filters to reduce as much as possible the amount of data the query will retrieve. These filters are built into a single query before the database is called.
Linq to SQL/Linq to Entities also both use Lazy Loading. This is where if you have related entities (like Sales Order --> has many Sales Order Lines --> has 1 Product), the query will not return them unless it knows it needs to. If you did something like this:
Dim orders = entities.SalesOrders
For Each o in orders
For Each ol in o.SalesOrderLines
Console.WriteLine(ol.Product.Name)
Next
Next
You will get awful performance, because at the time of calling GetEnumerator (the start of the For Each), the query engine doesn't know you need the related entities, so "saves time" by ignoring them. If you observe the database activity, you'll then see hundreds/thousands of database roundtrips as each related entity is then retrieved 1 at a time.
To avoid this problem, if you know you'll need related entities, use the Include() method in Entity Framework. If you've got it right, when you profile the database activity you should only see a single query being made, and every item being retrieved by that query should be used for something by your application.
If the call to Details.GetFeeDetails(emp.Emplid); involves another round-trip of some sort, then that's the issue. I would suggest altering your query in this case to return fee details with the original IList<Employee> query.
I posted a couple of questions about filtering in an eager loading query, and I guess the EF does not support filtering inside of the Include statement, so I came up with this.
I want to perform a simple query where get a ChildProdcut by sku number and it PriceTiers that are filtered for IsActive.
Dim ChildProduct = ChildProductRepository.Query.
Where(Function(x) x.Sku = Sku).
Select(Function(x) New With {
.ChildProduct = x,
.PriceTiers = x.PriceTiers.
Where(Function(y) y.IsActive).
OrderBy(Function(y) y.QuantityStart)
}).Select(Function(x) x.ChildProduct).Single
Is there a more efficient way of doing this? I am on the right track at all? It does work.
Another thing I really don't understand is why does this work? Do you just have to load an object graph and the EF will pick up on that and see that these collections belong to the ChildProduct even though they are inside of an anonymous type?
Also, what are the standards for formatting a long LINQ expression?
Is there a more efficient way of doing this? I am on the right track at all?
Nope, that's about the way you do this in EF and yes, you're on the right track.
Another thing I really don't understand is why does this work?
This is considered to be a bit of a hack, but it works because EF analyzes the whole expression and generates one query (it would look about the same as if you just used Include, but with the PriceTiers collection filtered). As a result, you get your ChildProducts with the PriceTiers populated (and correctly filtered). Obviously, you don't need the PriceTiers property of your anonymous class (you discard it by just selecting x.ChildProduct), but adding it to the LINQ query tells EF to add the join and the extra where to the generated SQL. As a result, the ChildProduct contains all you need.
If this functionality is critcal, create a stored procedure and link entity framework to it.
I need to convert a Session object to an IOrderedQueryable and came up blank. I've thought of creating a wrapper, but its not working properly. Basically, I am pulling a Linq query and would like to store it so that I don't have to pull it each time I visit. There are up to 7-10 parameters per user so it's not something that's great for caching.
I can simply cast my Session object as an IOrderedQueryable like:
(IOrderedQueryable<T>)Session["myObject"];
It seems you want to store the data returned by the linq query, if that's the case you need to make it grab the data i.e. by using .ToList() and storing that.