1. Trang chủ
  2. » Công Nghệ Thông Tin

Expert VB 2005 Business Objects Second Edition phần 7 pps

69 284 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 69
Dung lượng 1,06 MB

Nội dung

Friend Shared Function NewEditableChild() As EditableChild Return New EditableChild End Function Then the DataPortal_Create() method can be removed, since it won’t be used. The default constructor is then used to set any default values that are hard-coded into the class. Switchable Objects It’s possible that some classes must be instantiated as root objects on some occasions and as child objects on others. This can be handled by conditionally calling MarkAsChild(), based on how the object is being created. ■Note In most cases, the need for a switchable object indicates a flawed object model. While there are excep- tions for which this makes sense, you should carefully examine your object model to see if there’s a simpler solution before implementing a switchable object. Conditionally calling MarkAsChild() typically can’t be done in the default constructor, because there’s no way to determine whether the object is being created as a r oot or a child object at that point. Instead, you need to go back to your object’s life cycle to see where you can make this decision. In fact, since the default is for an object to be a root object, all you need to do is determine the paths by which a child object can be created, and make sure to call MarkAsChild() only in those cases. The template for creating a “switchable” object is the same as the editable root template, with the following exceptions: • Dual criteria objects • Dual create and fetch factory methods • Dual create and fetch data access methods Let’s discuss each change in turn. Dual Criteria Classes The object’s criteria must now include a flag to indicate whether the object is being created as a root or a child object (this is in addition to any object-specific criteria fields in this class). This can be done either by adding an actual flag field to the Criteria class or by creating a second criteria class. I pr efer the second appr oach as it makes the code simpler overall. Remember that for a child object, the criteria class is only used for the create operation, and so it typically doesn’t need any actual criteria data. The result is that there are two criteria classes; for example: <Serializable()> _ Private Class RootCriteria Private mId As Integer Public ReadOnly Property Id() As Integer Get Return mId End Get End Property CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 391 6315_c07_final.qxd 4/7/06 2:19 PM Page 391 Public Sub New(ByVal id As Integer) mId = id End Sub Public Sub New() End Sub End Class <Serializable()> _ Private Class ChildCriteria End Class These two classes will be used to differentiate the way the object should be created. Dual Factory Methods Instead of single factory methods to create and retrieve the object, there will be two methods for each operation: one Public, the other Friend. Public Shared Function NewSwitchable() As SwitchableObject Return DataPortal.Create(Of SwitchableObject)(New RootCriteria()) End Function Friend Shared Function NewSwitchableChild() As SwitchableObject Return DataPortal.Create(Of SwitchableObject)(New ChildCriteria()) End Function Public Shared Function GetSwitchableRoot( _ ByVal id As Integer) As SwitchableObject Return DataPortal.Create(Of SwitchableObject)(New RootCriteria(id)) End Function Friend Shared Function GetSwitchableChild( _ ByVal dr As SqlDataReader) As SwitchableObject Return New SwitchableObject(dr) End Function Notice how the NewSwitchable() methods are each designed. The Public version (used to cre- ate a root object) uses the RootCriteria object, while the Friend version (called by a parent object to create a child object) uses ChildCriteria. The DataPortal_Create() methods, which follow, are called based on the type of the cr iter ia object. The two GetSwitchable() methods ar e even more different. The Public one is called b y UI code to retrieve a root object. In this case, the data portal is called to retrieve the object based on the sup- plied criteria. The Friend one follows the pattern for child objects, accepting a data reader from the parent object and passing it along to a Private constructor, which in turn calls a Private Fetch() method. D ual D ata A ccess Methods The data access methods that handle create and fetch operations are different for a root and child object. Because of this, these methods are duplicated in a switchable object. In most cases, they can delegate to a shar ed implementation that is private to the class. For instance: CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES392 6315_c07_final.qxd 4/7/06 2:19 PM Page 392 Private Overloads Sub DataPortal_Create(ByVal criteria As RootCriteria) DoCreate() End Sub Private Overloads Sub DataPortal_Create(ByVal criteria As ChildCriteria) MarkAsChild() DoCreate() End Sub Private Sub DoCreate() ' load default values from database here End Sub Notice how the overload of DataPortal_Create() that accepts a ChildCriteria object calls MarkAsChild(), while the other does not. This ensures that the object is marked as a child object when appropriate. Similarly, the data-retrieval operations are duplicated: Private Overloads Sub DataPortal_Fetch(ByVal criteria As RootCriteria) ' TODO: create data reader to load values Using dr As SqlDataReader = Nothing DoFetch(dr) End Using End Sub Private Sub Fetch(ByVal dr As SqlDataReader) MarkAsChild() DoFetch(dr) End Sub Private Sub DoFetch(ByVal dr As SqlDataReader) ' TODO: load values End Sub If the object is being loaded from the UI, then it is treated as a root object and DataPortal_ Fetch() is called, passing in appropr iate criteria. This method opens the database, and sets up and executes a database command object to get back a data reader. That data reader is then passed to a central DoFetch() helper method to copy the data from the data reader into the object’s fields. On the other hand, if the object is being loaded from a parent object as a child, then its para- meterized constructor is called, which in turn calls the Fetch() method. This method calls MarkAsChild() to mar k the object as a child, and then the DoFetch() helper is called to cop y the data from the data reader into the object’s fields. O bject C reation Without Defaults When creating the object using the New keyword instead of calling DataPortal.Create(), the Friend factor y method can dir ectly call MarkAsChild(), as sho wn her e: Friend Shared Function NewSwitchableChild() As SwitchableObject Dim obj As New SwitchableObject obj.MarkAsChild() Return obj End Function From the parent object’s perspective, there’s no difference—it just calls the factory method; but this appr oach is faster because it doesn’t load default values from the database. CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 393 6315_c07_final.qxd 4/7/06 2:19 PM Page 393 Editable Root Collection At times, applications need to retrieve a collection of child objects directly. To do this, you need to create a root collection object. For instance, the application may have a Windows Forms UI consist- ing of a DataGridView control that displays a collection of Contact objects. If the root object is a collection of child Contact objects, the UI developer can simply bind the collection to the DataGridView, and the user can do in-place editing of the objects within the grid. This approach means that all the child objects are handled as a single unit in terms of data access. T hey are loaded into the collection to start with, so the user can interact with all of them, and then save them all at once when all edits are complete. This is only subtly different from having a regular root object that has a collection of child objects. Figure 7-10 shows the regular root object approach on the left and the collection root object approach on the right. This approach isn’t recommended when there are large numbers of potential child objects, because the retrieval pr ocess can become too slow, but it can be very useful in cases where you can specify criteria to limit the number of objects returned. To create an editable root collection object, use a template like this: <Serializable()> _ Public Class EditableRootList Inherits BusinessListBase(Of EditableRootList, EditableChild) #Region " Authorization Rules " Public Shared Function CanAddObject() As Boolean ' TODO: customize to check user role Return ApplicationContext.User.IsInRole("") End Function Public Shared Function CanGetObject() As Boolean ' TODO: customize to check user role Return ApplicationContext.User.IsInRole("") End Function Public Shared Function CanEditObject() As Boolean ' TODO: customize to check user role Return ApplicationContext.User.IsInRole("") End Function CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES394 Figure 7-10. Comparing simple root objects (left) and collection root objects (right) 6315_c07_final.qxd 4/7/06 2:19 PM Page 394 Public Shared Function CanDeleteObject() As Boolean ' TODO: customize to check user role Return ApplicationContext.User.IsInRole("") End Function #End Region # Region " Factory Methods " Public Shared Function NewEditableRootList() As EditableRootList Return New EditableRootList() End Function Public Shared Function GetEditableRootList(ByVal id As Integer) As EditableRootList Return DataPortal.Fetch(Of EditableRootList)(New Criteria(id)) End Function Private Sub New() ' require use of factory methods End Sub #End Region #Region " Data Access " <Serializable()> _ Private Class Criteria Private mId As Integer Public ReadOnly Property Id() As Integer Get Return mId End Get End Property Public Sub New(ByVal id As Integer) mId = id End Sub End Class Private Overloads Sub DataPortal_Fetch(ByVal criteria As Criteria) ' TODO: load values RaiseListChangedEvents = False Using dr As SqlDataReader = Nothing While dr.Read Add(EditableChild.GetEditableChild(dr)) End While End Using RaiseListChangedEvents = True End Sub Protected Overrides Sub DataPortal_Update() RaiseListChangedEvents = False For Each item As EditableChild In DeletedList item.DeleteSelf() Next DeletedList.Clear() CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 395 6315_c07_final.qxd 4/7/06 2:19 PM Page 395 For Each item As EditableChild In Me If item.IsNew Then item.Insert(Me) Else item.Update(Me) End If Next RaiseListChangedEvents = True End Sub #End Region End Class The Authorization Rules region contains the standard Shared methods discussed earlier for editable root objects. Since collection objects don’t have detailed properties, there’s no need or support for the AddAuthorizationRules() method. The Factory Methods region implements factory methods to create, retrieve, and (optionally) delete the collection. The create method simply uses the New keyword to create an instance of the collection. There’s no need to load default values for the collection itself. The retrieve and delete methods rely on the data portal to do much of the work, ultimately delegating the call to the appropriate DataPortal_XYZ method. In the Data Access region, the DataPortal_Fetch() method is responsible for getting the data from the database, typically via a data reader. It then calls the Shared factory method of the child class for each row in the data reader, thereby allowing each child object to load its data. The Shared factor y method in the child class calls its o wn Private constr uctor to actually load the data fr om the data reader. The DataPortal_Update() method must loop through all the child objects contained in the deleted object collection, calling each object’s DeleteSelf() method in turn. An alternative is to have the collection object dynamically generate a SQL statement to delete all the items in the DeleteList with a single call. The specific implementation is up to the business developer and may vary depending on the database design. Once the child objects have been deleted from the database, that list is cleared. Then the active child objects are either inserted or updated based on their IsNew property value. ■Note It’s critical that the deleted child objects be processed first. It’s quite possible for the user to delete a child object from the collection, and then add a new child object with the same primary key value. This means that the collection will have the original child object mar ked as deleted in the list of deleted child objects, and the new child object in the list of active objects. This new object will have its IsNew property set to True because it’s a new object. If the original child object isn’t deleted first, the insertion of the new child object will fail. Thus, the code first processes the list of deleted child objects, and then moves on to process the list of activ e child objects . B oth the DataPortal_Fetch() and DataPortal_Update() methods set the RaiseListChangedEvents property to False before changing the collection, and then restore it to True once the operation is complete. Setting this property to False tells the base BindingList(Of T) class to stop raising the ListChanged event. When doing batches of updates or changes to a collec- tion, this can increase performance. CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES396 6315_c07_final.qxd 4/7/06 2:19 PM Page 396 Editable Child Collection The most common type of collection is one that is contained within a parent object to manage a collection of child objects for that parent; like ProjectResources and ResourceAssignments in the sample application. ■Tip Note that the parent object here might be a root object, or it might be a child itself—child objects can be nested, if that’s what the business object model requires. In other words, this concept supports not only root-child, but also child-grandchild and grandchild-to-great-grandchild relationships. A child collection class inherits from BusinessListBase and calls MarkAsChild() during its cre- ation process to indicate that it’s operating in child mode. This also means that it won’t be directly retrieved or updated by the DataPortal, but instead will be retrieved or updated by its parent object: <Serializable()> _ Public Class EditableChildList Inherits BusinessListBase(Of EditableChildList, EditableChild) #Region " Factory Methods " Friend Shared Function NewEditableChildList() As EditableChildList Return New EditableChildList End Function Friend Shared Function GetEditableChildList( _ ByVal dr As SqlDataReader) As EditableChildList Return New EditableChildList(dr) End Function Private Sub New() MarkAsChild() End Sub Private Sub New(ByVal dr As SqlDataReader) MarkAsChild() Fetch(dr) End Sub #End Region #Region " Data Access " Private Sub Fetch(ByVal dr As SqlDataReader) RaiseListChangedEvents = False While dr.Read Add(EditableChild.GetEditableChild(dr)) End While RaiseListChangedEvents = True End Sub Friend Sub Update(ByVal parent As Object) CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 397 6315_c07_final.qxd 4/7/06 2:19 PM Page 397 RaiseListChangedEvents = False For Each item As EditableChild In DeletedList item.DeleteSelf() Next DeletedList.Clear() For Each item As EditableChild In Me If item.IsNew Then item.Insert(parent) Else item.Update(parent) End If Next RaiseListChangedEvents = True End Sub #End Region End Class As you can see, this code is very similar to a root collection in structure. The differences start with the factory methods. Since only a parent object can create or fetch an instance of this class, the Shared factory methods are scoped as Friend. The Shared method to create an object simply returns a new collection object. As with the EditableChild template, the constructor calls MarkAsChild() to indicate that this is a child object. Likewise, the Shared method to load the child collection with data creates a new collection object and then calls a parameterized constructor just like in the EditableChild template. That con- structor calls a Fetch() method to load the data. The Update() method is identical to the DataPortal_Update() method in the EditableRootList. It loops through the list of deleted child objects, calling their DeleteSelf() methods, and then loops through the active child objects , calling Insert() or Update() as appropriate . Notice, however, that the Update() method accepts a reference to the parent object as a param- eter, and this value is provided to the child objects’ Insert() and Update() methods. As discussed earlier, this allows the child objects to use data from the parent object as needed for things like for- eign key values and so forth. Read-Only Business Objects Sometimes, an application may need an object that provides data in a read-only fashion. For a read- only list of data, ther e ’s ReadOnlyListBase; but if the r equir ement is for a single object containing read-only data, it should inherit from ReadOnlyBase. This is one of the simplest types of object to create, since it does nothing more than retrieve and return data, as shown here: <Serializable()> _ Public Class ReadOnlyRoot Inherits ReadOnlyBase(Of ReadOnlyRoot) #Region " Business Methods " Private mId As Integer CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES398 6315_c07_final.qxd 4/7/06 2:19 PM Page 398 Public ReadOnly Property Id() As Integer Get CanReadProperty(True) Return mId End Get End Property Protected Overrides Function GetIdValue() As Object Return mId End Function #End Region #Region " Authorization Rules " Protected Overrides Sub AddAuthorizationRules() ' TODO: add authorization rules 'AuthorizationRules.AllowRead("", "") End Sub Public Shared Function CanGetObject() As Boolean ' TODO: customize to check user role 'Return ApplicationContext.User.IsInRole("") Return True End Function #End Region #Region " Factory Methods " Public Shared Function GetReadOnlyRoot(ByVal id As Integer) As ReadOnlyRoot Return DataPortal.Create(Of ReadOnlyRoot)(New Criteria(id)) End Function Private Sub New() ' require use of factory methods End Sub #End Region #Region " Data Access " <Serializable()> _ Private Class Criteria Private mId As Integer Public ReadOnly Property Id() As Integer Get Return mId End Get End Property Public Sub New(ByVal id As Integer) mId = id End Sub End Class CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 399 6315_c07_final.qxd 4/7/06 2:19 PM Page 399 Private Overloads Sub DataPortal_Fetch(ByVal criteria As Criteria) ' load values End Sub #End Region End Class Like other business objects, a read-only object will have instance fields that contain its data. I t will typically also have read-only properties or methods that allow client code to retrieve values. As long as they don’t change the state of the object, these may even be calculated values. Like editable objects, read-only objects must override the GetIdValue() method and provide a unique identifying value for the object. This value is used by the Equals(), GetHashCode(), and ToString() implementations in the ReadOnlyBase class. If those implementations are inadequate for your needs, you can override them and provide your own implementations. The AddAuthorizationRules() method only needs to add roles for read access, since no proper- ties should be implemented to allow altering of data. It also includes a CanGetObject() method so that the UI can enable or disable options based on that result. In the Factory Methods region, there’s just one factory method that retrieves the object by call- ing DataPortal.Fetch(). This means there’s also a Criteria class, which should be modified to contain the criteria data needed to select the correct object for retrieval. The Data Access region just contains DataPortal_Fetch(). Of course, there’s no need to support updating or deleting of a read-only object. Read-Only Collections of Objects Applications commonly retrieve read-only collections of objects. The CSLA .NET framework includes the ReadOnlyListBase class to help cr eate r ead-only collections. It throws an exception any time there’s an attempt to change which items are in the collection by adding or removing objects. ■Note The template shown here is for the most common scenario: a read-only root collection. You can adapt this to provide a read-only child collection if desired. However, there’s no way for the collection object to stop client code from interacting with the child objects themselves. Typically, the items in the collection will expose only read-only proper- ties and methods. If read-write objects are put into the collection, client code will be able to alter their data. A read-only collection only guarantees that objects can’t be added or removed from the collection. The child objects may be derived from ReadOnlyBase, but mor e often they will be simple objects that don’t inherit from any CSLA .NET base class. The only requirements for these child objects is that they are implemented with read-only properties and that they are marked as <Serializable()>. The code for a typical r ead-only collection object looks like this: <Serializable()> _ Public Class ReadOnlyList Inherits ReadOnlyListBase(Of ReadOnlyList, ReadOnlyChild) #Region " Authorization Rules " CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES400 6315_c07_final.qxd 4/7/06 2:19 PM Page 400 [...]... 405 6315_c 07_ final.qxd 4 /7/ 06 2:19 PM Page 406 6315_c08_final.qxd 4 /7/ 06 2:00 PM CHAPTER Page 4 07 8 sss Business Object Implementation T his chapter will implement the business objects designed in Chapter 6 by following the business object coding structures from Chapter 7 This chapter will illustrate how to write code to create business objects that enjoy all the features and capabilities built into the... object model By implementing these objects, you should get a good feel for the practical process of taking the class templates from Chapter 7 and applying them to the creation of real business classes 4 07 6315_c08_final.qxd 408 4 /7/ 06 2:00 PM Page 408 CHAPTER 8 s BUSINESS OBJECT IMPLEMENTATION Figure 8-1 ProjectTracker application classes Setting Up the Project Technically, business classes can be placed... Inherits BusinessBase(Of Project) 6315_c08_final.qxd 4 /7/ 06 2:00 PM Page 411 CHAPTER 8 s BUSINESS OBJECT IMPLEMENTATION The BusinessBase class requires one generic type parameter This is the type of the business object itself, and is used to provide strongly typed Save() and Clone() methods for the object as discussed in Chapter 3 The class will contain the standard code regions discussed in Chapter 7: • Business. .. almost all the code in the business objects will be business focused Each business class will largely consist of three areas: • UI-focused business properties and methods • Shared factory methods to support the class-in-charge model (as discussed in Chapter 1) • Data access methods (DataPortal_XYZ, as discussed in Chapter 4) The object model created in Chapter 6 includes editable objects and collections,... object is immediately useful for things like data binding, setting property values, or adding child objects Read-Only Properties The bulk of the code in the Business Methods region for most objects will be the properties Some objects may include complex methods implementing business logic, but virtually all objects include properties to allow the UI to view or update the object’s values The Id property... used within other business objects to execute code on the application server A primary example is when a normal editable business object wants to implement an Exists() command You’ll see an example of this concept in the Project and Resource objects in Chapter 8 If the UI is to directly use the object, the class will be Public, while if it is to be used within the context of another business object,... Visual Studio But to get the full advantages of mobile objects and the CSLA NET framework, they really must be placed in a Class Library project By putting the business classes in a DLL, it becomes possible for the business objects to be used by various different “front ends.” This is important, because Chapters 9 through 11 will use exactly the same business DLL to create Windows Forms, Web Forms, and... code in this method runs on the server and 403 6315_c 07_ final.qxd 404 4 /7/ 06 2:19 PM Page 404 CHAPTER 7 s USING THE CSLA NET BASE CLASSES can do any server-side work This might be something as simple as doing a quick database lookup, or it might be a complex server-side workflow The code in this method can create and interact with other business objects (all on the server of course) It can interact... implement common types of business objects and how to establish various object relationships For the complete code, please refer to the code download for this book, available at www.apress.com ProjectTracker Objects Chapter 6 covered the creation of an object model for the sample project-tracking application This object model, shown in Figure 8-1, includes some editable root business objects (Project and... Note The default IsValid and IsDirty properties must be enhanced for all objects that subclass BusinessBase and contain child objects A parent object is valid only if it is in a valid state and if all of its child objects are in a valid state Likewise, a parent object is dirty if its own data has been changed or if any of its child objects or collections have been changed To handle this properly, the . 7 ■ USING THE CSLA .NET BASE CLASSES 405 6315_c 07_ final.qxd 4 /7/ 06 2:19 PM Page 405 6315_c 07_ final.qxd 4 /7/ 06 2:19 PM Page 406 Business Object Implementation This chapter will implement the business. ApplicationContext.User.IsInRole("") End Function CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES394 Figure 7- 10. Comparing simple root objects (left) and collection root objects (right) 6315_c 07_ final.qxd 4 /7/ 06 2:19 PM Page 394 Public. Sub Friend Sub Update(ByVal parent As Object) CHAPTER 7 ■ USING THE CSLA .NET BASE CLASSES 3 97 6315_c 07_ final.qxd 4 /7/ 06 2:19 PM Page 3 97 RaiseListChangedEvents = False For Each item As EditableChild

Ngày đăng: 12/08/2014, 16:21

TỪ KHÓA LIÊN QUAN