Chicken or the Egg

Chicken or the Egg

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


wjcomeaux posted on Tuesday, January 23, 2007

What should come first?

My NewApplicationRequest (editable root) has a private member of Request (editable child)

When I do DataPortal_Insert, the NewApplicationRequest is put into the database first and then UpdateChildren is called. However, my NewApplicationRequest table needs the ID from the Request table so obviously I'd need to perform my UpdateChildren first and then save the NewApplicationRequest (when I have the RequestID available). However, the templates don't handle this.

I am wondering if my design here is flawed. Should my main objects be the Request and each one have a child of the superclass?

What I have right now is

class NewApplicationRequest{
   Request _request;
   int _requestID;
} //this won't work because Insert requires the _requestID to be correct

Should I have something like this instead?

class Request {
   NewApplicationRequest _newApplicationRequest;
}

In which case, what then does the data look like? Right now my tables all reference the ID of the base Request. The other way around would require that the Request table have two columns (one for the ID of the wrapping data and another column to help determine what table the wrapping data is).

Current data is like this
Request(ID, other stuff)
NewApplicationRequest(ID, RequestID, other stuff)
BugFixRequest(ID, RequestID, other stuff)

Would I have to go to this model?
Request(ID, SuperRequestID, SuperRequestType)
NewApplicationRequest(ID, other stuff)
BugFixRequest(ID, other stuff)

I like my current data model more because it seems simpler and more intuitive but for CSLA it is making life difficult ATM.

Thanks for any thoughts,
Will

 

phowatt replied on Tuesday, January 23, 2007

I am not sure if I understand your problem but it sounds like you are using using the IDENTITY function in the database to assign the ID.  Many people do not use that approach they instead use a GUID for ID and therefore when the editable root is created the ID is known.  I do not do that I use the IDENTITY function of SQL Server.  Obviously you will not know the ID of the root object until it has been saved to the database.  But the stored procedure that does the save will return the IDENTITY value so you can retrieve that value before you update the children.  The next issue is how to pass that ID value to the child update process.  The technique I use is to create a variable of the type HashTable.  Then in the create methods of the children I pass a parameter of the type HashTable and then pass a reference to the HashTable variable in the root object.  I can then add any number of values to the has table and since all children have access to the same HashTable I have a way to share information throughout the object tree.  So after retrieving the IDENTITY from the root save stored procedure I add that ID to the hash table.  In the child update process I just retrieve the the root ID from the HashTable reference that was passed to the child when the child was created.

I have used this extensively and it works just fine.  I did, however, discover one problem with it and it has to do with the third party datagrid I use.  Since the IDs are not assigned until the newly created objects are saved for the first time the child collection items will all have the same ID of zero if the ID is an integer for example.  My datagrid did not like that so I had to add a little logic in the child manager class in the Add method that assigned a temporary ID to each child.  I simply kept a running tally variable and subtracted 1 each time I added a new child.  So all of the child items had negative numbers and none of them were repeating and could never conflict with numbers assigne by SQLServer since they are all positive numbers. 

Hopefully this is a help.

Skafa replied on Tuesday, January 23, 2007

You can also make an EditableRoot Request, wich will be saved first. It's ID will be assigned to NewApplicationRequest and then saved.

wjcomeaux replied on Tuesday, January 23, 2007

I am using the @@Identity function of SQL Server to get the ID of the last inserted record. This is returned via an output parameter and CSLA then has access to it in the Insert function.

However, the problem is what happens when I have a business object that has an ID property that is dependent on a child business object.

The example of Request and NewApplicationRequest
My NewApplicationRequest uses composition so it has
private int _newApplicationRequestID;
private Request _request; //The child business object
private int _requestID;//The id in the child business object (not necessary just for ease of use, will probably remove as this is accessible from _request.ID

So the CodeSmith templates generate this for NewApplicationRequest

protected override void DataPortal_Insert()

{

using (SqlConnection cn = new SqlConnection(Database.RequestsConnection))

{

cn.Open();

ExecuteInsert(cn);

//update child object(s)

UpdateChildren(cn);

}//using

}

In the above code, the ExecuteInsert statement needs to know the value of the _request.ID, however, this is not known until after the call to UpdateChildren which persists the _request object to the database and gets the @@Identity value.

