Print Page | Close Window

Property Interceptors not fired on Foreign Key property when setting Navigation Property

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3886
Printed Date: 13-May-2026 at 12:56am


Topic: Property Interceptors not fired on Foreign Key property when setting Navigation Property
Posted By: stephenmcd1
Subject: Property Interceptors not fired on Foreign Key property when setting Navigation Property
Date Posted: 11-Jan-2013 at 1:40pm
As the title says, we are running into problems where a Set interceptor isn't fired when we'd expect it to.  We have a set interceptor attached to a foreign key property.  Then when we assign the corresponding navigation property, we'd expect our interceptor to be fired since the value is changing/changed.  But the interceptor is not fired.

From the ' http://drc.ideablade.com/xwiki/bin/view/Documentation/entity-set-a-property#HSetpipeline-1 - Get and set a property ' page, it seems to imply that interception should happen on the foreign key property:

The set pipeline for a reference property is more complex than for an ordinary data property.  Because both the navigation property reference and the corresponding foreign key property are set, there are more opportunities for interception and validation, and more events are raised.

We also have a lot of logic that assumes that we'll get notified when the value is changed....and in this case, it's easy for our interceptors to not get told about a change in the property.

In case my description is not clear enough, I've included some code to show the kind of scenario I'm talking about:
public void TestForeignKeyInterceptors()
{
    var em = new EntityManager(shouldConnect: false);

    //Make an order
    var order = em.CreateEntity<Order>();
    order.EntityAspect.AddToManager();

    //Make a customer - and generate a new ID for it
    var customer = em.CreateEntity<Customer>();
    customer.CustomerID = Guid.NewGuid();
    customer.EntityAspect.AddToManager();

    //The CustomerID field should currently be NULL
    var originalCustomerId = order.CustomerID;
    Assert.IsNull(originalCustomerId);

    //Various bools used to see what things get fired
    var propertyChangeFired = false;
    var afterSetFired = false;
    var beforeSetFired = false;

    //Add before and after set interceptors to the CustomerID field
    Order.PropertyMetadata.CustomerID.SetterInterceptor.AddAction(
        PropertyInterceptorTiming.After,
        args => { afterSetFired = true; });

    Order.PropertyMetadata.CustomerID.SetterInterceptor.AddAction(
        PropertyInterceptorTiming.Before,
        args => { beforeSetFired = true; });

    //Also watch for property change notifications
    order.PropertyChanged += (s, e) =>
        {
            if (e.PropertyName == "CustomerID")
                propertyChangeFired = true;
        };

    //Assign the customer entity - this will trigger the Customer and CustomerID fields to get changed
    order.Customer = customer;

    //Verify that the CustomerID did in fact get updated
    var newCustomerId = order.CustomerID;
    Assert.AreEqual(customer.CustomerID, newCustomerId);
    Assert.AreNotEqual(originalCustomerId, newCustomerId);

    //Now see what things got fired

    //PropertyChanged event is raised
    Assert.IsTrue(propertyChangeFired); 

    //But before and after set interceptors don't.  These next two tests will fail.
    Assert.IsTrue(afterSetFired); //Fails
    Assert.IsTrue(beforeSetFired);//Fails
}

Thanks!



Replies:
Posted By: kimj
Date Posted: 11-Jan-2013 at 4:08pm
You're right that the documentation would seem to imply that property interceptors are fired for both the navigation property and its associated foreign key property.  In actuality this is not the case, and interceptors (and verifiers) are fired for only the navigation property when the navigation property is set. 
 
In your use case, interceptor actions on the Order.PropertyMetadata.Customer.SetterInceptor will fire as expected.  If this is insufficient we can look at a feature request to support this.


Posted By: stephenmcd1
Date Posted: 14-Jan-2013 at 11:14am
Yes, I guess I didn't really have a clear question/request in my original post.  For our application, we would like interceptors to fire on the FK property in addition to the navigation property.  It sounds like this isn't a bug report....and instead, I'm making a feature request.

What is the chance that such a feature would get implemented?  I'm guessing DevForce 2010 might not be getting many new features?  But perhaps in DevForce 2012?

Thanks


Posted By: kimj
Date Posted: 15-Jan-2013 at 4:12pm
Stephen, we don't think the extra complexity in the already quite complex setter pipeline warrants a change, especially when there are several possible workarounds.
There are quite a few ways of adding interceptor actions, and it should be possible to add a general purpose action for these situations.
 
For example, if you're using attributed interceptors, an action such as the following should give you the flexibility you need:
 
[BeforeSet(EntityPropertyNames.Customer)]
[BeforeSet(EntityPropertyNames.CustomerID)]
private void BeforeSetCustomer(IPropertyInterceptorArgs args) {
  // common action
}
 
Or similarly, if dynamically adding actions:
Action<IPropertyInterceptorArgs> pa = args => beforeSetFired = true;
Order.PropertyMetadata.CustomerID.SetterInterceptor.AddAction(PropertyInterceptorTiming.Before, pa);
Order.PropertyMetadata.Customer.SetterInterceptor.AddAction(PropertyInterceptorTiming.Before, pa);
 
DevForce will pass the appropriate concrete arguments to an action, as long as the arguments can be coerced into what the action will accept.  In the code above, these actions, since they take an IPropertyInterceptorArgs type, could also be used for AfterSet processing, or even for getter interception.


Posted By: stephenmcd1
Date Posted: 04-Feb-2013 at 4:22pm
Thanks Kim, I was mostly expecting that kind of response.  I understand the interceptor logic is probably very complicated so I knew it was a long shot.  I've spent some time looking in to alternate ways for us to implement this and I have a few ideas - although, I think it will be non-trivial.  Thanks for those tips, though - I think it will come in handy.  As with everything we've run into, DevForce is always powerful/flexible enough for us to tweak things to get them to work with our architecture...even if it takes a little extra work.



Print Page | Close Window