Ideas for handling "privileged" property updates?

Ideas for handling "privileged" property updates?

Old forum URL: forums.lhotka.net/forums/t/3855.aspx


rsbaker0 posted on Wednesday, November 07, 2007

In our application, we have database fields that can't be set directly by the user, but the user may be authorized to perform a transaction that updates the field.

A classic example is a bank account balance. You can't just enter this number, but you can withdraw money from an ATM, and the withdrawal transaction updates the balance.

My first thought was to add some sort of "*System" AllowWrite role to the privileged properties, and then the transaction engine could somehow allow the current user to  adopt or impersonate the *System role only during the execution of a transaction.

Another possibility might be to use EditLevel to distinguish user updates from transactional updates (undo would never be used during a transaction), and then to do this with a validation rule (perhaps in conjunction with some sort of read-only attribute so the UI can take the appropriate action). However, this doesn't strike me as robust.

How have others handled this particular issue?

richardb replied on Thursday, November 08, 2007

Using your bank example, I'd have a BankTransaction object with a readonly property AccountBalance on your business object and a TransactionAmount property which the UI can set with the amount being withdrawn or deposited.  You can then add business rules to check that the account cannot go overdrawn, etc perhaps with an OverdraftLimit property to help.  Plus you can put authorisation code in the Save method or TransactionAmount property to make sure only authourised people can perform a transaction.

The UI will never be able to change the AcountBalance directly but when you save the business object the account balance will be recalculated in the database and returned to the business object (for example using an output paramter in the Update stored procedure).  In the save the returned account balance would be saved into your internal variable holding the account balance and thus the UI would then have access to the new balance.

If other transactions are going on at the same time on that account you'd get the right balance from the database.

Hope that helps.

Richard.

rsbaker0 replied on Thursday, November 08, 2007

So, in general you're suggesting that you have to move the read/write capability of such properties to an entirely different object and be careful not to make said object available to the user?

(Stored procedures are out for us since we support Access in addition to SQL Server and Oracle, so everything has be to done in the BO layer)

Meanwhile, I found that the authorization rules work fine for blocking updates to such properties, I guess it's just a question of whether that's a reasonable approach rather than moving them to a different object.

richardb replied on Friday, November 09, 2007

No, not really.  Perhaps I'm not being very clear here.

Lets say you have an object called Transaction with read only properties for Bank Account, Sort Code and AccountBalance.  You'll have a read/write property called TransactionAmount and the UI code will set this to the amount being withdrawn (or deposited).

Private _accountBalance as Decimal

public Readonly Property AccountBalance()
Get
   Return _accountBalance
End Get

Public Property TransactionAmount()
Get....
Set... etc

When the object is saved, if authorised to do so, your update code will apply the transaction amount to the database and the Account Balance changes in the database too.  Immediately after the save in the DataPortal_Update method you'd modify the internal member variable holding the accountbalance to reflect the new value, either from the dataset, output parameter of a stored procedure or however you are updating the data.

Sub DataPortal_Update()
...
...Do the Save
......then amend the balance on the object (really get it from the data source though!)
_accountBalance = _accountBalance - _transactionAmount
...

Richard.

 

richardb replied on Friday, November 09, 2007

PS.

Perhaps what I'm saying is that in the bank Account example, the AccountBalance would NEVER be writeable by the UI.  It would only be modified by a transaction being applied to it.

In your application it sounds to me then you perhaps sometimes want to allow the UI (a.ka. User) to be able to change the value and sometimes not base on some business rule. 

It may be appropriate to seperate the object and create 2 business objects but it sounds like you just need an authorisation rule on the property. 

I guess your analysis, Use Cases, etc have already identified that it really is only necessary for one business object here and not two, but some re-analysis and refactoring might change things later on.

Apologies if I'm just confusing things here.  Don't you sometimes wish there was just one way of doing things. :-)

Richard.

rsbaker0 replied on Monday, November 12, 2007

Thanks. Yes, there are many ways of doing things.

We're in the unfortunate position of having to migrate a legacy application and run (at least for a while) side-by-side with the old one.

In the original application, we wouldn't "bind" the "Account Balance" directly in the UI, but instead would bind a cached copy. If an authorized user wanted to directly change it, the altered value would be passed to a separate transaction processor that would do the actual update and record a Transaction record at the same time.  (Bind isn't the quite the right word, because it was a C++ application and we were in complete control of the movement of data to/from the UI and the data structures).

I'm trying to find a way to map this type of operation in the CSLA world. The actual behavior being implemented (at the object level) is simply that an Account Balance change must be accompanied by an associated Transaction.

Data binding/object updating seems to work much differently in the CSLA world. Previously, nothing was saved unless the user actually pushed a saved button. With EditableRootListBase, an object will be saved anytime the current row changes in the host list.

mtagliaf replied on Friday, November 09, 2007

 I do this type of stuff all the time.

   Public Property PrefPos() As Integer
        Get
            Return fPrefPos
        End Get
        Friend Set(ByVal value As Integer)     
            If Not fPrefPos.Equals(value) Then
                fPrefPos = value
                PropertyHasChanged()
            End If
        End Set
    End Property


Here's a property that can be ready by everybody, but can only be written to by other classes in the CSLA library.

Copyright (c) Marimer LLC