LINQ to SQL: On load processing of lazy loaded associations - c#

If I have an object that lazy loads an association with very large objects, is there a way I can do processing at the time the lazy load occurs? I thought I could use AssociateWith or LoadWith from DataLoadOptions, but there are very, very specific restrictions on what you can do in those. Basically I need to be notified when an EntitySet<> decides it's time to load the associated object, so I can catch that event and do some processing on the loaded object. I don't want to simply walk through the EntitySet when I load the parent object, because that will force all the lazy loaded items to load (defeating the purpose of lazy loading entirely).

Subscribe to the ListChanged Event
EntitySet<T> exposes an event called ListChanged which you can use to detect if an item is being added. Evaluate the ListChangedType property of the ListChangedEventArgs. Here's a link to the values available in the ListChangedType enum.
There is no danger of forcing the load to execute as long as you avoid requesting the enumerator.
http://msdn.microsoft.com/en-us/library/system.componentmodel.listchangedtype.aspx

I don't see any extensibility points for this available; the only thing I can see is in the FK entity there is a Created method on each individual object that gets fired from the constructor...
So the constructor calls created, and personally, I'm not 100% sure that the entity set loading creates each individual object at that time, and fires the event...
HTH.

There are a bunch of built in extensibility methods to the datacontext and data classes generated by Linq2SQL.
http://msdn.microsoft.com/en-us/library/bb882671.aspx
http://csainty.blogspot.com/2008/01/linq-to-sql-extending-data-classes.html
Either of these may be able to serve the purpose you need.

