Adapter vs. Self-Servicing

Posts   
 
    
Chester
Support Team
Posts: 223
Joined: 15-Jul-2005
# Posted on: 02-Aug-2005 22:26:36   

I've read the documentation and many, many posts on the use of adapter and self-servicing. But I've barely used LLBLGen, so the decision to go with one or the other isn't very intuitive to me at this point.

The question I keep asking myself is this: why even have an Adapter version of the template? If you want to support multiple databases, can't you just re-generate the code and target a different database driver?

I have a somewhat related question as well: how can I use LLBLGen as part of a solution that targets multiple databases? e.g. Order Entry is in SQL Server database, but Order Fulfillment is in Oracle database. Suppose I want to have an Order object where Order.OrderDate is in the SQL Server database, but Order.ShippedDate is in the Oracle database. How can I best use LLBLGen in this solution? Does this affect the decision to use Self-Servicing vs. Adapter?

My idea so far for the 2nd question is this:

1) Create Business Facade layer that gets called from GUI.


MyOrderEntity order = MyOrderEntity.RetrieveOrder(12345);

2) Business Facade assembles object by calling each database separately


public static MyOrderEntity RetrieveOrder(int pk)
{
   SQL.OrderEntity sqlOrder = new SQL.OrderEntity(12345);
   Oracle.OrderEntity oracleOrder = new Oracle.OrderEntity(12345);
   MyOrderEntity returnOrder = new MyOrderEntity();
   returnOrder.ID = pk;
   returnOrder.OrderDate = sqlOrder.OrderDate;
   returnOrder.ShippedDate = oracleOrder.ShippedDate;
   return returnOrder;
}

Forget the fact that the primary keys won't match for now. You get the idea. It seems a bit messy to do it this way, but I don't know a better way to do it. And this is just selecting data. Updates get really messy. Anyone dealt with this issue before?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 03-Aug-2005 10:48:26   

Uh, wrote:

I've read the documentation and many, many posts on the use of adapter and self-servicing. But I've barely used LLBLGen, so the decision to go with one or the other isn't very intuitive to me at this point.

The question I keep asking myself is this: why even have an Adapter version of the template? If you want to support multiple databases, can't you just re-generate the code and target a different database driver?

Not if you want to target multiple databases in one application, for example read an entity from oracle, and save that same instance into sqlserver.

Furthermore, Adapter has separation between persistence logic and entity objects. This means that the entity code is database generic and the code using these objects are not aware of any persistence logic. This is ideal in systems where a BL tier has to be used for data retrieval/processing, so GUI code has to call that BL tier, it can't lazy load or save data itself.

I have a somewhat related question as well: how can I use LLBLGen as part of a solution that targets multiple databases? e.g. Order Entry is in SQL Server database, but Order Fulfillment is in Oracle database. Suppose I want to have an Order object where Order.OrderDate is in the SQL Server database, but Order.ShippedDate is in the Oracle database. How can I best use LLBLGen in this solution? Does this affect the decision to use Self-Servicing vs. Adapter?

Yes, that's exactly a situation where adapter is ideal and selfservicing isn't. Adapter provides you a way to supply multiple 'adapters' to your code so you can pick one to persist your entity with. Depending on the adapter chosen, the entity ends up in sqlserver or oracle or other db.

My idea so far for the 2nd question is this:

1) Create Business Facade layer that gets called from GUI.


MyOrderEntity order = MyOrderEntity.RetrieveOrder(12345);

2) Business Facade assembles object by calling each database separately


public static MyOrderEntity RetrieveOrder(int pk)
{

   SQL.OrderEntity sqlOrder = new SQL.OrderEntity(12345);
   Oracle.OrderEntity oracleOrder = new Oracle.OrderEntity(12345);
   MyOrderEntity returnOrder = new MyOrderEntity();
   returnOrder.ID = pk;
   returnOrder.OrderDate = sqlOrder.OrderDate;
   returnOrder.ShippedDate = oracleOrder.ShippedDate;
   return returnOrder;
}

