Entities In Distributed Scenario

Posts   
 
    
Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 16-Dec-2005 19:09:52   

i was wondering how you guys handle this situation....

in my case im sending entities over webservices, i have a Order Entity with Order Details entities and these order details entities have a reference to a product. Now in my web service i have a function called SaveOrder, in which i want to pass a order object along with all its order detail objects to my business layer. Now i would like to be able to take advantage of the recursive saving functionality as it makes life easy, however how do you prevent someone from say passing a product along with it? As if you you used recursive saving it would also save that product correct?

Is my only choice to manually loop through each entity and save it manually...?

bclubb
User
Posts: 934
Joined: 12-Feb-2004
# Posted on: 17-Dec-2005 03:10:25   

I don't believe that you will be able to lock the object to the point that you can't add new products to the order, unless you wrote it into your logic to fail an orderitem save if it's product entity IsNew.

jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 31-Dec-2005 10:40:37   

Answer wrote:

i was wondering how you guys handle this situation....

in my case im sending entities over webservices, i have a Order Entity with Order Details entities and these order details entities have a reference to a product. Now in my web service i have a function called SaveOrder, in which i want to pass a order object along with all its order detail objects to my business layer. Now i would like to be able to take advantage of the recursive saving functionality as it makes life easy, however how do you prevent someone from say passing a product along with it? As if you you used recursive saving it would also save that product correct?

Is my only choice to manually loop through each entity and save it manually...?

Yes, this is another argument against using the generated entities or the Unit of Work class as parameters for a business layer: the requirements aren't explicit. As the entities themselves can have object references and also can be saved recursively, they function as a de facto Unit of Work. And, just like a Unit of Work, they aren't "strongly typed" as in there aren't explicit instructions on how to use it, or what entities may or may not be added, etc.

If you're the sole user, go ahead and use them; it's not a big deal. However, if your service will serve multiple and/or unknown clients, I'd highly recommend either staying away from them or making an explicit rule in your BL development not to use recursive saves or create derived Units of Work that have members that are strongly typed for how you wish the caller to use them or roll your own.

Jeff...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 31-Dec-2005 10:54:32   

jeffreygg wrote:

Answer wrote:

i was wondering how you guys handle this situation....

in my case im sending entities over webservices, i have a Order Entity with Order Details entities and these order details entities have a reference to a product. Now in my web service i have a function called SaveOrder, in which i want to pass a order object along with all its order detail objects to my business layer. Now i would like to be able to take advantage of the recursive saving functionality as it makes life easy, however how do you prevent someone from say passing a product along with it? As if you you used recursive saving it would also save that product correct?

Is my only choice to manually loop through each entity and save it manually...?

Yes, this is another argument against using the generated entities or the Unit of Work class as parameters for a business layer: the requirements aren't explicit. As the entities themselves can have object references and also can be saved recursively, they function as a de facto Unit of Work. And, just like a Unit of Work, they aren't "strongly typed" as in there aren't explicit instructions on how to use it, or what entities may or may not be added, etc.

They don't act as a de facto unitofwork, because they don't contain any action definition. They're just data. THe unitofwork contains actions, which is a fundamental difference.

With the unitofwork, what it will do is inside the unitofwork as added actions. Nothing more, nothing less. Sure, if you add your entities for save and do that recursively, you will of course then by that action tell the unitofwork to traverse the whole graph of the entity and save every entity in that graph. But that's what you said it should do so I don't see that as a downside.

I also fail to see your argument against 'strongly typed'. They're containers for work to be done. They offer you a way to store actions along the way, so you can execute those actions later on, even pass those actions over a wire, that doesn't matter.

ANything related to webservices should be done with messages. Don't send graphs nor pass graphs back to clients. Send messages back and forth. That's where the strong points of webservices lay.

If you're the sole user, go ahead and use them; it's not a big deal. However, if your service will serve multiple and/or unknown clients, I'd highly recommend either staying away from them or making an explicit rule in your BL development not to use recursive saves or create derived Units of Work that have members that are strongly typed for how you wish the caller to use them or roll your own. Jeff...

You mix architectures. If you offer a service to unknown clients, which implies that the software contacting your service is also unknown (and can be anything: browser, javaclient, vb program... ) you should solely rely on messaging. Send and receive messages. Of course the unitofwork object isn't suitable, because the client isn't known.

If the service is a webservice, messages are teh only way to go anyway.

If the software IS known, but the person operating it isn't, the unitofwork still is suitable. You just have to setup proper security measures but it comes down to: if you offer a service to known client software, is that service part of the client software or an independent entity. If it's the first, the client ordered some work to be done so the service obeys. If it's the latter, the service has to check every input and because it's autonomous, other clients probably can connect to so it should work with messages only.

Frans Bouma | Lead developer LLBLGen Pro
jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 31-Dec-2005 22:13:58   

Otis wrote:

jeffreygg wrote:

Answer wrote:

i was wondering how you guys handle this situation....

