# CSLA : Step-by-Step, Complex Data Types & some gotchas

Welcome to the third instalment of CSLA: Step-by-Step. In the previous 2 parts we looked at which [tools](/archive/2007/08/29/csla--step-by-step--getting-started.aspx) to use to get started and creating business objects with parent-child [relationships](/archive/2007/09/24/csla--step-by-step--relationships.aspx).

In this part we’ll do some pretty cool stuff with CSLA as well as tackling one or two gotchas that pops up every now and again.  
All right, let’s get cracking. Open our NorthwindTraders solution, we created in part 1. If you followed the previous two tutorials you should already have the following classes in your project:

*   Customer (BusinessBase/EditableRoot)
*   Database (Module)
*   Order (BusinessBase/EditableRoot)
*   OrderDetail (BusinessBase/EditableChild)
*   OrderDetails (BusinessListBase/EditableChildList)

### **The Gotchas**

One gotcha that had me scratching my had every now and again is when you try to create a new object i.e. Order.NewOrder(), you get the following error:

_Csla.DataPortalException : DataPortal.Create failed (System.NotSupportedException: Invalid operation – create not allowed_

You can test this by adding the following code to your OrderUnitTests class in your Northwind solution’s Order.vb :  

<Test()\>\_  
PublicSubCreateOrder()  
DimobjOrderAsOrder\=Order.NewOrder  
objOrder.CustomerID\="ALFKI"  
objOrder.EmployeeID\=1  
objOrder.ShipVia\=1  
objOrder.Save()  
EndSub  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

At first it seems like an extremely weird error, but the solution and explanation is actually very easy. You’ll notice that your object’s DataPortal\_Create, expect a criteria parameter of type object. Remove the parameter from and test your code again.Viola! it works.

You’ll notice this error only happens when you have an object for a table that has a primary key that also has an Identity Specification. The code generated expects you pass the primary key/identifier for the object, but when it is assigned by the database, you obviously wouldn’t need to. The Customer object in our Northwind Solution, will work without any hiccups, because you have to specify the CustomerID when creating a new Customer.

Another gotcha is when you manually add a child property to your business object. You have to change the IsValid and IsDirty property of your object to include the new child object. Also make sure you change your Data Access code to include the new child object. The easiest way this can be overcome by just re-generating your business object and including both child object properties.

### **The Cool Stuff**

Right, let’s get to the nifty bit.

Create a new BusinessBase/EditableRoot object called Product. Use CodeSmith to generate it from the Northwind Products table and MyGeneration to generate the sql stored procedures. See [part 1](/archive/2007/08/29/csla--step-by-step--getting-started.aspx), if you need to know how.  
Your CodeSmith property grid should look something like this:

[![Product](http://www.mythicalmanmoth.com/wp-content/uploads/2009/10/product-thumb.png "Product")](http://www.mythicalmanmoth.com/wp-content/uploads/2009/10/product.png)

We are going to change the ProductID property on you OrderDetail object to be of type Product and not Integer. This will give us some pretty cool and powerful flexibility later on.

First open your OrderDetail class. Change the ProductID variable and property to look like this:

Private\_productAsProduct\=Nothing

PublicPropertyProduct()AsProduct  
Get  
CanReadProperty("Product",True)  
Return\_product  
EndGet  
Set(ByValvalueAsProduct)  
\_product\=value  
EndSet  
EndProperty  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

Change FetchObject, AddInsertParameters and AddUpDateParameters to look like this:

PrivateSubFetchObject(ByValdrAsSafeDataReader)  
\_orderID\=dr.GetInt32("OrderID")  
\_product\=Product.GetProduct(dr.GetInt32("ProductID"))  
\_unitPrice\=dr.GetDecimal("UnitPrice")  
\_quantity\=dr.GetInt16("Quantity")  
\_discount\=dr.Item("Discount")  
EndSub

PrivateSubAddInsertParameters(ByValcmAsSqlCommand,ByValparentAsOrder)  
cm.Parameters.AddWithValue("@OrderID",parent.OrderID)  
cm.Parameters.AddWithValue("@ProductID",\_product.ProductID)  
cm.Parameters.AddWithValue("@UnitPrice",\_unitPrice)  
cm.Parameters.AddWithValue("@Quantity",\_quantity)  
cm.Parameters.AddWithValue("@Discount",\_discount)  
EndSub

PrivateSubAddUpdateParameters(ByValcmAsSqlCommand,ByValparentAsOrder)  
cm.Parameters.AddWithValue("@OrderID",\_orderID)  
cm.Parameters.AddWithValue("@ProductID",\_product.ProductID)  
cm.Parameters.AddWithValue("@UnitPrice",\_unitPrice)  
cm.Parameters.AddWithValue("@Quantity",\_quantity)  
cm.Parameters.AddWithValue("@Discount",\_discount)  
EndSub  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

Instead of passing the ProductID variable, we’re passing the Product object’s ProductID property and we’re fetching a Product object rather than an integer value.

In theory we can now also change our UnitPrice property to a readonly property and return the Product.UnitPrice, like so:

PublicReadOnlyPropertyUnitPrice()AsDecimal  
Get  
CanReadProperty("UnitPrice",True)  
Return\_product.UnitPrice  
EndGet  
EndProperty  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

**Note:** You can then also change you data access code, practically you would no longer need to save the unit price on the OrderDetail level. This would all depend on the design of your application. For now, we’ll just assume, we no longer require the unit price on the order detail, since we have it on the product level.

Now we need to see if the changes we’ve made actually works. Let’s create our Order with Details Unit test, it can look something like this:

<Test()\>\_  
Public Sub CreateOrder()  
‘We Get the Product we want to add to this order  
‘our clientisafanofGrandma’sBoysenberrySpreadsohe’sordereda100  
Dim objProduct As Product\=Product.GetProduct(6)

‘Wecreatetheorder  
Dim objOrderAs Order\=Order.NewOrder  
objOrder.CustomerID\="CHOPS"  
objOrder.EmployeeID\=1  
objOrder.ShipVia\=1

‘WecreatetheOrderDetail  
Dim objDetail As OrderDetail\=OrderDetail.NewOrderDetail  
objDetail.Product\=objProduct  
objDetail.Quantity\=100

‘AddtheOrderDetailtotheorder  
objOrder.Orderdetails.Add(objDetail)

‘SavetheOrder  
objOrder.Save()

‘DisplayourneworderID  
Console.Write(objOrder.OrderID.ToString)  
EndSub  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

**Note:** I’ve add a constructor to the OrderDetail object to make things easier. Also when you compile there will be a few errors complaining about the \_productID, remember it’s now the \_product.ProductID.Here’s the code for the constructor:

Friend Shared Function NewOrderDetail()As OrderDetail  
Return New OrderDetail()  
EndFunction

Private Sub New()  
ValidationRules.CheckRules()  
MarkAsChild()  
EndSub  

Generated using [PrettyCode.Encoder](http://www.vbcity.com/encoder)

I’ve made a couple of changes to the code, that I did not mention here, you can download the files [here](/downloads/Code_Part3.zip).

I hope part 3 was of use, tune in next time for some Data Binding Fun with CSLA.

Happy Coding!
