Command Object - Not Returning Values after execution

Command Object - Not Returning Values after execution

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


awbacker posted on Monday, September 22, 2008

I have written a command object, but I am having trouble getting the values back after it is executed through the portal.  Local execution works just fine. 

  1. I create a new object of my command type
  2. I set the various parameters
  3. I call DataPortal.Execute(Of MyClass)( instance )
  4. Execution goes fine (no exceptions, if I put a RAISERROR in it returns that as an ex, etc)
  5. The member variables that are populated by the DataPortal_Execute get their values
    1. I can test by throwing an exception inside DP_Ex, which is returned properly, and shows me that the server has the correct values at _that_  point.
  6. Control returns to my client
    1. Member variables are still in their initial state

Execute is this:

Protected Overrides Sub DataPortal_Execute()
   
Using cn As SqlConnection = New SqlConnection(Database.MyConnection)
       
Using cmd As SqlCommand = cn.CreateCommand()
             
cmd.CommandText = Procedure
              cmd.CommandType = CommandType.StoredProcedure
              cmd.Parameters.Add(CreateReturnParam())
              For Each key As String In _paramHashTable.Keys
                  cmd.Parameters.AddWithValue(key, _paramHashTable.Item(key))
              Next
              cn.Open()
              _scalarResult = CType(cmd.ExecuteScalar(), Object)
              _returnValue = GetReturnValue(cmd.Parameters)
              _procedure = "This overwrites the proc name"
          End Using
    End Using
End Sub

Is there something that I am doing wrong?  IIRC this worked previously, but I have no idea if it just wasn't tested properly, or there is some other detail I am overlooking.  I overwrite an existing value (_procedure) to see if that makes it back when the others do not; it doesn't :(

When I compile the dataportal, I restart IIS just to be sure.
CSLA 3.0.2

Thanks for any help,

//Andrew 

skagen00 replied on Monday, September 22, 2008

You are using the result object of the DP_Execute, right?

resultObject = DataPortal.Execute<MyCommandClass>(new MyCommandClass(parms0);

That's probably your problem.

awbacker replied on Monday, September 22, 2008

Nope, I was not :( I considered that, but the fact that it worked out just fine before is what had me stumped, so I didn't look at that.

It is looking like it wasn't properly tested, and probably never worked through the portal like I thought it did.

It would be really nice if it replaced the existing reference, but I don't know how excruciatingly difficult that would be =)

Thanks! 

// Andrew

JoeFallon1 replied on Monday, September 22, 2008

As I recall Rocky has changed the local dataportal to act (by default) the same way as the remote dataportal. That way your initial code that "worked" would have been broken and you could have fixed it sooner. He put this in to the framework and turned off initially with the caveat that in a future version he would turn it on. Well, the future is here.

This may well be the top support issue on the forum. We are seeing it a lot lately. We can expect to see more of it as people upgrade to the newer version. There is a switch to revert to the "old broken behavior" but it would be better to fix your code.

Joe

 

awbacker replied on Monday, September 22, 2008

Already patching. 

My "workaround" is to have the base class Execute() method pass the returned instance to a CopyProperties() function, which lets me copy the returned values/etc from the dataportal instance into the local instance, and then dispose of the returned instance.

Not the prettiest thing every, but it works pretty well.  I suppose you could get all fancy and do something with refleciton, but darn, that is simpler and probably faster.

// Andrew

ajj3085 replied on Monday, September 22, 2008

What's wrong with calling the Execute method like this?

cmd = DataPortal.Execute<MyCmd>( cmd );


awbacker replied on Monday, September 22, 2008

Nothing is wrong with doing it that way, just like the user experience of doing it without overwriting the object.   Also, and of course, that actually _is_ called, it is just hidden from the invokee. 

Doing it this way lets me keep all the existing code the same, since the handling of the return object is transparent to the caller.  Housekeeping is taken care of by the derived classes. 

Public MustInherit Class OurBaseCommand( Of .. long.. ) : CommandBase
    Public Sub Execute
()
        Dim r = DataPortal.Execute(Of derivedClass)(CType(Me, derivedClass
))
        Me._returnValue = r.
ReturnValue
       
'-- give the derived classes a chance to copy any properties 
       
CopyPropertiesAfterDataPortalExecute(r
)
        r =
Nothing
    End
Sub
End Class

'-- derived class, maintains the .ScalarResult code
Public
Class OurScalarCommand(Of T)
    Inherits OurBaseCommand(Of OurScalarCommand(Of T))

'-- Invoking the commands:
With New OurScalarCommand(Of Boolean)("some_procedure")
   
.AddParameter("@code", code)
   
.Execute()
   
Return .ScalarResult
End With

   

rsbaker0 replied on Monday, September 22, 2008

JoeFallon1:

This may well be the top support issue on the forum. We are seeing it a lot lately. We can expect to see more of it as people upgrade to the newer version. There is a switch to revert to the "old broken behavior" but it would be better to fix your code.

If only there were some way to require the result of a method to be assigned via an attribute of some sort versus just invoking it for its side effects - e.g. let the compiler flag the problems for us... :(

awbacker replied on Tuesday, September 23, 2008

I assume a compiler generated temp would suffice, since I would like to be able to do things like :

dim x = DataPortal.Execute(new Command(params)).ResultValue

Copyright (c) Marimer LLC