Editable Root Collection

Editable Root Collection

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


esaulsberry posted on Thursday, June 04, 2009

Hello,

I'm running into a little difficulty with a collection. The collection is intended to be an Editable Root Collection as described on p. 187 in the current book.

The collection is defined like this:

public class ClientList : BusinessListBase<ClientList, Client>

The child client object is defined as

public class Client : BusinessBase<Client>
...
internal static Client GetClient(Data.Client client){
   return DataPortal.FetchChild<Client>(client);
}
...
private void Child_Update() { ...

If I understand p.189 correctly, the BLB's default implementation of DataPortal_Update should call the Child_Update on the children.  I have no update methods in the list class as shown in the example on p. 188.  However when the Silverlight CslaDataProvider Save method is invoked, the base class throws at line 113 in BusinessBase (version 3.6.2)

public virtual T Save(){
T result;
if (this.IsChild)
throw new NotSupportedException(Resources.NoSaveChildException);

I'm trying to use this as follows:

I have a silverlight form that's a "client editor".  The bottom half has a grid control of clients bound to the list provided by the data provider.  When the selection changes, the selected item is made the data context of the edit form in the top half of the control. 

private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e){HorizonSoftware.OSMobileStock.BusinessObjects.Client client = e.AddedItems[0] as HorizonSoftware.OSMobileStock.BusinessObjects.Client;
if (client != null){
GrdClientForm.DataContext = client;
}
}

The save button is tied to the save function on the data provider.  This seems like a reasonable approach.  I don't what to have to round trip every time the selection changes to fetch an editable root for the edit form.  The book seems to indicate this pattern is supported but if it is I haven't found the magic sprinkles.

Thanks for taking a look.

Elton

sergeyb replied on Thursday, June 04, 2009

I think you have an issue on your form.  I think you are calling Save() on an individual client record instead of ClientList object.  If you can paste the code that fires Save on your form, I can tell for sure.

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: esaulsberry [mailto:cslanet@lhotka.net]
Sent: Thursday, June 04, 2009 5:34 PM
To: Sergey Barskiy
Subject: [CSLA .NET] Editable Root Collection

 

Hello,

I'm running into a little difficulty with a collection. The collection is intended to be an Editable Root Collection as described on p. 187 in the current book.

The collection is defined like this:

public class ClientList : BusinessListBase<ClientList, Client>

The child client object is defined as

public class Client : BusinessBase<Client>
...
internal static Client GetClient(Data.Client client){
   return DataPortal.FetchChild<Client>(client);
}
...
private void Child_Update() { ...

If I understand p.189 correctly, the BLB's default implementation of DataPortal_Update should call the Child_Update on the children.  I have no update methods in the list class as shown in the example on p. 188.  However when the Silverlight CslaDataProvider Save method is invoked, the base class throws at line 113 in BusinessBase (version 3.6.2)

public virtual T Save(){
T result;
if (this.IsChild)
throw new NotSupportedException(Resources.NoSaveChildException);

I'm trying to use this as follows:

I have a silverlight form that's a "client editor".  The bottom half has a grid control of clients bound to the list provided by the data provider.  When the selection changes, the selected item is made the data context of the edit form in the top half of the control. 

private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e){HorizonSoftware.OSMobileStock.BusinessObjects.Client client = e.AddedItems[0] as HorizonSoftware.OSMobileStock.BusinessObjects.Client;
if (client != null){
GrdClientForm.DataContext = client;
}
}

The save button is tied to the save function on the data provider.  This seems like a reasonable approach.  I don't what to have to round trip every time the selection changes to fetch an editable root for the edit form.  The book seems to indicate this pattern is supported but if it is I haven't found the magic sprinkles.

Thanks for taking a look.

Elton



esaulsberry replied on Friday, June 05, 2009

Looks like Rocky had the key.

For what it's worth, here's how it's hooked up.

<csla:CslaDataProvider x:Key="CslaDpClient"
DataChanged="CslaDpClient_DataChanged"
ManageObjectLifetime="True"
IsInitialLoadEnabled="False"
ObjectType="HorizonSoftware.OSMobileStock.BusinessObjects.ClientList, HorizonSoftware.OSMobileStock.BusinessObjects, Version=..., Culture=neutral, PublicKeyToken=null"
FactoryMethod="BeginGetClientList"
PropertyChanged="CslaDpClient_PropertyChanged" />

<Grid Height="Auto" Margin="0,0,0,0" x:Name="GrdClientEditor" VerticalAlignment="Stretch" Grid.Column="1" Grid.Row="0" DataContext="{Binding Path=Data, Source={StaticResource CslaDpClient}}">

<data:DataGrid AutoGenerateColumns="False" HeadersVisibility="Column" x:Name="dgClient" ItemsSource="{Binding}" Margin="8,0,8,0" SelectionChanged="DataGrid_SelectionChanged">

<Button x:Name="BtnSave" Width="76.855" Margin="0,0,3,0"
csla:InvokeMethod.MethodName="Save"
csla:InvokeMethod.Resource="{StaticResource CslaDpClient}"
csla:InvokeMethod.TriggerEvent="Click"
IsEnabled="{Binding Mode=OneWay, Path=CanSave, Source={StaticResource CslaDpClient}}">

RockfordLhotka replied on Friday, June 05, 2009

Btw, in 3.6.2 and higher you can use a shorter ObjectType value:

 

ObjectType=”HorizonSoftware.OSMobileStock.BusinessObjects.ClientList, HorizonSoftware.OSMobileStock.BusinessObjects

 

The version/culture/etc aren’t required unless you sign the assembly.

 

Rocky

RockfordLhotka replied on Thursday, June 04, 2009

I know there's some minor errata in that area of the book - like one word is wrong - but that could be the issue.

For a root collection you do need to implement DataPortal_Update(), because CSLA doesn't know how to open your database connection, object context, data context or whatever you are using to talk to your database.

Also, CSLA doesn't know what transactional model you want, so you need to implement the DataPortal_Update() method so you can put the appropriate Transactional attribute on the method.

But the implementation is generally easy, because Child_Update() does all the work:

protected override void DataPortal_Update()
{
  // open database connection or whatever
  base.Child_Update();
  // close database connection or whatever
}

 

esaulsberry replied on Friday, June 05, 2009

That's all it took.  Thanks.

cdkisa replied on Thursday, June 04, 2009

Change your code to this instead...(root objects do not call "Child" methods)

internal static Client GetClient(int clientID){
   return DataPortal.Fetch<Client>(clientID);
}

...

private void DataPortal_Fetch() { ...

private void DataPortal_Update() { ...

private void DataPortal_Insert() { ...

private void DataPortal_Delete() { ...

esaulsberry replied on Friday, June 05, 2009

cdkisa:

Change your code to this instead...(root objects do not call "Child" methods)

Thanks for taking a look.  In this case, the collection is the root and the business object is a child of the collection, so the UI calls for the collection and it does the rest.  The individual BO's aren't created by the UI individually.

Elton

 

Copyright (c) Marimer LLC