How to manually override property OnLoad method in NHibernate? - c#

Is it possible to manually change an entity when it's loaded from the database by NHibernate. Is there an OnLoad event listener which we can override or inherit from which will allow us to manually set an entity.
For clarity, we wish to assign a custom entity when the property is null. We are successfully doing the opposite when we persist to the database however would rather implement the logic in an NHibernate listener rather than in the property "Getter".
Please note we do not want to use IInterceptors as we are using the latest version of NHibernate.

You can implement IPostLoadEventListener. It's just one method:
void OnPostLoad(PostLoadEvent #event)
Which I think is exactly what you want.

Related

Can I tell linq 2 SQL not to update certain columns after attachment or use of UpdateModel?

Let's assume I have the following situation, the update method in my service accepts a model (the one that is going to be updated) as an input parameter. The model can be unattached (in which case attach method is called before submitting changes) or attached (in which case we just submit changes). Edit actions just call this update method in my service. Now let's assume I cannot change the code in those actions (the code that produces the model to be updated). Can I still somehow prevent certain columns from updating from within the update method. Note that I might want to set those columns using linq to SQL, but only during insert method.
I'm quite sure I'm trying something unconventional here, but it might help me write some easy to reuse code. If it cannot be done, then I'll solve it differently, but it never hurts to try something new.
The Attach method does provide an override to accept both a modified and original entity.
Attach Modified Entity on Data Context
When using this the internal change tracker will figure out which columns have been updated and will only update those ones on the datasource which have changed, rather than updating all columns.
Alternatively if you want more explicit control over which properties are updated, you can reattach your entity as unmodified in its original state:
Attach Modified/Unmodified Entity on Data Context
This will hook up the internal change tracker to the PropertyChanging events on the entity so it can be tracked. You would then simply change the values of the properties on that entity in the Update method on your Service.
void Update(MyModel model)
{
using (MyContext ctx = new MyContext())
{
ctx.DeferredLoadingEnabled = false;
ctx.MyEntities.Attach(model.OriginalEntity);
model.OriginalEntity.Value = model.ModifiedEntity.Value;
ctx.SubmitChanges();
}
}
The pitfall of these approaches means you must maintain both the original and modified entities in your model, but could be set when your entities are loaded - a simple shallow copy of the object should do the trick by deriving from ICloneable in a partial class for each entity.

Entity Framework On-The-Fly serialization/encryption of properties

Is that possible to serialize/deserialize a string property of an Entity by using its getters and setters on access, on save?
There are two main goals I would like to do for string properties.
1-Keep a json serialized string for special, complex or custom column types.
2-Encrypt on saving, decyrpt on access confidential information, i.e. Email address
Is that possible?
If so, do we have a limited usage of linq queries on this entity?
If so, would fetching all records and trigger their decryption/deserialization would work?
You could use the SavingChanges event to modify the entity right before saving it.
Then use the ObjectMaterialized event to handle when the properties are loaded into the entity.
Obviously, these events could be a little bit of overkill but I think you can have a lot of control and you may not want to attach event handlers every time you use the context.

NHibernate instantiate collections on save

I am using NHibernate to persist my entities in the database. MY entities have some relationships between them resulting into some mapped collections. I my case I use the Iesi.ISet interface to map these collections. I was wondering if it's possible for nhibernate to check if the properties containing those collections to be automatically set when I execute save if they are null.
This is how it should work. I have a property with a collection called "MyCollection" that is null before I save it to the database. I want NHibernate to set a collection to that property so that it's not null anymore on save. Is this possible?
This is what your constructors are for.
If you very much want to hide such initialization behind NHibernate you might be able to inject the code for this using an NHibernate interceptor or event listener.

LinqToSQL and auditing changed fields

Here's another one of these LinqToSQL questions where I'm sure I must have missed the boat somewhere, because the behavior of the O/R Designer is very puzzling to me...
I have a base class for my LinqToSQL tables, which I called LinqedTable. I've successfully used reflection to get hold of all the properties of the descendant classes and do other standard stuff.
Now I want to have some automatic auditing of my tables, so that whenever a LinqedTable record is inserted or deleted, or a field value changes, I will insert a record into an audit table, detailing the change type, the field name, and its value pre- and post-save.
I thought I would be able to do it using the PropertyChanging event, keeping track of all the changed properties before a save, then clearing the collection of changes after each SubmitChanges() call. But - the generated code from the O/R designer, for some bizarre reason, doesn't give you the property name in the PropertyChanging event - it sends an empty string! (WHY?!) It does send the property name in the PropertyChanged event, but that's already too late for me to get the original value.
I thought to grab all the original values of all properties using the OnLoaded() partial method - but that is private by definition, and I need access to that method in the base class. Even if I used reflection to get hold of that method, that would mean I would have to implement the other half of the partial method for every one of my tables, which kinda defeats the purpose of having inheritance!
I also can't find any suitable method in the DataContext to use or override.
So what would you recommend to get this audit functionality working?
You can use GetChangeSet on the DataContext to retrieve a list of updates, inserts and deletes that have occurred on all tables within a context. You can use ITable.GetOriginalEntityState to retrieve the original values of a changed entity. However, when you retrieve the original values of a deleted or updated record, the associations will not be available so you will have to rely on foreign key values only in that area if you need to process related entities. You can Use ITable.GetModifiedMembers to help retrieve only values that have changed.
Forgive me for perhaps a stupid answer, but how about doing the audit directly in the SQL Server using triggers (if you are in SQL Server 2005 or 2008 standard) or using the change tracking facilities in SQL server 2008 Enterprise?

Changing Entities in the EntityFramework

I have the following scenario:
Entities are loaded from the database.
One of them is presented to the user in a Form (a WPF UserControl) where the user can edit properties of that entity.
The user can decide to apply the changes to the entity or to cancel the editing.
How would I implement something like this with the EntityFramework?
My problem is that, when I bind the UI directly to the Properties of the Entity, every change is instantanously applied to the entity. I want to delay that to the moment where the user presses OK and the entity is validated successfully.
I thought about loading the Entities with NoTracking and calling ApplyPropertyChanges after the detached entity has been validated, but I'm not entirely sure about the correct way to do that. The docu of the EntityFramework at MSDN is very sparse.
Another way I could think of is to Refresh the entity with StoreWins, but I don't like resetting the changes at Cancel instead of applying changes at Ok.
Has anyone a good tutorial or sample?
One options is what you said do a no-tracking query.
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);
Then the customer can modify 'customer' as required in memory, and nothing is actually happening in the context.
Now when you want actually make the change you can do this:
// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();
Now if you are uncomfortable with the query either for performance or concurrency reasons, you could add a new extension method AttachAsModified(...) to ObjectContext.
that looks something like this:
public static void AttachAsModified<T>(
this ObjectContext ctx,
string entitySet,
T entity)
{
ctx.AttachTo(entitySet, entity);
ObjectStateEntry entry =
ctx.ObjectStateManager.GetObjectStateEntry(entity);
// get all the property names
var propertyNames =
from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
select s.FieldType.Name;
// mark every property as modified
foreach(var propertyName in propertyNames)
{
entry.SetModifiedProperty(propertyName);
}
}
Now you can write code like this:
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();
And now you have no concurrency or extranous queries.
The only problem now is dealing with FK properties. You should probably look at my index of tips for help here: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx
Hope this helps
Alex
I suggest IEditableObject, too, and additionally IDataErrorInfo.
The way i do it is, i basically have a viewmodel for an entity that takes the entity as constructor parameter (basically a wrapper object).
In BeginEdit, i copy the entity properties to my viewmodel, so if i do CancelEdit, the data is only changed in the ViewModel and the original Entity hasn't changed. In EndEdit, i just apply the ViewModel properties to the Entity again, or course only if validation has succeeded.
For validation i use the methods of IDataErrorInfo. I just implement IDataErrorInfo.Error so that it checks each Property name via IDataErrorInfo[string columnName] and concatenates eventual error messages. If it's empty, everything is ok. (not sure if Error is meant to be used that way, but i do it)
If i have other Entities attached to my original Entity, such as Customer.Orders, i create them as nested ViewModels in the original Entity's ViewModel. The original ViewModel calls it's subModels' Begin-,Cancel-,EndEdit / Error methods in it's own implementations of those methods then.
It's a bit more work, but i think it's worth it because between BeginEdit and EndEdit, you can be pretty sure that nothing changes without you noticing it. And having a code snippet for INotifyPropertyChanged-enabled properties helps a lot, too.
The normal way of doing this is binding to something that implements IEditableObject. If and how that fits in with the entity framework, I'm not sure.

Categories

Resources