I'm developing a SOA Application, and some restrictions are imposed on it's design. The most important of them is that I'm not allowed to use the OpenAccess Disconnected API. I just can send plain DataContracts over the wire so automatic change traking is not available.
Another restriction is that every database access must be done through Stored Precedures.
I have managed to determine at the client side which objects within a collection where modified and send them to the service so the data can be updated in the database. The problem is that these objects are plain DataContracts so they are 'more than detached' from the scope :)
The only way I can figure out to update this data is to iterate through my DataContract objects collection and for each DataContract read the corresponding OpenAccess Object using a unique field (not the PK, I'm using Internal Key), updating my OpenAccess object and confirming the transaction. This means I must perform read and a write operation for each object.
However, since I'm accessing the database through stored procedures, OpenAccess defines an 'update' sp for each persistent object. May be I could call that sp directly passing the DataContract's data. The problem is that it requires the voa_version (by the way, it should be called 'toa_version' ;) ) and that information is not available at the datacontracts level.
I'm not sure if I will be allowed to include version info in my datacontracts. In case yes, is it possible to read that information so I can use it later?
Do you have any suggestion about this matter?
Thanks in advance, and best regards.
Gonzalo
7 Answers, 1 is accepted
I've managed to get the version information for a persistent class like this:
IPersistentTypeDescriptor ptd = GetScope().PersistentMetaData.GetPersistentTypeDescriptor(o.GetType());
return Convert.ToInt16(ptd.PersistentVersion.GetValue(o));
As I told before, I must access the database using SPs. So OpenAccess generates SPs for inserting, deleting and updating objectes.
I reverse mapped a SP for updating objects and I got a static method that calls my SP. So far so good. The SP generated code is as follows:
USE
[WorkHoursService]
GO
/****** Object: StoredProcedure [dbo].[usr_update] Script Date: 05/19/2010 14:29:03 ******/
SET
ANSI_NULLS ON
GO
SET
QUOTED_IDENTIFIER ON
GO
ALTER
PROCEDURE [dbo].[usr_update] ( @usr_id INT, @default_role_id INT, @description VARCHAR(255) = NULL, @e_mail VARCHAR(255) = NULL, @is_active tinyint, @nme VARCHAR(255) = NULL, @passwd VARCHAR(255) = NULL, @user_id INT, @voa_version SMALLINT , @OLD_voa_version SMALLINT ) AS UPDATE [usr] SET [default_role_id] = @default_role_id , [description] = @description , [e_mail] = @e_mail , [is_active] = @is_active , [nme] = @nme , [passwd] = @passwd , [user_id] = @user_id , [voa_version] = @voa_version WHERE [usr_id] = @usr_id AND [voa_version] = @OLD_voa_version
In this situation, for me it's clear that I must pass the original version value for the OLD_voa_version argument. The question is: What value shoud I pass to the voa_version argument?? For my first tests I'll pass the original version value in this case too, but I'm not sure this is the right approach. Any help will be very apraciated.
Best wishes,
Gonzalo
This talks about the 'version' mechanism:
OpenAccess ORM uses this method by default for optimistic concurrency control. It uses a version column to detect concurrent updates. The version number is incremented on every update and the previous version number is included in the where clause. This is the fastest and safest optimistic concurrency control mode.
I guess this answers my question. This is the path I will follow even thought I won't be using the disconnected API. Just for a matter of consistency. If this is wrong, please tell me.
Best wishes,
Gonzalo
To me it looks like the perfect approach.
We have build a SOA application just like yours (SmartClient, WebClient, ServiceClient on the client tier and WCF services on the Application Server tier).
DataContracts flows between client and server (and includes both the id and version) of the entity the datacontract object represents (if it represents an entity)..
In each and every datacontract we have included an EditState (None, Dirty, New, Delete) which the client sets when it manipulates the entity retrieved from the server... (easily done if you databind the datacontract objects retrieved from the the server and the client - we use the property notify change event in our datacontracts).
When the datacontract objects (typically one would modify a graph of objects) are sent back the EditState is also returned... And the server inspects this EditState and decides what operation should be performed on the persistent model.
This approach might seems cumbersome, but it has proved to be very useful.
Regards
Henrik
Thank you very much for your feedback.
Implementing INotifyPropertyChanged would be great and is something I've done before, as well as keeping track of the EditState. However my DataContracts are automatic generated by WSSF 2010 and unfortunately I must keep them as simple as possible, because obviously if I generate the code again from the WSSF 2010 model my DCs will be overriden. Besides, I'm not allowed to modify them anyway. Bad luck... :(
I guess I'll have to give my web client more intelligence to call the right method of the service.
Thanks a lot.
Regards,
Gonzalo
OK, so you don't need the concurrency control.
We used a common base class which holds the logic to alter the EditState and all our DataContracts inherits from this common base class. I think there's an option to do so in the proxy generator (command-line although).
Just thought I wanted to share.
/Henrik
I used to be a software architect in my previous job so I had full power to make design desitions. I adapted the 3 layered architecture they had so the base class for business objects had a property called PersistenceState. It was of type enum and the possible values where:
- New (When the object was just created)
- Unchanged (When the object was even persisted into DB or read from DB without changes)
- Modified (After reading the object from DB, if it had been changed)
- Deleted (After deleting the object from DB. Object is not valid anymore).
The objects implement INotifyPropertyChanged. The setters update the persistence state from Unchanged to Modified so the objects automatically changes their state from the point of view of their clients.
These business objects were used by a Winforms application and also by a WCF application as Datacontracts, accessed by Silverlight (after reading the great articles by David Betz on the internet about this matter). This mechanism works great.
But now I'm using Web Services Software Factory 2010 and I'm new at this company. I'll have to gain their confidence before being allowed to introduce some of these ideas.
It was a great pleasure to share thoughts with you. If you'd like to keep in touch I invite you to add me as a contact in linkedIn: http://uy.linkedin.com/in/gonzalomendezdiaz
Best Wishes,
Gonzalo