I could change the code generation template to call UpdateChildren before ExecureInsert and that would indeed solve this issue but it doesn't feel proper. If feels down right backwards actually.

One would think that Request would be the parent object and would have a child of NewApplicationRequest but that also doesn't fit right and opens a lot of other issues.

I am thinking ATM that I will alter the code generator to examine a flag. I know at ORM time in which objects I need to save the children first. So maybe if that flag is true I can do this
UpdateChildren()
UpdateMyIDProperty()
ExecuteInsert()

and when the flag is false I can just do that
ExecuteInsert()
UpdateChildren()

Thoughts on this approach?

Thanks,
Will

phowatt replied on Tuesday, January 23, 2007

I guess I do not understand why the root needs to have the child ID.  Usually it is the child that has the root ID which is what provides the relationship for the set.

wjcomeaux replied on Tuesday, January 23, 2007

And I think I have a solution. It came not in a problem with the business objects on in the code generation but from a denormalized database. Now I feel silly from not spotting this a LOT sooner.

Turns out that my business object parent child relationship is made very difficult by having a database structure with a parent child relationship that doesn't make sense.

We have a Request table that stores basic information about all request objects. We then have NewApplicationRequest, BugFixRequest, etc that foreign key into the Request table. However, in CSLA terms, the Request is the primary table and would be the parent object and the others would be the child. However, this leaves me with a single Request object that we would have to then write logic to figure out the exact type based on child objects (bad design). My design of making the child database tables serve as the parent has the falldown of not knowing the parent ID during persistence time.

It turns out normalizing the database (take the fields from the Request table and simply incorporate them into all of the child tables) solves the issue. The database is now more normalized since my relationships were 1 to 1 then it is more normalized to have that data in the same table. Each record in Requests connects to one and only one record in one of the other (more specific) request tables.

I was trying to keep the generic data inside a single table and then have a table each for all the types of request objects. It turns out that this would benefit me nothing and will likely degrade performancce some as I'd require a join every time I want to load a single request. Now, no more joins, and still no duplicated data.

So, this seems like it will work well and generate a simple data model and business object structure. Only now I have to alter our data model a bit.

Thoughts are still welcome,
Will

RockyRocks replied on Monday, April 16, 2007

Hi all,

I'm new on here which is why I'm responding to an 'old' thread. I'm no expert but I thought I'd reflect on your problem and whether your solution was what I would have done.

I can see why you might have wanted your original data structure. It is perhaps better normalised than your final solution, because although there is no duplication of data in your latest model there is duplication of fields.

I think one answer to your dilemma relates to regeneration. Are the templates about generating an entire object without changes, or are they about getting you 95% there and changing the stuff once generated? Trying to build a generic code generation tool that generates a complete and regeneratable object is nigh impossible - you could get it to work within a limited zone (such as an application or suite of applications) but could lose most of your life taking it any further.

So far my approach with code generation (only a few apps to date) is that it creates a 'near complete' object for me that I then tweak after the fact. I add custom validation rules to enforce data integrity, custom data access to split data model from object model, and so on (remember that a data model and object model are not necessarily a 1 to 1 mapping in every case). I wouldn't expect the code generation tool to do this for me - it can't be expected to read my mind. In your case, once generated you could simply reorder the save of child and parent.

Obviously the disadvantage of my generate-once method is when the data structure changes; particularly when fields are added to the data model. I DO see the benefit of regeneration (no, really, I do!) but I'm not personally convinced that it's all that easy and so at the moment I don't consider it worth trying. When I add fields, I simply regenerate and then take the bits I want from the CodeSmith output and paste them into the class I had already. This is even easier than before because CSLA.NET 1.5 and above support the separation of validation rules from properties, so the properties can more often be left untouched (but not always - see Project class in the book and its dependency between start and end dates).

As an aside, I would reconsider whether the data you were trying to represent is in fact parent/child at all, which it isn't really. It's kinda summary and detail i.e. base class and extension, and should not necessarily be represented in your object model as hierarchical objects at all, perhaps being stored like this only in the data model. You might want a list that summarises all Request types and your original data structure made that easy. Because the data to object model need not be a one to one relation, I would have saved it in the data model in the way you identified and modified the stored procedures (or data access code) to flatten this in the object model.

Food for thought perhaps?

 

Andrew

Copyright (c) Marimer LLC