You are definitely not bound to use the default EntitySet<> but can use any IList<> collection instead. I did a little reflection on EntitySet<> but have found no hook into the Load() method, which implements enumerating the lazy source of the entity set (it's where the EntitySet actually gets queried and materialized).
Linq To SQL will use the Assign() method to assign an IEnumerable source (which is lazy by default) to your collection. Starting from there, you can implement your own lazy loading EntitySet with a custom hook at the point you first enumerate the source collection (execute the query).

Related

Custom Code on Entity Lazy Load

I've written a WPF desktop application, making use of Entity Framework to persist data (code first). I've got lazy loading enabled, which is working great.
For some of my entities, I need to implement some code every time it is instantiated through lazy loading. For example, I save some of my Datatables as lists in the database, and would like to convert these lists back to Datatables whenever the entity is lazy loaded.
I don't want to go through this conversion for the whole project necessarily (as not only can this be somewhat expensive, but for some projects the total objects can exceed available RAM). I also have all the 'custom' code that I'd like to run contained in one method. Lazy loading is therefore perfect, I just need to be able to run some custom code every time an entity is loaded.
So my question: is there any event (or other structure/pattern) that I can utilise or subscribe to so that I can run custom code every time an entity is initialised through lazy loading? I cannot use the parameterless constructor of said entity, as the properties haven't been loaded at that stage.
Thanks to the comments, I've implemented the necessary code in the appropriate get and set accessors. All properties are therefore being 'lazy loaded', which is in line with my requirements. My datatables therefore look as follows:
[NotMapped]
public DataTable MyTable
{
get
{
//Deserialize MyTable from byte[] or string property, obtained from database.
}
set
{
//Serialize MyTable to a byte[] or string property, which is saved to database.
}
}

Entity Framework Check virtual Lists after disposing of ObjectContext

My scenario is I have an object FOO which has a virtual List<bar> property on it. This is being auto generated by EF.
After I load FOO I dispose of the data context, I am turning FOO into a business object through a DTO. For example
var newFOO = FOO_Dto.change(FOO);
Inside of FOO_Dto.change I want to check if the virtual list property is empty/null. I understand that closing the ObjectContext and checking the navigation property will throw an error. In My Data Layer there are times when I return FOO with the list and FOO without the list.
My Question is how do I check the Navigation Property to see if the list has been populated or not and avoid the ObjectContext error that is currently generating
Thank you very much!!
EDIT
From the comments section, I purposely want the context closed before I check to see if I loaded the List<Bar> property.
No, you can't, other than the ugly way of trying and catching the exception. You can only determine whether a collection is loaded by getting the owner's DbEntityEntry, which you can only obtain through a context instance.
But if you know up front that the collection may be addressed outside the scope of the context, you need to load it while the context is alive, OR not load it and prevent lazy loading. You should never allow lazy loading to occur outside the lifespan of a context.
In most cases this means you'll have to turn off lazy loading and eagerly load all data required by a consuming method.
The more I work with EF in a disconnected fashion the less I allow lazy loading. I'm close to considering lazy loading an anti-pattern.

NHibernate lazy loading but no virtual properties?

I'm experiencing something rather odd. I'm tinkering with NHibernate 3.2 mapping by code and have a very simple object model I'm using just to play.
None of my properties in the entire model are marked as virtual because I dont want lazy loading. I'm mapping by code and in each class mapping I'm setting Lazy(false);
However when it comes to mapping collections, if I try and access a collection after the session has ended I get an error "failed to lazily initialize a collection of role...".
I have to explicitly set collectionMapping.Lazy(CollectionLazy.NoLazy); before it will eager load the collection. It was my understanding that lazy loading was not possible unless your properties in your model were defined at virtuals?
Have I fundamentally missed something?
virtual is needed more than just for lazy loading. NHibernate requires them to be virtual because it creates a run-time proxy of the class and injects behavior.
Virtual properties and methods are only needed for lazy associations (many-to-one or one-to-one) because NHibnerate needs to set a proxy entity on the association property.
Collections (one-to-many and many-to-many) don't need any virtual properties because only the collection is lazy, not the entities in the collection. NHibernate will always use its own collection classes, even if you disable lazy loading.
You still need to use IList<T> instead of List<T>, because NH needs its own collection implementation.
Consider:
You won't get very far in a complex model without lazy loading, except your database fits into RAM or you don't mind to cut you OO model into pieces which destroys both maintainability and performance.
You can have entities without virtual members when you use interfaces to create proxies from. However, you should only use these interfaces to reference to entities, because they could always be proxies.

EntityFramework knowing when being materialized

I realize there is an event ObjectMaterialized with gets called on ObjectContext after an object is materialized.
Is there a way to know when an object is currently being materialized?
An object can be re-materialized by being refreshed from the database. So I can't simply have a flag in my class indicating if I've already been materialized, because it may happen again.
Basically, when certain properties are being set, I'd like to know if they are being set as fresh values from the database (i.e. while being materialized), or if the application is calling them from elsewhere.
If i read the documentation correct then the ObjectMaterialized event fires only once when the entity object is created and then it is loaded from the database with a query or a load operation.
You can track object changes with ObjectStateManager but i don't know if it helps you find out the source of the change.
As pointed in answer by #BigL this event is not fired again when entity is refreshed. Materialization means creating an instance and that will happen only once. Refreshing only updates values in the existing instance and sets entity state.
You always know that properties are being set by refreshing because you must trigger that operation yourselves on the specified entity instance so you can control what ever flag you need to turn on or off your logic used when properties are set.

Ensure LINQ to SQL Entities Delete On Submit

What is the best way to mark some entities DeleteOnSubmit(). Is there a way to check and say to the context that this is for deletion?
Example: I have an Entity which reference an EntitySet<> and i delete from the EntitySet<> 4 of the 8 entities. When submitting changes i want to say DeleteOnSubmit() on those 4! This scenario should play on a single EntityRef<> too.
Of course DataContext lives in another layer so...grabbing, changing, sending back is the job.
Thank you.
This is pretty hard to answer based on the description of your architecture. Just because you're using a layered approach doesn't mean that you can't call DeleteOnSubmit... you'd just call your own method that wraps that I presume.
Unless, of course, you're instantiating your DataContext object in the update routine. in this case you'd have to do something else. Your data layer could expose a method like MarkForDelete() which just adds the entity to a collection, then expose a separate SubmitChanges() that iterates over the collected items for deletion, attaches them to the datacontext and then does the actual DeleteAllOnSubmit() call.
That said I've never really bothered with the whole entity serialization/deserialization/reattach thing as it seems fraught with peril. I usually just collect the primary keys in a list, select out the entities and re-delete them. It's no more work, really.
Take a look at DeleteAllOnSubmit(). You pass this method a list of entities to be deleted.

Categories