Hum. I guess I didn't explain myself well enough.
I have a client table with a 'client_id' column (it's unchangeable by the user). The number is a char(12) field, but it contains number values, based on a REF_KEY table, with the last used id for each table that needs these keys. So, there is a stored proc that returns the next avaliable number for a given table. Then, for the CLIENT table, there is another stored proc that calls the aforementioned one, pads the number out to 9 digits (why not 12, I'll never know), and then ensures there is no client_id with that number. if so, it goes back to the original stored proc to get another number, and re-checks this number, until an unused one is found. Okay. That's all there, and it's working.
Now, If I pull a number from that stored proc when I do a Client.NewClient() shared call, that's fine, I guess, except that if the user chooses not to actually save this client, I'll "waste" that Id. Is this a big deal? No, but it seems unnecessary to me somehow. So, I'd like to assign it at the same time as it would happen if I were using a normal autonumber integer indentifier field for the table: at the time the insert actually happens. Okay. But the Client has child collections (address, dependents, etc). So, with the save of the children happening automatically (by the CSLA framework) AFTER the root object's insertion, how can I propegate the parent's Client_Id value (returned from the Insert, I guess) down to the appropriate field on the child objects? I think I need a instance (not class) method on the child collection classes that can push the values down to the individual child items. Correct? And at the same time, because the child objects have a key of (Child_id, Seq_Num), I can assign an appropriate Seq_Num to any item that has a seq number of 0. I would call this collection method after inserting the root object, but before saving the child collections. Make sense?
If I take this approach then The retrevial of the next Client_Id value will happen within the InsertClient stored proc, so I technically don't need to understand this magical CommandBase object, but, to help augment my CSLA knowledge...
Next question of my original post.
The CommandBase object. Yeah. The book (CSLA 2.x) Expert VB2005 Business Objects talks about it, but in every case I can find, it has the code for the CommandBase class, without a single example of something that implements a CommandBase. Chapter 7 promises that there will be an example of this in Chapter 8 for the Exists method of, IIRC, the Project class. Yet, pouring over that chapter (admittedly, after a 20 hour work day), I can't find any hint of the example. And searching online has proven similarily unsuccessful. Every one says, "just use a CommandBase" object,but no one goes into detail.
I should be smart enough to figure this out, but I'm afraid I'm just not looking at it correctly. Suppose I have a Client object that inherits from BusinessBase. I want to have a "NextClientId" instance method that calls stored proc "GetNextClientId", passing in @NextClientId (in/out or out), and the table name, in this case "Client". I don't get the DataPortal stuff.
Should I declare a private class inside (inner class?) the Client object? If so, should it inherit CommandBase or simply ReadOnlyBusinessBase?
I'm not asking anyone to write my code for me, I'm simply hoping for someone to provide an example, with their code, that has done something similar. I'll adapt it to my needs. I have the stored proc, so that's fine. I just don't know how to hook that stored proc to CSLA object, considering that the stored proc doesn't return a result set. It simply updates the 'OUT' parameter. I suppose I could write a wrapper stored proc that ends with a "SELECT @NextClientId", forcing the creation of a result set and therefore is parallel to all our other CLSA CRUD procs. But it seems so unnecessary.
The previous thread talks about ADO.NET, Linq to SQL, etc, but that's not consistent with the rest of our CSLA approach. I know that CLSA objects can be written with Linq or ADO.NET calls, but I don't want to introduce another way of getting things done. Consistency is key to other developers understaning my code.
I can't speak my other companies, but at mine, hiding all the ORM stuff (yeah, I know, "Business Framework, not ORM framework" : ) in CodeSmith generated classes, means that our developers don't need to know much about it. Simply copy things from another similar class. So now that I want to do "something different", I'm having to really understand how this works. In our environment, almost everyone other than the architects are simple developers with only a high level knowledge of the CSLA framework; they know enough to decide what type of CSLA object to inherit from, but that's about it. And my architect is unavaliable until he gets back from medical leave, so I'm kinda lost here.
I sincerly appreciate the help folks have tried to provide, and hope a bit more comes my way.
Thanks for reading this far.
--
Don Brown
Lets try 1 more time then :-)
dbro199:Now, If I pull a number from that stored proc when I do a Client.NewClient() shared call, that's fine, I guess, except that if the user chooses not to actually save this client, I'll "waste" that Id. Is this a big deal? No, but it seems unnecessary to me somehow. So, I'd like to assign it at the same time as it would happen if I were using a normal autonumber integer indentifier field for the table: at the time the insert actually happens.
That's fine but just be careful how to handle transactions since if an insert fails during the execution of your dataportal insert then your IDs will not be in sync.
dbro199:Okay. But the Client has child collections (address, dependents, etc). So, with the save of the children happening automatically (by the CSLA framework) AFTER the root object's insertion, how can I propegate the parent's Client_Id value (returned from the Insert, I guess) down to the appropriate field on the child objects?
Do you even need a field for the FK value on your child object? Its not really a requirement... The way you propagate the parent PK value is (in the PT example):
// update child objects
_resources.Update(this);
This call occurs after the parent insert so "this" (the project) has its PK Id field populated. This is how you propagate parent ID values to child objects.
dbro199:If I take this approach then The retrevial of the next Client_Id value will happen within the InsertClient stored proc, so I technically don't need to understand this magical CommandBase object, but, to help augment my CSLA knowledge...
Yes that would be another valid approach. Just remember to populate your object with the new ID.
dbro199:Chapter 7 promises that there will be an example of this in Chapter 8 for the Exists method of, IIRC, the Project class. Yet, pouring over that chapter (admittedly, after a 20 hour work day), I can't find any hint of the example.
Sorry again I dont have the book in front of me. But download and check out the PTracker example, it is in there (int Library\Project.cs). If you follow the SP route of populating the PKs then you wont need the CommandBase for your scenario but its a good thing to know.
dbro199:I just don't know how to hook that stored proc to CSLA object, considering that the stored proc doesn't return a result set. It simply updates the 'OUT' parameter. I suppose I could write a wrapper stored proc that ends with a "SELECT @NextClientId", forcing the creation of a result set and therefore is parallel to all our other CLSA CRUD procs. But it seems so unnecessary.
The previous thread talks about ADO.NET, Linq to SQL, etc, but that's not consistent with the rest of our CSLA approach. I know that CLSA objects can be written with Linq or ADO.NET calls, but I don't want to introduce another way of getting things done. Consistency is key to other developers understaning my code.
The OUT paramter will be fine. No need to use wrapper SPs or anything complicated. The way you execute the SP is up to you. As long as it is in a DataPortal_XYZ method its up to you how you do it. CSLA is independent of the technology you use to access your data store.
Phew, hope this helps!
If the id is numeric and not changeable by the user (e.g. typical autonumber behavior), then one technique is to use a "pseudo" id while the object is new and defer generation of the actual id until the object is actually saved.
The ORM I am using uses negative numbers for new object id's bound to autonumber database fields. Each type maintains it's own last used value which decrements each time one is required. When the object is saved, the negative number is replaced with the actual value generated by the database.
Copyright (c) Marimer LLC