Mutiple Related Entities, tLLBLGenProDataSource & FormView (but no grid)

Posts   
 
    
smcleod_au
User
Posts: 13
Joined: 27-Jul-2005
# Posted on: 21-Dec-2006 12:35:27   

Hi,

I have an issue that I’m sure hundreds of developers come across, not all together related to LLBLGen, but I think there might be a neat way to solve it through the product.

I have a Customer table (entity) a CustomersAddresses table (entity) an Address table (entity)

and of course, a LLBLGenProDataSource and an Asp.NET v2 FormView.

In my edit template I have all my customer fields. Say, firstname, lastname, etc.

What I need to be able to do though, is have a few fields from the address table, say addressLine1, addressLine2, etc.

BUT, I know that this doesn’t actually make sense from a relational point of view, because there can be many addresses, given my CustomerAddressesTable. So I’ve added a bool (bit) column in the CustomersAddresses table called IsPrimary. (So now there are 3 columns - CustomerId, AddressId, IsPrimary)

Therefore, I only want to retrieve (when updating) that address which is the primary address, and when inserting, ensure that the new address is the primary address.

So my issue is two fold. How do I combine more than one entity in to my LLBLGenProDataSource and perform two way databinding, and how do I stipulate that relationship between the two entities?

Or am I barking up the wrong tree, and just shouldn’t be using formview, and I need to do all this manually?

Thanks in advance,

Stuart.

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 21-Dec-2006 14:47:12   

option 1.) prefetch the address entities via customerAddress and set the relation bucket predicate to filter on the address where 'primary = true(1)'. This will require some manual binding in the FormView as you will need to Eval the address entity and properties.

option 2.) create a dynamic list consisting only of fields you require from customer and address along with the filter. then bind the result to your FormView. This will give you 1 row of data to directly bind to the FormView.

In either case you will need to set LivePersistance to 'false' and manually save the entities to the database by defining the PreformSelect, PreformWork (and PreformDbCount if paging is enabled).

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 21-Dec-2006 15:34:58   

as jmeckley has said: Since you have to insert into 2 tables when you insert a new address for a customer (a record into the Address table and a record into the CustomerAddresses table). therefore you will need to do the insertion manually through setting the LivePersistence property to false, and handle the corresponding events.

Then comes the question what to use to bind to the form view, a DynamicList can be a possibility, you can also bind to the intermediate table (EntityCollection) , while using some fields mapped on related fields from the Customer table and the Address table. With the help of prefetchPaths.

A design point of View: I think the Customer - Address relation should be implemented as a 1:m relation where a customer can have more than one address, but an address should belong to only one customer, even if you have 2 different customers living in the same address (eg. 2 brothers), you should have one address record for each. This will be easier and much better when you come to handle the different use cases in your BL. Examlples: 1- When you want to delete a customer record: In my case you will automatically delete its address records. In your case you will delete the record in the intermediate table, and you may need to check if there are another records in the intermediate table that reference those addresses of the Customer, and if there is nothing references them you will need to delete them, in order not to leave many records in the Adddress table with no use.

2- the same situation can apply when a customer has an address which he want to change (he moved out), if this address is shared with another customer, you will need to create another record, and if the address is not used, then you may need to update the existing record.

It's just too much logic and cases that may rise in implementing it as an m:n relation. While it would be much simpler if you implement it as an 1:m relation.

In the later case you will have the IsPrimary flag and your databinding scenarios would be much simpler.

smcleod_au
User
Posts: 13
Joined: 27-Jul-2005
# Posted on: 22-Dec-2006 00:11:31   

Thanks for the replies.

If i'm not mistaken, isn't a dynamic list read only? I need two way databinding (the whole point of FormView I suppose) so that really cuts out a dynamic list.

So, back to my original issue. Ideally I'd love to be able to go Text='<%# Bind(Customer.AddressLine1) #>' But I don't think this is possible, is it? Would it be possible to create some kind of new Entity called CustomerWithAddress, include somekind of filter or predicate in here that limits that address to the primary address, (and EntityCollection - CustomerWithAddressCollection) that combines the two and each attribute would be accessable. I imagine I'd then have to override some select, update and insert methods?

I'm also interested to understand when the databinding actually takes place. With .Net2 the InitializeMethod is all hidden, but I think I'd like to take control of that process. For instance;

I'm opening a page with a QueryString parameter of CustomerId. That page has all kinds of things on it (in tabs) like addresses, orders, etc, etc. Each one of those is quite easy to handle because they are typically grids that I can build from TypedViews. Wouldn't it be best to be able to provide a filter to the LLBLGenProDataSource so it doesn't bring back the entire collection. Or should I use select parameters, based on the QueryString?

With respect to the database design, it's a very good point. I hadn't considered the extra work involved, BUT, it's a little more complicated than how I described. The reason I did it that way, is so I can use an address for multiple entities. For instance a customer and a supplier can have addresses.

And therefore I can just store all addresses in one table, and use that intemediary table between the address entity and the primary entity. eg CustomersAddresses and SuppliersAddresses. Rather than building a new address table for every different entity. But having a look through my schema, I had a few entities that weren't accessed from multiple primary entities, so I cleaned them up - deleted the intermediary table.

I'm thinking with the entity classes (self servicing / two class) I can add some methods like customer.DeleteAddress() and override customer.Delete() to ensure that all addresses get deleted for that customer as well.

Thanks for your help.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 22-Dec-2006 10:29:55   

smcleod_au wrote:

Thanks for the replies.

If i'm not mistaken, isn't a dynamic list read only? I need two way databinding (the whole point of FormView I suppose) so that really cuts out a dynamic list.

So, back to my original issue. Ideally I'd love to be able to go Text='<%# Bind(Customer.AddressLine1) #>' But I don't think this is possible, is it? Would it be possible to create some kind of new Entity called CustomerWithAddress, include somekind of filter or predicate in here that limits that address to the primary address, (and EntityCollection - CustomerWithAddressCollection) that combines the two and each attribute would be accessable. I imagine I'd then have to override some select, update and insert methods?

One big difference between 2-way databinding in winforms and webforms is that in webforms there's no currencymanager. So there's no object which keeps collections in an 1:n related fashion in sync (master-detail).

To have master-detail in a webform, you have to have 2 datasource controls where you have the fk field in the detail in the select parameters of its datasource and define it so it pulls the data from the pk field value control of the master.

I'm also interested to understand when the databinding actually takes place. With .Net2 the InitializeMethod is all hidden, but I think I'd like to take control of that process. For instance;

In ASP.NET 2.0, controls bound to a datasourcecontrol get bound to the control by asp.net and then call ExecuteSelect on the datasourcecontrol which will return the data already fetched (if nothing changed) or will refetch the data. This is all behind the scenes and not something you should be concerned about.

Frans Bouma | Lead developer LLBLGen Pro