[
Serializable()] public class SomeParent : BusinessBase<SomeParent>{
#region
Constructors private SomeParent(){
/* require use of factory methods */ }#endregion
#region
Public Properties#region
SomeParentID private Int32 _someParentID = 0;[System.ComponentModel.
DataObjectField(true, true, false)] public Int32 SomeParentID{
[System.Runtime.CompilerServices.
MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] get{
CanReadProperty(
"SomeParentID", true); return _someParentID;}
}
#endregion
//Child Object Collection#region
ChildList private ChildList _childList = ChildList.NewChildList(); public ChildList ChildList{
get { return _childList; }}
#endregion
#endregion
#region
Business Base Requirements protected override object GetIdValue(){
return _someParentID;}
// The default IsValid and IsDirty properties must be enhanced for all objects that // subclass BusinessBase and contain child objects public override bool IsValid{
get{
return base.IsValid && _childList.IsValid;}
}
public override bool IsDirty{
get{
return base.IsDirty || _childList.IsDirty;}
}
#endregion
#region
Factory Methods /// Create a new instance of a SomeParent public static SomeParent NewParent(){
if (!CanAddObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.AddEntityNotAllowed, "SomeParent")); return DataPortal.Create<SomeParent>();}
/// Get an Instance of a SomeParent by querying on Default public static SomeParent Get(Int32 someParentID){
if (!CanGetObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.ViewEntityNotAllowed, "SomeParent")); SomeParent fetchInstance = null; try{
fetchInstance =
DataPortal.Fetch<SomeParent>(new Criteria(someParentID));}
catch (System.Exception ex){
Logger.Error(ex.Message); throw;}
return fetchInstance;}
/// Deletes a SomeParent based on its Default public static void Delete(Int32 someParentID){
if (!CanDeleteObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.DeleteEntityNotAllowed, "SomeParent")); try{
DataPortal.Delete(new Criteria(someParentID));}
catch (System.Exception ex){
throw;}
}
/// Save the current instance of a SomeParent public override SomeParent Save(){
if (IsDeleted && !CanDeleteObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.DeleteEntityNotAllowed, "SomeParent")); else if (IsNew && !CanAddObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.AddEntityNotAllowed, "SomeParent")); else if (!CanEditObject()) throw new System.Security.SecurityException(String.Format(ExceptionResources.UpdateEntityNotAllowed, "SomeParent")); SomeParent saveInstance = null; try{
saveInstance =
base.Save();}
catch (System.Exception ex){
throw;}
return saveInstance;}
#endregion
#region
Criteria Classes[
Serializable()] private class Criteria{
#region
SomeParentID private Int32 _someParentID = 0; public Int32 SomeParentID{
get{
return _someParentID;}
}
#endregion
public Criteria(Int32 someParentID){
_someParentID = someParentID;
}
}
#endregion
Criteria Classes#region
Data Access[
RunLocal()] protected override void DataPortal_Create(){
ValidationRules.CheckRules();
}
private void DataPortal_Fetch(Criteria criteria){
using (DbConnection conn = Database.DBConnection){
conn.Open();
using (DbCommand cmd = conn.CreateCommand()){
cmd.CommandType =
CommandType.StoredProcedure;cmd.CommandText =
"SomeParentGet"; DbParameter param;#region
@p_SomeParentIDparam = cmd.CreateParameter();
param.ParameterName =
"@p_SomeParentID";param.DbType =
DbType.Int32;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(criteria.SomeParentID);cmd.Parameters.Add(param);
#endregion
using (NullableDataReader dr = new NullableDataReader(cmd.ExecuteReader())){
if (dr.Read()){
Fetch(dr);
// Load all the child objectsdr.NextResult();
_childList =
ChildList.GetChildList(dr);}
else{
throw new Csla.DataPortalException("Criteria Did Not Match any Data", this);}
}
}
}
}
private void Fetch(NullableDataReader dr){
_SomeParentID = dr.GetInt32(
"SomeParentID");}
[
Transactional(TransactionalTypes.TransactionScope)] protected override void DataPortal_Update(){
if (base.IsDirty || _childList.IsDirty){
using (DbConnection conn = Database.DBConnection){
conn.Open();
using (DbCommand cmd = conn.CreateCommand()){
cmd.CommandText =
"SomeParentUpdate";cmd.CommandType =
CommandType.StoredProcedure; DbParameter param;#region
@p_SomeParentIDparam = cmd.CreateParameter();
param.ParameterName =
"@p_SomeParentID";param.DbType =
DbType.Int32;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(_someParentID);cmd.Parameters.Add(param);
#endregion
int rowsAffected = cmd.ExecuteNonQuery();_childList.Update(
this);}
}
}
}
#endregion
}
Now to the collection object
// Business List Base class
[Serializable()] public class ChildList : BusinessListBase<ChildList, Child>{
#region
Business Methods // Add methods and expose it to UI for playing with the collection public void AddChild(int someParentID, string childItem){
Child newItem = Child.NewChild(someParentID, childItem); if (!Contains(newItem)) this.Add(newItem);}
public void RemoveChild(int someParentID, string childItem){
Child newItem = Child.NewChild(someParentID, childItem); foreach (Child item in this){
if (item.ParentID == someParentID && item.ChildItem == chilItem){
Remove(item);
break;}
}
}
#endregion
#region
Factory Methods // The factory methods are declared as internal scope since they are not for use by the // UI code,internal static ChildList NewChildList()
{
//Returns a new instance of the collection object
return new ChildList();}
internal static ChildList GetChildList(NullableDataReader dr){
//Returns collection with the child objects based on the data from the database return new ChildList(dr);}
#endregion
#region
Constructor private ChildList(){
MarkAsChild();
}
private ChildList(NullableDataReader dr){
MarkAsChild();
Fetch(dr);
}
#endregion
#region
Data Access //Loading Data private void Fetch(NullableDataReader dr){
RaiseListChangedEvents =
false; while (dr.Read()) this.Add(Child.GetChild(dr));RaiseListChangedEvents =
true;}
//Updating Data internal void Update(SomeParent someParent){
RaiseListChangedEvents =
false; // Delete the child objects that are removed from the collection foreach (Child item in DeletedList)item.DeleteSelf(
Convert.ToInt32(item.ParentID), item.ChildItem);DeletedList.Clear();
// Add or Update any current child objects foreach (Child item in this){
if (item.IsNew)item.Insert();
elseitem.Update();
}
RaiseListChangedEvents =
true;}
#endregion
}
Now the Child itself
// Business Base Class
// Child Object[
Serializable()] public class Child: BusinessBase<Child>{
#region
Public Properties#region
ParentID private Int32? _parentID = null; public Int32? ParentID{
get{
return _parentID;}
set{
if (_parentID != value){
_parentID =
value;}
}
}
#endregion
#region
ChildItem private String _childItem = null; public String ChildItem{
get{
return _childItem;}
set{
if (_childItem != value){
_childItem =
value;}
}
}
#endregion
#endregion
#region
BusinessBase Requirements protected override object GetIdValue(){
return string.Format("{0}:{1}", _parentID, _childItem);}
#endregion
#region
Constructors // Default private constructor private Child(){
MarkAsChild();
}
// New private Child(int parentID, string childItem){
MarkAsChild();
_parentID = parentID;
_childItem = childItem;
}
// Get private Child(NullableDataReader dr){
MarkAsChild();
_parentID = dr.GetNullableInt32(
"ParentID");_childItem = dr.GetNullableString(
"ChildItem");MarkOld();
}
#endregion
#region
Factory Method internal static Child NewChild(int parentID, string childItem){
return new Child(parentID, childItem);}
internal static ChildGetChild(NullableDataReader dr){
return new Child(dr);}
#endregion
#region
Data Access internal void Insert(){
using (DbConnection conn = Database.DBConnection){
conn.Open();
using (DbCommand cmd = conn.CreateCommand()){
cmd.CommandText =
"ChildInsert";cmd.CommandType =
CommandType.StoredProcedure; DbParameter param;#region
@p_ParentIDparam = cmd.CreateParameter();
param.ParameterName =
"@p_ParentID";param.DbType =
DbType.Int32;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(_parentID);cmd.Parameters.Add(param);
#endregion
#region
@p_ChildItemparam = cmd.CreateParameter();
param.ParameterName =
"@p_ChildItem";param.DbType =
DbType.AnsiString;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(_childItem);cmd.Parameters.Add(param);
#endregion
int rowsAffected = cmd.ExecuteNonQuery();}
}
}
internal void Update(){
if (base.IsDirty){
using (DbConnection conn = Database.DBConnection){
conn.Open();
using (DbCommand cmd = conn.CreateCommand()){
cmd.CommandText =
"ChildUpdate";cmd.CommandType =
CommandType.StoredProcedure; DbParameter param;#region
@p_ParentIDparam = cmd.CreateParameter();
param.ParameterName =
"@p_ParentID";param.DbType =
DbType.Int32;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(_parentID);cmd.Parameters.Add(param);
#endregion
#region
@p_childItemparam = cmd.CreateParameter();
param.ParameterName =
"@p_childItem";param.DbType =
DbType.AnsiString;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(_childItem);cmd.Parameters.Add(param);
#endregion
int rowsAffected = cmd.ExecuteNonQuery();}
}
}
}
internal void DeleteSelf(int ParentID, string childItem){
Delete(parentID, childItem);
}
internal void Delete(int parentID, string childItem){
using (DbConnection conn = Database.DBConnection){
conn.Open();
using (DbCommand cmd = conn.CreateCommand()){
cmd.CommandType =
CommandType.StoredProcedure;cmd.CommandText =
"ChildDelete"; DbParameter param;#region
@p_ParentIDparam = cmd.CreateParameter();
param.ParameterName =
"@p_ParentID";param.DbType =
DbType.Int32;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(parentID);cmd.Parameters.Add(param);
#endregion
#region
@p_ChildItemparam = cmd.CreateParameter();
param.ParameterName =
"@p_ChildItem";param.DbType =
DbType.AnsiString;param.Direction =
ParameterDirection.Input;param.Value =
Database.DBNullConvert(assetUsage);cmd.Parameters.Add(param);
#endregion
int rowsDeleted = cmd.ExecuteNonQuery();}
}
}
#endregion
}
Now on the UI
SomeParent someParent = SomeParent.Get(SomeID);//Get the Parent and its children
For adding a child to the collection call the public method AddChild of ChildList object which in turn checks to see whether child already exists and then calls the internal constructor.
someParent.ChildList.AddChild(newID,newChildItem)
For removing a child from the collection call the public method RemoveChild of ChildList object
someParent.ChildList.RemoveChild(somechildID,somechildItem)
Update the Parent someParent.
someParent.Save();
This would mean that all the objects are updated in the same transaction scope hence the child list update doesn not require transactional scope and so the Update is called in the SomeParent transaction scope.This would rollback the whole transaction and would prevent inconsistency.
1) The above example still would work if you want to add the children in a separate form.Get the parent and children(in this case someParent but a empty children list) and use the AddChild() to add and save the Parent.
2)The IDs for the child objects would have to be created when the the factory method AddChild() calls the internal constructors.In my case I had a composite key and hence I pass the parentID and another value(childItem) wchihc forms the key for the child object.
HTH,
Note:I modifed my class so there might be some typos :-(.I created these based on the same example in the text book but instead of the Assign factory method I had to add AddChild and RemoveChild methods.One more issue was configuring the MSDTC to allow distributed transactions.
Cheers
Hi,
I am not quite sure about it since we have not moved to that yet.
Cheers
From another Forum post http://www.lhotka.net/weblog/CSLANET35CodeReductionWithChildObjects.aspx
It looks like you can still code the child objects in CSLA 2.0 or using the new 3.5 Child_XXX Methods that auto mark the object as childern.
Copyright (c) Marimer LLC