in my case im sending entities over webservices, i have a Order Entity with Order Details entities and these order details entities have a reference to a product. Now in my web service i have a function called SaveOrder, in which i want to pass a order object along with all its order detail objects to my business layer. Now i would like to be able to take advantage of the recursive saving functionality as it makes life easy, however how do you prevent someone from say passing a product along with it? As if you you used recursive saving it would also save that product correct?

Is my only choice to manually loop through each entity and save it manually...?

Yes, this is another argument against using the generated entities or the Unit of Work class as parameters for a business layer: the requirements aren't explicit. As the entities themselves can have object references and also can be saved recursively, they function as a de facto Unit of Work. And, just like a Unit of Work, they aren't "strongly typed" as in there aren't explicit instructions on how to use it, or what entities may or may not be added, etc.

They don't act as a de facto unitofwork, because they don't contain any action definition. They're just data. THe unitofwork contains actions, which is a fundamental difference.

Well, I wasn't aware that there is an explicit definition of UnitOfWork, and if there is, I guess I can't argue with that. simple_smile However, as I am defining it a UnitOfWork is a set of data to be acted upon: the aggregation or results of a process that then needs to be acted upon or commited. An entity with related entities as object references and the associated recursive save ability mimics the UnitOfWork's AddForSave functionality. True that AddForDelete isn't there, nor are the stored proc callbacks there, but I think it's fair to say that it's still a clear subset of the UnitOfWork's functionality.

With the unitofwork, what it will do is inside the unitofwork as added actions. Nothing more, nothing less. Sure, if you add your entities for save and do that recursively, you will of course then by that action tell the unitofwork to traverse the whole graph of the entity and save every entity in that graph. But that's what you said it should do so I don't see that as a downside.

I also fail to see your argument against 'strongly typed'. They're containers for work to be done. They offer you a way to store actions along the way, so you can execute those actions later on, even pass those actions over a wire, that doesn't matter.

I think what I'm trying to communicate is that there is no way to explicit define to the caller how to use that UnitOfWork. If I create a BL signature that asks for it, as Answer has described, how does Answer communicate to the caller that Products are not to be added to the UnitOfWork? As containers for work they succeed brilliantly; as arguments to a BL method I think they're misapplied. Just need to use them above or below the BL surface as necessary and not to get between the two.

ANything related to webservices should be done with messages. Don't send graphs nor pass graphs back to clients. Send messages back and forth. That's where the strong points of webservices lay.

I think that that's exactly what I'm trying to convey: UnitsOfWork are poor substitutes for messages. However, even if the user decide to opt for a more RPC form of signature, UnitsOfWork are still not good option; in either case they're "loosely typed" (boy am I destroying that term or what? simple_smile ) - and the caller doesn't really know what to put inside that UoW. They're simply misapplied as a BL signature class.

However, it's the danger of using entities at all as arguments to a BL method. They can be passed in as a graph and as a service developer I may not have control over the callers using the entities as such. Again, one option is to make it an explicit rule not to do recursive saving of entities passed in as arguments to the BL, but a) there's no real way of enforcing that on a team, and b) the user may assume that the service does do recursive saves and we're back to the argument that there's no clear communication to the caller on how exactly to pass either the entities or the UnitsOfWork.

If you're the sole user, go ahead and use them; it's not a big deal. However, if your service will serve multiple and/or unknown clients, I'd highly recommend either staying away from them or making an explicit rule in your BL development not to use recursive saves or create derived Units of Work that have members that are strongly typed for how you wish the caller to use them or roll your own. Jeff...

You mix architectures. If you offer a service to unknown clients, which implies that the software contacting your service is also unknown (and can be anything: browser, javaclient, vb program... ) you should solely rely on messaging. Send and receive messages. Of course the unitofwork object isn't suitable, because the client isn't known.

If the service is a webservice, messages are teh only way to go anyway.

If the software IS known, but the person operating it isn't, the unitofwork still is suitable. You just have to setup proper security measures...

Maybe I'm missing something here, but that's a runtime thing, right? I'm not exactly sure what you mean by "setup proper security measures", but if I pass in a UnitOfWork, I'm not going to know until runtime whether I've passed it in properly, and then only if we've done proper code coverage testing.

... but it comes down to: if you offer a service to known client software, is that service part of the client software or an independent entity. If it's the first, the client ordered some work to be done so the service obeys. If it's the latter, the service has to check every input and because it's autonomous, other clients probably can connect to so it should work with messages only.

Not sure I follow you here, but it seems to me that even if I introduce one other developer into the equation who will/may consume my service - whether or not the service is integrated into the client app, or it's independent and autonomous, I should be moving towards making the requirements of the method's signature as clear as possible - whether I use messages or RPC-style methods. If my message or my method asks for either an entity or a unit of work, there is a danger that a) it will be treated as an object graph and b) the user will not know what is allowable to include (more of a UoW problem).

For some situations I simply think that the use of entities and units of work is misapplied - in this case when they are used as parameters to a BL method, or as properties/attributes to a service message. They were originally created for use below the BL surface and they seem to be most at home there.

