New Posts New Posts RSS Feed: Binding to and managing collection navigation properties
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Binding to and managing collection navigation properties

 Post Reply Post Reply
Author
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Topic: Binding to and managing collection navigation properties
    Posted: 13-Jan-2011 at 3:20pm
I received an email with some perceptive questions. Here is that email and my response:
 
=== The Questions ===
 

Would you say that if a view has a grid, the grid should most always be populated by a parent.child relationship such as Member.Invoices instead of an ObservableCollection such as Invoices?

 

After the save of a child entity using the above parent.child relationship how do I tell the data binding to refresh the view because a new entity has been added to the grid?

 

Would I raise OnPropertyChanged(“”) ; should the property name be “ Member.Invoices” ?

 
===  My Reply ===
 

Would you say that if a view has a grid, the grid should most always be populated by a parent.child relationship such as Member.Invoices instead of an ObservableCollection such as Invoices?

 

No, I would not say that. In fact, I would ONLY display a child collection in the grid if the grid were ReadOnly.

 

I feel rather strongly that Member.Invoices.Add and Member.Invoices.Remove should never be called and I would have removed them from the public API if I could. Why? Because I think business logic should guard whether a child can be added or removed from a parent and there is no way known to me for injecting that logic into the Add and Remove (we’re considering interceptors for these methods in a future version but haven’t received enough votes to do it.)

 

You can set the navigation property “read only” both in the model and at the entity instance levels.

 

A collection navigation property such as Member.Invoices returns a DevForce RelatedEntityList<T> (T being an Invoice in this case). The RelatedEntityList<T> has a IsReadOnly property that you can set to true. When ‘true’, the Add and Remove methods throw an exception.

 

You don’t need the Add/Remove property. When you set the child entity’s parent FK, DevForce adds (or removes) the child entity to the parent RelatedEntityList for you. Thus writing “newInvoice.Member = someMember”  automatically adds the “newInvoice” to the “someMember.Invoices” collection.

 

This puts YOU, the DEVELOPER, in the position of determining whether or not this newInvoice is allowed to be an invoice of that Member. You can add pre-set validation rules to Invoice.Member (and Invoice.MemberID) properties that prevent invalid invoices from joining the invoice of “someMember”.


If I were being thorough I personally would

 

·         Force the Member.Invoices collection to always be read only (see how below)

·         Make the setter of Invoice.Member and Invoice.MemberID “internal”

·         Add “AddInvoice” and “RemoveInvoice” methods to “Member”; these methods can set the “newInvoice.Member” if and when it has determined that “newInvoice” can be added to the member’s invoices.

 

All of this is me being extra careful about the business rules and semantics of my application model. I’m not sure ANY CUSTOMER has ever been this careful. Most don’t write any validations at all. But your question gave me the excuse to explain how I think it OUGHT to be done even if almost no one does it J

 

--

 

If you want to ensure that a collection navigation property is always read only, you can declare that intent while refining the model. Here’s a snap shot of the EF Model Browser property window where you flip the “Is collection read only” property.

 

 

When set true, DevForce set the IsReadOnly property to ‘true’ when it constructs the RelatedEntityList<T> for a navigation property of an entity instance.

 

===========

 

After the save of a child entity using the above parent.child relationship how do I tell the data binding to refresh the view because a new entity has been added to the grid?

 

You seem to be talking about what to do after saving a NEW entity rather than saving changes to an EXISTING entity that is already in the Member.Invoices.

 

The view should pick up on this if (a) the new entity is/was added to the bound collection and (b) the bound collection implements INotifyCollectionChanged (as RelatedEntityList<T> does).

 

Let’s assume that the MemberID of the new invoice has been set to the ID of the Member whose invoices are on display. As explained above, DevForce automatically adds the new entity to Member.Invoices because that collection navigation property is a RelatedEntityList<Invoice>; the DevForce EntityManager watches that list and automatically adds/removes invoices that qualify/do-not-qualify for the list. Per the assumption, the new invoice qualifies.

 

There is no such automatic mechanism for ObservableCollection<T>. You will have to add and remove items from the OC yourself unless …

 

… unless you decide to manage the OC with a DevForce EntityListManager. An EntityListManager can maintains a list in the same manner as DevForce does the RelatedEntityList<T>. This is an “advanced” DevForce option which you might find useful here.

 

On the other hand, many folks don’t like the “magic” of the EntityListManager and will choose to add/remove from the OC programmatically.

 

=======

 

Would I raise OnPropertyChanged(“”) ; should the property name be “ Member.Invoices” ?

 

Raising it for “Member.Invoices” would be telling the view that the collection OBJECT ITSELF had been replaced which is not so. What has really happened is that the collection CONTENTS have changed.

 

The view should know this automatically because the collection returned by Member.Invoices is a RelatedEntityList<Invoice> which implements INotifyCollectionChanged.



Edited by WardBell - 13-Jan-2011 at 3:20pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down