Transferring entites and collections between tiers

Posts   
 
    
Posts: 19
Joined: 08-Jan-2007
# Posted on: 09-Jan-2007 16:21:13   

Hi

I'm currently evaluating LLBLGen, but I have a question about how best to transfer entities/collections between tiers.

Currently all our apps use typed datasets as "data transfer objects", to pass data through the tiers. It has the advantage that the business tier can populate a number of tables in this dataset and send it all up to the UI in one go. For example, if I had a customer/order data entry page, the business tier might populate the dataset with the customer row, all their order rows, plus any lookup/reference data needed by the UI (e.g. country names, Mr/Mrs/titles, order status codes, and so on - for use in dropdown lists).

If I was to move over to LLBLGen, how could I accomplish a similar "data transfer" of many entities/collections at once? I would be using the "adapter" model.

Obviously the customer/orders is straightforward, and would be populated using code similar to this:

DataAccessAdapter adapter = new DataAccessAdapter(true); OrderEntity order = new OrderEntity(10254); adapter.FetchEntity(order); order.Customer = (CustomerEntity)adapter.FetchNewEntity(new CustomerEntityFactory(), order.GetRelationInfoCustomer()); adapter.CloseConnection();

The customer can then be transferred up through the tiers, taking the related orders with it. But what can I do about all the other lookup/reference data tables that I might want to send with it? Can anyone suggest a way to transfer all this in one go, or will it be an architecture change (e.g. repeated calls to the business tier to retrieve the lookup data)?

Thanks in advance

Andy

jbb avatar
jbb
User
Posts: 267
Joined: 29-Nov-2005
# Posted on: 09-Jan-2007 16:31:10   

Hello,

you can make only one call to the adapter and use prefetchpath to retrieve the related entities. In your example:

DataAccessAdapter adapter = new DataAccessAdapter(true); OrderEntity order = new OrderEntity(10254); prefetchPath2 myPrefetchPath=new prefetchpath(EntityType.OrderEntity) myPrefetchPath.add(OrderEntity.prefetchpathCustomer) adapter.FetchEntity(order,myPrefetchPath); adapter.CloseConnection()

With the prefetchpath, you can also retrieve all the related object or your customer.

Posts: 19
Joined: 08-Jan-2007
# Posted on: 09-Jan-2007 17:01:03   

Hi jbb

Thanks for the reply but I'm not sure if I explained the problem very well. The issue is not so much with how to retrieve all this information using LLBLGen, but more of a "best practice" for passing it up through the tiers.

As a clearer example, I have a "country" lookup table containing a list of all country names, and a "customer" table that has a CountryId column (FK back to the country table). I want the business tier to return to the UI a given customer plus all country names (if that's possible). The customer entry UI needs the full list of countries to populate a dropdown.

Using code similar to your example, wouldn't that just give me a CustomerEntity, with its "Country" property populated with just its related (parent) CountryEntity?

I need the business tier to return a given customer and all countries in one go if possible. The only options I see at the moment are:

1) make separate business tier calls, i.e. one to get the CustomerEntity and another to get the lookup data (Country entity collection).

2) Have the business component retrieve the CustomerEntity and Country entity collection, then project both of these onto a dataset so they can be passed back to the UI in one go.

Thanks again Andy

jbb avatar
jbb
User
Posts: 267
Joined: 29-Nov-2005
# Posted on: 09-Jan-2007 17:15:39   

Hello,

If you want to add all related contry for your customer, you can just add a subpath on your prefetchpath : OrderEntity order = new OrderEntity(10254); prefetchPath2 myPrefetchPath=new prefetchpath(EntityType.OrderEntity) myPrefetchPath.add(OrderEntity.prefetchpathCustomer).subpath.add(CustomerEntity.prefetchPathCountry) adapter.FetchEntity(order,myPrefetchPath);

This request will send you for a given order, all the customer and all the linked country. But if you want to get all the country (not relying on customer) and customers, you need to make another business tier call.

If you want all the information in only one datatable it will be difficult because the column won't be the same depending on the entitytype. If you want directly all related entities in a datatable, you can use fetchtypelist with relations. But if data are not related, I think it's better to make separate business tier calls.

Hope it's answer more to your question.

rmm
User
Posts: 59
Joined: 07-Dec-2006
# Posted on: 10-Jan-2007 11:44:01   

I was wondering about the same issue - when and how to load lookup-data? To create and persist a SalesOrder I need at least 3 controls (Combobox) filled with data - Customers, Contacts and Items. And this means ALL records from these table, not just related records. Suppose there are 10 000+ customers, 15 000+ items in the database. I'm using Remoting over http, WinForms and BackroundWorker when fetching/saving data. What would be "best practise" to handle this situation? We've considered following options:

  1. Create small typed lists for lookup data - include only CustomerId and CustomerName. Load the data when Combobox first becomes active and load CustomerEntity after a Customer has been selected, because we need additional info (Address, VAT rate etc) from Customer into SalesOrder. This means many trips to BL (database) - if I need to insert 10+ rows into SalesOrder I have to fetch ItemEntity for each row after making selection in Combobox.

  2. Load entire entitycollections of lookup-data when creating new SalesOrder. This means 3 initial fetches, lot's of records in clients memory, but no more database calls before saving SalesOrder.

I prefer the first option, but would love to hear other opinions. Maybe there's more options. I'm sure someone has done something similar, would you describe your solution? Thanks

Posts: 19
Joined: 08-Jan-2007
# Posted on: 11-Jan-2007 15:02:36   

Having thought about this a bit more, a simple solution is to create a "data transfer object" (DTO) - a very basic class consisting of nothing more than a series of properties - one per entity and entitycollection.

Using my previous example, my UI would call a business tier method "GetCustomerAndLookupData()". This would retrieve the required customer and store it in the DTO's Customer property (related orders are obviously persisted in the customer's own "Orders" property). The same business tier method would then retrieve the necessary lookup/reference data (e.g. country names, customer titles, etc) and store them in the corresponding entitycollection properties of the DTO, which is then returned to the UI. In other words, I have retrieved everything needed by the UI in a single call to the business tier.

Think of the DTO class like a DataSet, but it contains entities and entitycollections instead of DataTables.

Any comments or other suggestions?

Thanks Andy

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 11-Jan-2007 15:49:35   

We all agree that an Entity or an Entity collection can be passed through tiers with all its related entities and collections.

The problem comes when you want to transfer other un-related data, such as LookUp tables.

IMHO, making several calls to the BL is the best solution, there can not be any considerable gain with calling the BL only once. Calls to the database are the ones that matter most of the time.

Another approach is to load all the lookup tables only once when the application starts in cashed objects (e.g. HashTables) stored in the UI/Presentation Layer memory, so you won't need to fetch them again from the BL. The same approach is used in the development of this Forum, check the HnD source code.

Posts: 19
Joined: 08-Jan-2007
# Posted on: 11-Jan-2007 16:04:27   

Walaa, thanks for the input.

Normally I would agree that there are no real performance gains to be made by calling the BLL just once, however all the web apps that we develop here are distributed. The BLL sits on our corporate intranet, while the UI (web app) sits on the internet DMZ, and calls the BLL via a webservice (and through a firewall) when making BLL calls. This is generally the bottleneck for us, rather than DB calls.

So I think in our situation a single call to the BLL would be a benefit. Caching the lookup data on app startup may also be a useful technique as you suggest.

Thanks again

Andy