Where can the adapter go

Posts   
 
    
simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 28-May-2006 17:30:33   

I have this code and it works great....

        // Retrieve a collection of Ships along with their Voyages and PortCalls
        // where the voyage had a start date within the last 7 days
        IDataAccessAdapter adapter = new DataAccessAdapter();
        EntityCollection ships = new EntityCollection(new ShipEntityFactory());
        RelationPredicateBucket bucket = new RelationPredicateBucket();
        bucket.Relations.Add(ShipEntity.Relations.VoyageEntityUsingShipSeq);
        bucket.PredicateExpression.Add(VoyageFields.StartDtm >= DateTime.Now.Subtract(TimeSpan.FromDays(7)));
        PrefetchPath2 prefetchPath = new PrefetchPath2((int) EntityType.ShipEntity);
        prefetchPath.Add(ShipEntity.PrefetchPathVoyages).SubPath.Add(VoyageEntity.PrefetchPathPortCalls);
        adapter.FetchEntityCollection(ships, bucket, prefetchPath);

What I would like to do is be able to do is have the DataAccessAdapter run on a different machine via remoting by changing one line. IDataAccessAdapter adapter = (IDataAccessAdapter) Activator.GetObject(typeof(IDataAccessAdapter), "http://localhost:1234/IDataAccessAdapter.rem");

I have written a simple remoting app with a client and server side. The server side has a RemoteAdapter class which implements IDataAccessAdapter and wraps a real DataAccessAdapter object.

The server side works as expected and retrieves the info from the server. However the client side is going to a copy of the data back from the server and so appears empty.

What do I need to implement to get this scenario working (without writing a Service Facade for every required operation)? Is it actually possible?

Cheers Simon

sparmar2000 avatar
Posts: 341
Joined: 30-Nov-2003
# Posted on: 28-May-2006 19:04:44   

Hi Simon

Rather then hardcoding the URL in your code, perhaps you might want to consider use of app.config file. There are quite a few example on the web...google revealed too many for me to list them here.

simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 29-May-2006 06:19:31   

sparmar2000 wrote:

Hi Simon

Rather then hardcoding the URL in your code, perhaps you might want to consider use of app.config file. There are quite a few example on the web...google revealed too many for me to list them here.

This is just test code.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 29-May-2006 09:27:11   

The adapter isn't remotable because it contains a connection. Now, it could be remotable through a proxy and that would lead to a 'chatty' application (for every db operation, a lot of networktraffic is needed). So it was decided not to make the dataaccessadapter remotable. You've to write a service which accepts messages which are then executed by the service. That's more efficient and scalable, maintainable.

Frans Bouma | Lead developer LLBLGen Pro
simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 31-May-2006 08:15:22   

Otis wrote:

The adapter isn't remotable because it contains a connection. Now, it could be remotable through a proxy and that would lead to a 'chatty' application (for every db operation, a lot of networktraffic is needed). So it was decided not to make the dataaccessadapter remotable. You've to write a service which accepts messages which are then executed by the service. That's more efficient and scalable, maintainable.

I don't thing chattiness is a real issue. I make a request and pass certain parameters, sure these will be serialized but this would be the same as sending a message to a service interface.

If remoting is to be used at all, whether in my scenario or a service as you mention, there is still going to be the same two-way serialization/deserialization involved. As mentioned in other threads in this forum this is the slow part anyway.

Another 'issue' with the service method is that it will return a new physical entity. I would like to be able to update an existing entity in-situ. This means no further work would need to be done to ensure that any collections/bindings that the original entity was involved with need to be modified. Just replace the entity's data and raise an event or events to say it has changed and thats it. One of the big advantages of LLBLGen over CSLA for me was that the entity class data could be treated as a unit and that you can Fetch intoan entity rather than Fetch an entity. On the other hand, what CSLA does have is this ability to change from a local to a remoting application with a simple configuration file change - I am just looking to implement this feature.

I've managed to write a simple proof of concept for just fetching a single entity and a collection of entities. Because the serialization is by value resulting in a new copy, I needed to do two things slightly differently. Firstly, make sure that the entity fetched on the server side is actually returned (the standard IDataAccessAdapter signature won't work as-is because only the result value will be returned. So either we use a ref parameter for the entity/collection to force it to be returned or change the signature to return the entity/collection itself (and therefore use null to return true or false as the real result). Secondly, take the content of the returned entity/collection and put it into the local object. Snippet here works fine:

    public bool FetchEntity(IEntity2 entityToFetch)
    {
        IEntity2 originalEntityToFetch = entityToFetch;
        bool result = RemoteAdapter.FetchEntity(ref entityToFetch);
        originalEntityToFetch.Fields = entityToFetch.Fields;
        originalEntityToFetch.IsNew &= !result;
        return result;
    }

