Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
'Imports System.Configuration
''AyaNova Imports
Imports System.Threading
Imports CSLA.Security
'''
''' This is the base class from which most business collection
''' objects will be derived.
'''
'''
'''
''' To create a collection of business objects, inherit from this
''' class. The business objects contained in this collection must
''' inherit from , and the objects
''' must be marked as child objects.
'''
''' Please refer to 'Expert One-on-One VB.NET Business Objects' for
''' full details on the use of this base class to create business
''' collections.
'''
'''
_
Public MustInherit Class BusinessCollectionBase
Inherits CSLA.Core.SortableCollectionBase
Implements ICloneable
Implements Serialization.ISerializationNotification
#Region " Contains "
'''
''' Used to see if the collection contains a specific child object.
'''
'''
''' Only the 'active' list of child objects is checked.
''' Business collections also contain deleted objects, which are
''' not checked by this call.
'''
''' A reference to the object.
''' True if the collection contains the object.
Public Function Contains(ByVal Item As BusinessBase) As Boolean
'Return list.Contains(Item)
Dim element As BusinessBase
For Each element In list
If element.Equals(Item) Then
Return True
End If
Next
Return False
End Function
'''
''' Used to see if the collection contains a reference to a
''' child object that is marked for deletion.
'''
'''
''' This scans the list of child objects that have been marked
''' for deletion. If this object is in that list, the method
''' returns True.
'''
''' A reference to the object.
''' True if the collection contains the object.
Public Function ContainsDeleted(ByVal Item As BusinessBase) As Boolean
Dim element As BusinessBase
For Each element In deletedList
If element.Equals(Item) Then
Return True
End If
Next
Return False
End Function
#End Region
#Region " IsDirty, IsValid "
'''
''' Returns True if this object's data has been changed.
'''
'''
'''
''' When an object's data is changed, CSLA .NET makes note of that change
''' and considers the object to be 'dirty' or changed. This value is used to
''' optimize data updates, since an unchanged object does not need to be
''' updated into the database. All new objects are considered dirty. All objects
''' marked for deletion are considered dirty.
'''
''' Once an object's data has been saved to the database (inserted or updated)
''' the dirty flag is cleared and the object is considered unchanged. Objects
''' newly loaded from the database are also considered unchanged.
'''
'''
''' If any child object within the collection is dirty then the collection
''' is considered to be dirty. If all child objects are unchanged, then the
''' collection is not dirty.
'''
'''
''' A value indicating if this object's data has been changed.
Public ReadOnly Property IsDirty() As Boolean
Get
' any deletions make us dirty
If deletedList.Count > 0 Then Return True
' run through all the child objects
' and if any are dirty then the
' collection is dirty
Dim Child As BusinessBase
For Each Child In list
If Child.IsDirty Then Return True
Next
Return False
End Get
End Property
'''
''' Returns True if the object is currently valid, False if the
''' object has broken rules or is otherwise invalid.
'''
'''
'''
''' By default this property relies on the underling
''' object to track whether any business rules are currently broken for this object.
'''
''' You can override this property to provide more sophisticated
''' implementations of the behavior. For instance, you should always override
''' this method if your object has child objects, since the validity of this object
''' is affected by the validity of all child objects.
'''
'''
''' If any child object within the collection is invalid then the collection
''' is considered to be invalid. If all child objects are valid, then the
''' collection is valid.
'''
'''
''' A value indicating if the object is currently valid.
Public ReadOnly Property IsValid() As Boolean
Get
' run through all the child objects
' and if any are invalid then the
' collection is invalid
Dim Child As BusinessBase
For Each Child In list
If Not Child.IsValid Then Return False
Next
Return True
End Get
End Property
#End Region
#Region " IsSavable "
'Added by JOHN, not in original
'''
''' Returns True if this object is both dirty and valid.
'''
'''
''' An object is considered dirty (changed) if
''' returns True. It is
''' considered valid if
''' returns True. The IsSavable property is
''' a combination of these two properties. It is provided specifically to
''' enable easy binding to a Save or OK button on a form so that button
''' can automatically enable/disable as the object's state changes between
''' being savable and not savable.
'''
''' A value indicating if this object is new.
Public Overridable ReadOnly Property IsSavable() As Boolean
Get
Return IsDirty AndAlso IsValid
End Get
End Property
#End Region
#Region " Begin/Cancel/ApplyEdit "
'''
''' Starts a nested edit on the object.
'''
'''
'''
''' When this method is called the object takes a snapshot of
''' its current state (the values of its variables). This snapshot
''' can be restored by calling
''' or committed by calling .
'''
''' This is a nested operation. Each call to BeginEdit adds a new
''' snapshot of the object's state to a stack. You should ensure that
''' for each call to BeginEdit there is a corresponding call to either
''' CancelEdit or ApplyEdit to remove that snapshot from the stack.
'''
''' See Chapters 2 and 4 for details on n-level undo and state stacking.
'''
''' This method triggers the copying of all child object states.
'''
'''
Public Sub BeginEdit()
If Me.IsChild Then
Throw New _
NotSupportedException("BeginEdit is not valid on a child object")
End If
CopyState()
End Sub
'''
''' Cancels the current edit process, restoring the object's state to
''' its previous values.
'''
'''
''' Calling this method causes the most recently taken snapshot of the
''' object's state to be restored. This resets the object's values
''' to the point of the last
''' call.
'''
''' This method triggers an undo in all child objects.
'''
'''
Public Sub CancelEdit()
If Me.IsChild Then
Throw New _
NotSupportedException("CancelEdit is not valid on a child object")
End If
UndoChanges()
End Sub
'''
''' Commits the current edit process.
'''
'''
''' Calling this method causes the most recently taken snapshot of the
''' object's state to be discarded, thus committing any changes made
''' to the object's state since the last
''' call.
'''
''' This method triggers an ApplyEdit in all child objects.
'''
'''
Public Sub ApplyEdit()
If Me.IsChild Then
Throw New _
NotSupportedException("ApplyEdit is not valid on a child object")
End If
AcceptChanges()
End Sub
#End Region
#Region " N-level undo "
Friend Sub CopyState()
Dim Child As BusinessBase
' we are going a level deeper in editing
mEditLevel += 1
' cascade the call to all child objects
For Each Child In list
Child.CopyState()
Next
' cascade the call to all deleted child objects
For Each Child In deletedList
Child.CopyState()
Next
End Sub
Friend Sub UndoChanges()
Dim Child As BusinessBase
Dim Index As Integer
' we are coming up one edit level
mEditLevel -= 1
If mEditLevel < 0 Then mEditLevel = 0
' Cancel edit on all current items
For Index = List.Count - 1 To 0 Step -1
Child = CType(list.Item(Index), BusinessBase)
Child.UndoChanges()
' if item is below its point of addition, remove
If Child.EditLevelAdded > mEditLevel Then list.Remove(Child)
Next
' cancel edit on all deleted items
For Index = deletedList.Count - 1 To 0 Step -1
Child = deletedList.Item(Index)
Child.UndoChanges()
' if item is below its point of addition, remove
If Child.EditLevelAdded > mEditLevel Then deletedList.Remove(Child)
' if item is no longer deleted move back to main list
If Not Child.IsDeleted Then UnDeleteChild(Child)
Next
End Sub
Friend Sub AcceptChanges()
Dim Child As BusinessBase
' we are coming up one edit level
mEditLevel -= 1
If mEditLevel < 0 Then mEditLevel = 0
' cascade the call to all child objects
For Each Child In list
Child.AcceptChanges()
' if item is below its point of addition, lower point of addition
If Child.EditLevelAdded > mEditLevel Then Child.EditLevelAdded = mEditLevel
Next
' cascade the call to all deleted child objects
For Each Child In deletedList
Child.AcceptChanges()
' if item is below its point of addition, lower point of addition
If Child.EditLevelAdded > mEditLevel Then Child.EditLevelAdded = mEditLevel
Next
End Sub
#End Region
#Region " Delete and Undelete child "
Private Sub DeleteChild(ByVal Child As BusinessBase)
' mark the object as deleted
Child.DeleteChild()
' and add it to the deleted collection for storage
deletedList.Add(Child)
End Sub
Private Sub UnDeleteChild(ByVal Child As BusinessBase)
' we are inserting an _existing_ object so
' we need to preserve the object's editleveladded value
' because it will be changed by the normal add process
Dim SaveLevel As Integer = Child.EditLevelAdded
list.Add(Child)
Child.EditLevelAdded = SaveLevel
' since the object is no longer deleted, remove it from
' the deleted collection
deletedList.Remove(Child)
End Sub
#End Region
#Region " DeletedCollection "
'''
''' A collection containing all child objects marked
''' for deletion.
'''
Protected deletedList As New DeletedCollection
'''
''' Defines a strongly-typed collection to store all
''' child objects marked for deletion.
'''
_
Protected Class DeletedCollection
Inherits CollectionBase
'''
''' Adds a child object to the collection.
'''
''' The child object to be added.
Public Sub Add(ByVal Child As BusinessBase)
list.Add(Child)
End Sub
'''
''' Removes a child object from the collection.
'''
''' The child object to be removed.
Public Sub Remove(ByVal Child As BusinessBase)
list.Remove(Child)
End Sub
'''
''' Returns a reference to a child object in the collection.
'''
''' The positional index of the item in the collection.
''' The specified child object.
Default Public ReadOnly Property Item(ByVal index As Integer) As BusinessBase
Get
Return CType(list.Item(index), BusinessBase)
End Get
End Property
End Class
#End Region
#Region " Insert, Remove, Clear "
'''
''' This method is called by a child object when it
''' wants to be removed from the collection.
'''
''' The child object to remove.
Friend Sub RemoveChild(ByVal child As BusinessBase)
list.Remove(child)
End Sub
'''
''' Sets the edit level of the child object as it is added.
'''
Protected Overrides Sub OnInsert(ByVal index As Integer, ByVal value As Object)
If Not ActivelySorting Then
' when an object is inserted we assume it is
' a new object and so the edit level when it was
' added must be set
CType(value, BusinessBase).EditLevelAdded = mEditLevel
CType(value, BusinessBase).SetParent(Me)
MyBase.OnInsert(index, value)
End If
End Sub
'''
''' Marks the child object for deletion and moves it to
''' the collection of deleted objects.
'''
Protected Overrides Sub OnRemove(ByVal index As Integer, ByVal value As Object)
If Not ActivelySorting Then
' when an object is 'removed' it is really
' being deleted, so do the deletion work
DeleteChild(CType(value, BusinessBase))
MyBase.OnRemove(index, value)
End If
End Sub
'''
''' Marks all child objects for deletion and moves them
''' to the collection of deleted objects.
'''
Protected Overrides Sub OnClear()
If Not ActivelySorting Then
' when an object is 'removed' it is really
' being deleted, so do the deletion work
' for all the objects in the list
While list.Count > 0
list.RemoveAt(0)
'DeleteChild(CType(list(0), BusinessBase))
End While
MyBase.OnClear()
End If
End Sub
#End Region
#Region " Edit level tracking "
' keep track of how many edit levels we have
Private mEditLevel As Integer
#End Region
#Region " IsChild "
Private mIsChild As Boolean = False
'''
''' Indicates whether this collection object is a child object.
'''
''' True if this is a child object.
Protected ReadOnly Property IsChild() As Boolean
Get
Return mIsChild
End Get
End Property
'''
''' Marks the object as being a child object.
'''
'''
'''
''' By default all business objects are 'parent' objects. This means
''' that they can be directly retrieved and updated into the database.
'''
''' We often also need child objects. These are objects which are contained
''' within other objects. For instance, a parent Invoice object will contain
''' child LineItem objects.
'''
''' To create a child object, the MarkAsChild method must be called as the
''' object is created. Please see Chapter 7 for details on the use of the
''' MarkAsChild method.
'''
'''
Protected Sub MarkAsChild()
mIsChild = True
End Sub
#End Region
#Region " Clone "
'''
''' Creates a clone of the object.
'''
''' A new object containing the exact data of the original object.
Public Function Clone() As Object Implements ICloneable.Clone
Dim buffer As New MemoryStream
Dim formatter As New BinaryFormatter
Serialization.SerializationNotification.OnSerializing(Me)
formatter.Serialize(buffer, Me)
Serialization.SerializationNotification.OnSerialized(Me)
buffer.Position = 0
Dim temp As Object = formatter.Deserialize(buffer)
Serialization.SerializationNotification.OnDeserialized(temp)
Return temp
End Function
#End Region
#Region " Data Access "
'''
''' Saves the object to the database.
'''
'''
'''
''' Calling this method starts the save operation, causing the all child
''' objects to be inserted, updated or deleted within the database based on the
''' each object's current state.
'''
''' All this is contingent on . If
''' this value is False, no data operation occurs. It is also contingent on
''' . If this value is False an
''' exception will be thrown to indicate that the UI attempted to save an
''' invalid object.
'''
''' It is important to note that this method returns a new version of the
''' business collection that contains any data updated during the save operation.
''' You MUST update all object references to use this new version of the
''' business collection in order to have access to the correct object data.
'''
''' You can override this method to add your own custom behaviors to the save
''' operation. For instance, you may add some security checks to make sure
''' the user can save the object. If all security checks pass, you would then
''' invoke the base Save method via MyBase.Save().
'''
'''
''' A new object containing the saved values.
Public Overridable Function Save() As BusinessCollectionBase
If Me.IsChild Then
Throw New NotSupportedException("Can not directly save a child object")
End If
If mEditLevel > 0 Then
Throw New Exception("Object is still being edited and can not be saved")
End If
If Not IsValid Then
Throw New Exception("Object is not valid and can not be saved")
End If
If IsDirty Then
Return CType(DataPortal.Update(Me), BusinessCollectionBase)
Else
Return Me
End If
End Function
'''
''' Override this method to load a new business object with default
''' values from the database.
'''
''' An object containing criteria values.
Protected Overridable Sub DataPortal_Create(ByVal Criteria As Object)
Throw New NotSupportedException("Invalid operation - create not allowed")
End Sub
'''
''' Override this method to allow retrieval of an existing business
''' object based on data in the database.
'''
''' An object containing criteria values to identify the object.
Protected Overridable Sub DataPortal_Fetch(ByVal Criteria As Object)
Throw New NotSupportedException("Invalid operation - fetch not allowed")
End Sub
'''
''' Override this method to allow insert, update or deletion of a business
''' object.
'''
Protected Overridable Sub DataPortal_Update()
Throw New NotSupportedException("Invalid operation - update not allowed")
End Sub
'''
''' Override this method to allow immediate deletion of a business object.
'''
''' An object containing criteria values to identify the object.
Protected Overridable Sub DataPortal_Delete(ByVal Criteria As Object)
Throw New NotSupportedException("Invalid operation - delete not allowed")
End Sub
'''
''' Returns the specified database connection string from the application
''' configuration file.
'''
'''
''' The database connection string must be in the appSettings section
''' of the application configuration file. The database name should be
''' prefixed with 'DB:'. For instance, DB:mydatabase.
'''
''' Name of the database.
''' A database connection string.
'Protected Function DB(ByVal DatabaseName As String) As String
' Return System.CXXXonfiguration.ConfigurationManager.AppSettings("DB:" & DatabaseName)
'End Function
#End Region
#Region " DumpState "
Friend Sub DumpState()
Dim Child As BusinessBase
Debug.WriteLine("BusinessCollectionBase!Count:" & list.Count)
Debug.WriteLine("BusinessCollectionBase!DeletedCount:" & deletedList.Count)
Debug.WriteLine("BusinessCollectionBase!mIsChild:" & mIsChild)
Debug.WriteLine("BusinessCollectionBase!mEditLevel:" & mEditLevel)
Debug.Indent()
For Each Child In list
Child.DumpState()
Next
Debug.Unindent()
End Sub
#End Region
#Region " ISerializationNotification "
'''
''' This method is called on a newly deserialized object
''' after deserialization is complete.
'''
Protected Overridable Sub Deserialized() _
Implements CSLA.Serialization.ISerializationNotification.Deserialized
Dim child As Serialization.ISerializationNotification
For Each child In list
child.Deserialized()
Next
For Each child In deletedList
child.Deserialized()
Next
End Sub
'''
''' This method is called on the original instance of the
''' object after it has been serialized.
'''
Protected Overridable Sub Serialized() _
Implements CSLA.Serialization.ISerializationNotification.Serialized
Dim child As Serialization.ISerializationNotification
For Each child In list
child.Serialized()
Next
For Each child In deletedList
child.Serialized()
Next
End Sub
'''
''' This method is called before an object is serialized.
'''
Protected Overridable Sub Serializing() _
Implements CSLA.Serialization.ISerializationNotification.Serializing
Dim child As Serialization.ISerializationNotification
For Each child In list
child.Serializing()
Next
For Each child In deletedList
child.Serializing()
Next
End Sub
#End Region
#Region "AyaNova related convenience items"
''Get the user object so
''we can check rights / get ID value
Public ReadOnly Property CurrentUserID() As Guid
Get
Dim CurrentUser As Security.BusinessPrincipal = CType(Thread.CurrentPrincipal, BusinessPrincipal)
Return CurrentUser.ID
End Get
End Property
'' Get security access right level from current identity
Public Function GetRight(ByVal RightName As String) As Int32
Return CType(Thread.CurrentPrincipal, BusinessPrincipal).Right(RightName)
End Function
#End Region
End Class