<CompositeResultBinder> Element

Maps a set of scalar columns of a stored procedure result set to an arbitrary set return value of a member mapped with the <StoredProcedure/> element.

<Member name="member" [signature="parameterList"]>

        <StoredProcedure dbName="stored-procedure">

               <Result>

                       <CompositeResultBinderbinderFactory="factory">

                               (ScalarResultBinder-element|

                               PersistentResultBinder-element)*

                       </CompositeResultBinder>

               </Result>

        </StoredProcedure>
</Member>

 

factory: Name of a type implementing ICompositeResultBinderFactory.

ScalarResultBinder-element: inner scalar binding, passed as a parameter to the factory.

PersistentResultBinder-element: inner persistent binding, passed as a parameter to the factory.

Remarks

The factory creates a new binder which is a class for populating new objects into the result set. Genome already provides a generic array for binding to arrays (T[]): ArrayResultBinderFactory<T>. To bind to other types, you need to implement your own result binder and result binder factory.

The binders specified inside the <CompositeResultBinder/> element are passed as the innerBinders parameter to the factory (in the order that they are specified in the XML mapping).

Example

Populating to a set of scalar type array

The following method returns a set of pairs containing int identities:

public Set<int[]> GetIdentityPairs();

The result can be mapped by using the (already provided) binder factory for arrays, specifying ArrayResultBinderFactory<int>. Note that the angle brackets for specifying the generic parameter of int need to be quoted in the mapping file:

<Member name="GetIdentityPairs">

        <StoredProcedure name="GetIdentityPairs">

               <CompositeResultBinder

                       binderFactory="ArrayResultBinderFactory&lt;int&gt;">

                       <ScalarResultBinder targetType="int" columnIndex="0"/>

                       <ScalarResultBinder targetType="int" columnIndex="1"/>

               </CompositeResultBinder>

        </StoredProcedure>

</Member>

The mapping above assumes that the stored procedure returns int in columns 0 and 1.

Populating to a set of object array

The following method returns a set of object[] containing a scalar type and a persistent type:

public Set<object[]> GetProductStock();

The result can again be mapped by using the already provided binder factory for arrays, specifying ArrayResultBinderFactory[object]:

<Member name="GetProductStock">

        <StoredProcedure name="GetProductStock">

               <CompositeResultBinder

                       binderFactory="ArrayResultBinderFactory&lt;object&gt;">

                       <PersistentResultBinder targetType="Product">

                               <FieldBinder fieldName="Id" columnIndex="0"/>

                               <FieldBinder fieldName="Name" columnIndex="1"/>

                       </PersistentResultBinder>

                       <ScalarResultBinder targetType="int" columnIndex="2"/>

               </CompositeResultBinder>

        </StoredProcedure>

</Member>

Each element of the returned set contains an object[] holding a Product on [0] and an int value on [1].

Populating to a set of arbitrary transient types (implementing your binder factory and binder)

As in the previous example, the result of a stored procedure is populated into a set of Product items together with their current stock. While the stored procedure is the same one as used previously, the set of ProductInfo classes to populate into is specialised for this purpose:

public class ProductInfo

{

        public Product Product;

        public int Stock;

        public ProductInfo(Product p, int s)

        {

               Product = p;

               Stock = s;

        }

}

To populate to arbitrary types, you need to implement your own result binder:

[Serializable]

public class ProductInfoBinder : CompositeResultBinder

{

        public ProductInfoBinder(DataDomainSchema schema, params ExternalQueryResultBinder[] innerBinders) :

            base(schema.TypeOf(typeof(ProductInfo)), innerBinders)

        {

        }

        protected override object Populate(object[] innerValues)

        {

               return new ProductInfo((Product)innerValues[0], (int)innerValues[1])

        }

}

Please observe the following rules for implementing binder classes:

·    Binder classes must be serialisable.

·    Binder must derive from CompositeResultBinder.

·    Result binders’ constructors must call the base constructor with the type of the populated class as a parameter.

·    Binders must override the populate method for constructing the object to be populated.

Next, you need to implement a result binder factory to create a new instance of the result binder, using the parameters of the mapping file that specify sub-binders:

public class ProductInfoBinderFactory : ICompositeResultBinderFactory

{

        public CompositeResultBinder Create(DataDomainSchema schema,

               ExternalQueryResultBinder[] innerBinders)

        {

               return new ProductInfoBinder(schema, innerBinders);

        }

}

The factory must have a default constructor.

Note: you can also create a specialised factory for complex result binding structures, where the user does not need to repeat result binding in the mapping file anymore. This factory can then configure the desired result binding structure in code and pass it with the innerBinders parameter to the result binder class created.

After implementing the binder and the binder factory, you can map the result of the stored procedure by using the new binder factory:

<Member name="GetProductStock">

        <StoredProcedure name="GetProductStock">

               <CompositeResultBinder

                       binderFactory="ProductInfoBinderFactory">

                       <PersistentResultBinder targetType="Product">

                               <FieldBinder fieldName="Id" columnIndex="0"/>

                               <FieldBinder fieldName="Name" columnIndex="1"/>

                       </PersistentResultBinder>

                       <ScalarResultBinder targetType="int" columnIndex="2"/>

               </CompositeResultBinder>

        </StoredProcedure>

</Member>

Each element of the returned set now contains a ProductInfo object. Note that the only change in the mapping file is the definition of the binder factory to be used.

Requirements

Editions:Professional, Evaluation, Express

Database Platforms:Microsoft SQL Server 2000, Microsoft SQL Server 2005, Oracle 9i Release 2, Oracle 10g Release 2

See also

<StoredProcedure/> element, <ScalarResultbinder/> element, <PersistentResultBinder/> element



<PersistentResultBinder> Element