I feel that this is achievable (assuming that all of the relevant classes are serializable of course - but that does seem to be the case) for the rest of the IDataAccessAdapter interface. However if you have already looked at this previosuly and found a showstopper then let me know!

Cheers Simon

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 31-May-2006 11:13:35   

Though you can do that too with a service which returns an entity, or do I miss something?

Frans Bouma | Lead developer LLBLGen Pro
simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 31-May-2006 11:22:03   

Otis wrote:

Though you can do that too with a service which returns an entity, or do I miss something?

Which bit are you referring to?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 31-May-2006 11:31:58   

simmotech wrote:

Otis wrote:

Though you can do that too with a service which returns an entity, or do I miss something?

Which bit are you referring to?

Oh sorry, the code you posted.


public bool FetchEntity(IEntity2 entityToFetch)
{
    IEntity2 originalEntityToFetch = entityToFetch;
    IEntity2 fetchedEntity = myService.FetchEntity(originalEntityToFetch.PkField);
    bool result = (fetchedEntity.IsNew==false);
    originalEntityToFetch.Fields = fetchedEntity.Fields;
    originalEntityToFetch.IsNew &= !result;
    return result;
}

Frans Bouma | Lead developer LLBLGen Pro
simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 03-Jun-2006 11:33:14   

Actually, regardless of whether a service is written (your suggestion) or whether a remote-aware DataAccessAdapter is written (my suggestion) or a combination of both, there is still the issue of serialization performance when remoting is involved in any way.

This is not an LLBLGen issue of course and I see that your implementation of ISerializable reduces the data down to the bare minimum required to work for all serialization cases.

However, in a remoting case, it will generally boil down to moving an EntityCollection from one machine to another (a single entity could be seen as a collection of one object to keep things simple) with the minimum amount of data for this specific case. That means that some of the data currently serialized will (may?) be redundant - saved fields, predicate factory and that kind of thing. (Actually, since these are likely to be null they make take up very little space anyway)

Let me give you some test figures: These are using a standard DataAccessAdapter to a SQL Server database (which is on a poorly-specced development server confused ) and then use a binary formatter to serialize to a memory stream to check the size and serialization time:

I run a query that returns 536 ship entities: It takes 1.078 seconds and serializes to 610,061 bytes in 0.28 seconds.

I then run a query with a prefetch path and a sub prefetch path returning 536 ships, 13,376 Voyages and 17,924 Port Calls: It can get all of these in just 12 seconds which is amazingly fast!! smile

However it takes over 13.5 minutes to serialize them to a staggering 37MB!!! frowning not to mention the CPU time involved. This is just serialization one-way of course, that 37MB would then have to be transmitted over the network and then deserialized and then require possibly more time to overlay onto existing entities (if there are any)

This test query may be atypical of general use of course but getting 31,846 entities from a database to the client computer can be done in 12 seconds but involving a remote layer will take 27+ minutes.

I see that other posts have been querying the same issue and showing that .NET serialization does an awful lot of work (retrieving that same object data dozens of times etc) that is redundant for the above scenario.

It seems to be me that there may be scope to transparently (without altering the IDataAccessAdapter interface but maybe adding an IRemoteDataAccessAdapter?) split out the database retrieval and entity population elements:- the database retrieval to be done either on the client or via a remote machine, and using an efficient point-to-point method to relay that data optimally, with the entity population always being done on the destination (client) machine. If all is done locally then the effect would be negligible or a NOP but for remoting we may see just the data itself doing one additional network hop - total of 24 seconds plus a little overhead?? which would blow away any other way of doing remote entites (ie wrapping ADO 2.0 datasets/tables in binary mode)

Cheers Simon

PS I know you are very busy with v2.0 now but maybe 2.1? Or I might have a look at this if you could give me any guidance.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 05-Jun-2006 11:03:31   

Thanks for the time to test it! simple_smile Though, wouldn't it be the same when the dataaccessadapter is remotable? I mean, the data in the collection is still transfered from server to client, so has to be serialized, as the fetching is done on the server, which means you run into the same serialization issue.

Frans Bouma | Lead developer LLBLGen Pro