Forget the fact that the primary keys won't match for now. You get the idea. It seems a bit messy to do it this way, but I don't know a better way to do it. And this is just selecting data. Updates get really messy. Anyone dealt with this issue before?

With adapter, you create a DataAccessAdapter factory, which produces simply the right DataAccessAdapter instance based on a key passed in, for example an enum. Your code is then written with IDataAccessAdapter.

So you have an OrderEntity, and you simply do: IDataAccessAdapter adapter = MyAdapterFactory.Create(Databases.Oracle); adapter.SaveEntity(myOrderEntity);

recursive saves etc. are per database, so you can create a graph in your upper tiers (or remote client/tier) and in the BL tier, break it up and save each part in the database of choice. If you want to save data using multiple adapters, it's recommended that you use a COM+ transaction (see the documentation of adapter for details on that), to which you can assign an adapter and make the calls to that adapter instance use the current COM+ transaction, which makes saves into multiple databases atomic. (if they support COM+ transactions of course, sqlserver/oracle/db2 do)

Frans Bouma | Lead developer LLBLGen Pro
Chester
Support Team
Posts: 223
Joined: 15-Jul-2005
# Posted on: 03-Aug-2005 17:59:33   

Otis wrote:

Not if you want to target multiple databases in one application, for example read an entity from oracle, and save that same instance into sqlserver.

Furthermore, Adapter has separation between persistence logic and entity objects. This means that the entity code is database generic and the code using these objects are not aware of any persistence logic. This is ideal in systems where a BL tier has to be used for data retrieval/processing, so GUI code has to call that BL tier, it can't lazy load or save data itself.

So the Self-Servicing approach, though a little easier to use, has coupled the business logic and data logic together, and the Adapter model separates them. Am I right here?

Otis wrote:

recursive saves etc. are per database, so you can create a graph in your upper tiers (or remote client/tier) and in the BL tier, break it up and save each part in the database of choice.

Well, I'm embarrased to ask flushed , but can you explain what you mean by a graph? Is this a composite business object that aggregates all the attributes of the entity?

I guess what I want is a business object that represents the true Enterprise business entity to the GUI developer, and under the hood that business object is able to persist to multiple databases if necessary.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 04-Aug-2005 10:06:59   

Uh, wrote:

Otis wrote:

Not if you want to target multiple databases in one application, for example read an entity from oracle, and save that same instance into sqlserver.

Furthermore, Adapter has separation between persistence logic and entity objects. This means that the entity code is database generic and the code using these objects are not aware of any persistence logic. This is ideal in systems where a BL tier has to be used for data retrieval/processing, so GUI code has to call that BL tier, it can't lazy load or save data itself.

So the Self-Servicing approach, though a little easier to use, has coupled the business logic and data logic together, and the Adapter model separates them. Am I right here?

Correct: selfservicing has the persistence logic as 'behavior' enclosed inside the object it targets (e.g. entity.Save()). Adapter has teh persistence logic exposed as a 'service', e.g. you apply it to a set of objects, the objects itself don't know anything about persistence.

Otis wrote:

recursive saves etc. are per database, so you can create a graph in your upper tiers (or remote client/tier) and in the BL tier, break it up and save each part in the database of choice.

Well, I'm embarrased to ask flushed , but can you explain what you mean by a graph? Is this a composite business object that aggregates all the attributes of the entity?

No, I mean with 'graph' a reference graph in memory simple_smile So a customer entity object references a couple of Order entity objects, which in turn reference some order detail entity objects and an employee entity object.

I guess what I want is a business object that represents the true Enterprise business entity to the GUI developer, and under the hood that business object is able to persist to multiple databases if necessary.

Ah I see what you mean. If different databases weren't an issue, this would have been a selfservicing entity's job, but adapter works a little different there. There you present a tier to the GUI developer, which provides a service to the GUI layer. The GUI tier works with entity objects and for functionality related to these entities it asks the BL tier to perform these for them. This is a more scalable approach as you can move the BL tier to a remoted server if you'd like, as the GUI tier won't call the dal directly.

Frans Bouma | Lead developer LLBLGen Pro