Now, I'm willing to grant that this is all very idealistic. simple_smile We ourselves use the entities and units of work as arguments to our service methods (we aren't using messages) as we simply don't have the time and we need to use the resources available to us. But it is through this process that I've come to the conviction that they are not well suited for the task.

Jeff... simple_smile

JimFoye avatar
JimFoye
User
Posts: 656
Joined: 22-Jun-2004
# Posted on: 01-Jan-2006 18:16:57   

I'm trying to follow this, as I'm doing a distributed application right now. But I'm having some trouble.

Frans, can you elaborate on what you mean by

Anything related to webservices should be done with messages. Don't send graphs nor pass graphs back to clients. Send messages back and forth. That's where the strong points of webservices lay.

Are you saying that a client shouldn't just send entities over the wire for a server to save? And Jeff, are you saying something similar? (Or altogether different?) And how would you use LLBLGenPro entities and NOT pass them up to a BL layer? Wouldn't that mean a lot of extra work in the BLL creating classes the same as, or at least very similar to, the LLBLGenPro entities?

In my situation I have no "unknown" clients.

Thanks!

[Edit] Sorry, I meant to say also I'm using .NET remoting, not web services, so Frans I also wanted to know if you're comment applied to .NET remoting as well.

jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 01-Jan-2006 18:45:24   

JimFoye wrote:

I'm trying to follow this, as I'm doing a distributed application right now. But I'm having some trouble.

Frans, can you elaborate on what you mean by

Anything related to webservices should be done with messages. Don't send graphs nor pass graphs back to clients. Send messages back and forth. That's where the strong points of webservices lay.

Are you saying that a client shouldn't just send entities over the wire for a server to save? And Jeff, are you saying something similar? (Or altogether different?) And how would you use LLBLGenPro entities and NOT pass them up to a BL layer? Wouldn't that mean a lot of extra work in the BLL creating classes the same as, or at least very similar to, the LLBLGenPro entities?

In my situation I have no "unknown" clients.

Thanks!

[Edit] Sorry, I meant to say also I'm using .NET remoting, not web services, so Frans I also wanted to know if you're comment applied to .NET remoting as well.

I do think Frans and I are saying similar things, except that I think Frans is trying to allow for the use of entities and units of work in situations where the the BL isn't distributed and/or when the client or client developer is known and trusted.

My point is that if there is more than one person on the team one should be very careful about defining the requirements of each method on the business layer. Entities and UnitsOfWork I don't think make great candidates as parameters to an RPC-style method, or as attributes/properties to a service message because their use is undefined.

As for your comment as to the extra work involved: Something I've toyed with is to create a data-only interface for the entities such as ICustomer that could be automatically generated and injected by Frans' excellent code generation framework. Each entity would implement the data-only interface and that would be whats passed to the BL in place of the implementation itself; you're really only looking for the data. Frans did mention there could be some downsides to this, though, and I've honestly not thought it all the way through. simple_smile

Jeff...

sparmar2000 avatar
Posts: 341
Joined: 30-Nov-2003
# Posted on: 02-Jan-2006 02:19:15   

I have been following this thread with great interest, hence this note, but apologies in advance if it causes any confusion.

My understanding is that if the client and the server is .Net then use Remoting using binary sink for efficiency and performance. Therefore in this senerio, the Entity,UOW and graphs will be known to both the client and server.

However, if the server is .Net and the client is a non .Net client, then Entity, UOV, graph will be unknown to the client. The only methods of passing data between the two would be in form of messages. On receiving these messages, the receiver would need to implemnt some logic to implement UOW/graph kind of processing whenever this is required.

Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 05-Jan-2006 01:32:02   

While, i have to say im leaning toward not using llblgen for this project as i think i understand what frans is saying about passing messages. Actually i should say that im not going to use self servcing/adapter, im still using llblgen, just the generator part, which rocks btw..simple_smile

But here is some info for you all on using lblgen over webservices. I know this is sorta off topic but the topic is what spawned it simple_smile

i did some makeshift testing on passing entities over webservices and i found that llblgen entities serialize about 5 times slower then my generated entities. In addition, cpu spiked much more with llblgen entities. I believe its due to the fact that the xml serialization routines in the base classes use reflection which we all know is a performance killer.

3rd, the xml output was much much bigger. 350kb for my entities, and 3.34mb for llblgen entities. Now oddly enough, if i zip compressed the output, they were 59k and 63k respectively. i wasnt expecting that!

Now with that said i believe the llblgen entities actually had a slight advantage as my entities were carring more data. My generated entities are just POCO btw simple_smile

To overcome these problems, you could create/modifiy templates to change the xml output, then create a plugin to get rid of all fields mapped to relations for each entity (so the entities are more message based and theres no graphs) and/or lastly use WSE 3.0 and modify the soap envelope by compressing the payload. I kinda got the vibe that llblgen wasnt designed from teh ground up to be used over webservices, so instead of trying to make it work, i just wrote some of my own templates to create a simple datalayer as its all i needed. However, i hadnt thought about making a plugin and getting rid of all fields mapped to other entities to make them more message based until just now, otherwise i probably would have attempted to make llblgen work. DUH!!! frowning