LinqToSql: stop eager loading - linq-to-sql

Having set the following options to eager load a customer's orders:
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Customer>(c => c.Orders);
db.LoadOptions = dlo;
How would I then stop this and revert back to lazy loading the orders again? Or are these LoadOptions only used for the next query?

These load operations only apply to the next query.
If you have a second query that doesn't have these options set then it will do lazy loading.

Related

laravel get old records after lockForUpdate?

my code:
DB::transaction(function () {
$foo = Foo::whereId(1)->lockForUpdate()->with('bars')->first();
// dump foo & bars
// update foo's columns
// update bars' columns
});
and I run this code at the same time twice, first time it can update correctly, but the second time when I query the foo, foo's columns is correct, but the bars are still old(in database it's correct), why is it and how to solve it?
Since you are using lockForUpdate() and want to use the new data after you update, you need to re-hydrate the model using refresh()
The refresh method will re-hydrate the existing model using fresh data from the database. In addition, all of its loaded relationships will be refreshed as well:
https://laravel.com/docs/9.x/eloquent#refreshing-models
There is a great answer by NoOorZ24 # Laravel lockforupdate (Pessimistic Locking) explaining how the lock for transaction works to further clarify.

Linq to SQL prefetching multiple tables not working

I am trying to prefetch some related tables using Linq to SQL but only one table is being prefetched.
My code looks like this...
using (EVTDataContext db = new EVTDataContext(Config.ConnString))
{
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<EVT_tbEventVersion>(c => c.EVT_tbRegistrations);
loadOptions.LoadWith<EVT_tbEventVersion>(c => c.EVT_tbSubEvents);
db.LoadOptions = loadOptions;
var q = ...
EVT_tbRegistrations and EVT_tbSubEvents are both associated with EVT_tbEventVersion. If I use either of the LoadWidth line son their own they each work, but if I use both then only one works.
How can I make Linq to SQL prefetch both tables?
It seems Linq to SQL can only join a single one-to-many relationship from each table. If you try to specify more than one to preload it picks which one to preload and which others to leave deferred (ignoring LoadWith).
Answer was found at Linq2SQl eager load with multiple DataLoadOptions
I have no experience with what you are doing .. but after checking MSDN here How to: Retrieve Many Objects At Once (LINQ to SQL) I can see differences between your code and the MS example. Most notably:
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<Customer>(c => c.Orders);
ds.LoadWith<Order>(o => o.OrderDetails);
db.LoadOptions = ds;
Where the specify a different <T> for each prefetch.

LINQ-to-SQL: sorting related entity set at load time

Imagine I have two tables ShowTimes and Movies. Each Movie can have a list of related ShowTimes. Say the ShowTimes table contains a DateTime field called StartTime. The ShowTimes can appear in the table in any order (the theatre manager can add new showings at any time).
Therefore, the LINQ-to-SQL Movie object will contain a
public EntitySet<ShowTime> ShowTimes;
field, which will be loaded when it is first accessed.
Is there any way to control the sort order of ShowTimes so that it will be sorted by StartTime when it is loaded? Or must I sort it myself before I use it? Can I control the “natural order” of the ShowTimes table – by default it is sorted by primary key (an integer, in my case), can I specify that it is to be sorted by StartTime?
You can set a default sort order for child entities with DataLoadOptions.AssociateWith().
For example:
DataContext context = new DataContext();
DataLoadOptions options = new DataLoadOptions();
options.AssociateWith<Movie>(movie => movie.ShowTimes
.OrderBy(showtime => showtime.StartTime));
context.LoadOptions = options;
// do your queries here, after the LoadOptions has been set
Note that LoadOptions can only be set once on a DataContext.
Also note that DataLoadOptions can be used to eager load, child entities.
You could bypass lazy loading by using .ToList(), .ToArray(), or .ToDictionary().
IEnumerable<ShowTime> ShowTimes =
(from showtime in DataContext.ShowTimes
order by showtime.StartTime
select showtime).ToList();

Forcing LINQ to SQL to make one single call for all child rows

Let say I have a method (example taken from another post):
public IQueryable<CityBlock> GetCityBlocks(){
var results = from o in db.city_blocks
let buildings = GetBuildingsOnBlock(o.block_id) //returns Iqueryable
select new CityBlock {
BuildingsOnBlock = buildings,
BlockOwner = o.block_owner
};
return results;
}
In the calling method I add Skip() and Take() methods plus some filtering and then do a ToList().
The trouble is that I am getting dozens of database calls - one for all the city blocks and then a separate one for each building.
Is there a way that I can refactor this code to just make two calls: one for the city blocks and one for all the buildings
Should add that I have tried eager loading using:
var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<city_blocks>(x => x.buildings);
db.LoadOptions = dataLoadOptions;
but does not seem to make a difference.
Eager load in Linq to SQL is flawed, it is a lazy load performed upfront..
that is, one query per collection per entity.
So you get the same ripple load effects as lazy load, but you get them upfront.
Entity Framework 4 supports true eager load, it can issue a single query that returns all the results.
seems to be a limitation of Linq to sql:
http://codebetter.com/blogs/david.hayden/archive/2007/08/06/linq-to-sql-query-tuning-appears-to-break-down-in-more-advanced-scenarios.aspx
Are you familiar with the L2S concepts of Lazy Loading and Eager Loading? Lazy loading does what you are experiencing. It will go to the database each time a request is made for child records. Eager loading gets them all up front. You can a Google search on Linq and Lazy or Eager Loading to learn more about this.
Perhaps you could use a Join and Group By?
public IQueryable<CityBlock> GetCityBlocks(){
var results = from o in db.city_blocks
join b in db.buildings on o.block_id equals b.block_id
group by o into g
select new CityBlock {
BuildingsOnBlock = g.buildings.DefaultIfEmpty(),
BlockOwner = g.Key.block_owner
};
return results;
}

ActiveRecord caching and update_attributes

If a model changes an attribute locally, then changes it back, ActiveRecord doesn't send the change to the DB. This is great for performance, but if something else changes the database, and I want to revert it to the original value, the change doesn't take:
model = Model.find(1)
model.update_attribute(:a, 1) # start it off at 1
# some code here that changes model.a to 2
model.a = 2 # I know it changed, reflecting my local model of the change
model.update_attribute(:a, 1) # try change it back, DOESN'T WORK
The last line doesn't work because AR thinks in the DB it's still 1, even though something else changed it to 2. How can I force an AR update, or update the cache directly if I know the new value?
Side note: the code that changes it is an update_all query that locks the record, but it has side effects that mess up the cache. Multiple machines read this table. If there's a better way to do this I'd love to know.
Model.update_all(["locked_by = ?", lock_name], ["id = ? AND locked_by IS NULL", id])
Use the reload method for this.
model.reload(:select => "a")
OR
You can try the will_change! method(Its not clear how your change happens. But you can try this method).
model.update_attribute(:a, 1) # start it off at 1
model.a_will_change! #fore warn the model about the change
model.a = 2 #perform the change
model.update_attribute(:a, 1)
The answer by Harish Shetty is correct, you need to call reload on the reference, however I found a better way to do that automatically.
In your model you want to reload attribute to, create a after_update callback and call reload directly there, like so:
after_update :reload_attr
def reload_attr
reload select: "attr"
end