Skip to content

Reflection.ObjectFactory

Igor Tkachev edited this page May 20, 2016 · 1 revision

Home / Reflection

The following example shows how to create objects of different types coming from the same data source.

Typically, to create an object, BLToolkit calls the TypeAccessor.CreateInstanceEx method. First of all, this method verifies if there is an object factory (ObjectFactory property) associated with the creating object’s type. If the property value is not null, it is used to create an object.

The ObjectFactory property can be assigned explicitly at any time or by decorating the target class with the ObjectFactory attribute.

ObjectFactory.cs

using System;
using System.Collections.Generic;

using NUnit.Framework;

using BLToolkit.Data;
using BLToolkit.Mapping;
using BLToolkit.Reflection;

namespace HowTo.Reflection
{
    [TestFixture]
    public class ObjectFactoryTest
    {
        [ObjectFactory(typeof(Person.ObjectFactory))]
        public class Person
        {
            [MapField("PersonID")]
            public int    ID;

            public string LastName;
            public string FirstName;
            public string MiddleName;

            class ObjectFactory : IObjectFactory
            {
                public object CreateInstance(TypeAccessor typeAccessor, InitContext context)
                {
                    // Get the object type indicator field.
                    //
                    object objectType = context.DataSource.GetValue(context.SourceObject, "PersonType");

                    // Target ObjectMapper must be changed in order to provide correct mapping.
                    //
                    switch ((string)objectType)
                    {
                        case "D": context.ObjectMapper = ObjectMapper<Doctor>. Instance; break;
                        case "P": context.ObjectMapper = ObjectMapper<Patient>.Instance; break;
                    }

                    // Create an object instance.
                    // Do not call ObjectMapper.CreateInstance as it will lead to infinite recursion.
                    //
                    return context.ObjectMapper.TypeAccessor.CreateInstance(context);
                }
            }
        }

        public class Doctor : Person
        {
            public string Taxonomy;
        }

        public class Patient : Person
        {
            public string Diagnosis;
        }

        [Test]
        public void Test()
        {
            using (DbManager db = new DbManager())
            {
                List<Person> list = db
                    .SetCommand(@"
                        SELECT
                            ps.*,
                            d.Taxonomy,
                            p.Diagnosis,
                            CASE
                                WHEN d.PersonID IS NOT NULL THEN 'D'
                                WHEN p.PersonID IS NOT NULL THEN 'P'
                            END as PersonType
                        FROM
                            Person ps
                                LEFT JOIN Doctor  d ON d.PersonID = ps.PersonID
                                LEFT JOIN Patient p ON p.PersonID = ps.PersonID
                        ORDER BY
                            ps.PersonID")
                    .ExecuteList<Person>();

                Assert.AreEqual(list[0].GetType(), typeof(Doctor));
                Assert.AreEqual(list[1].GetType(), typeof(Patient));

                if (list.Count > 2)
                    Assert.AreEqual(list[2].GetType(), typeof(Person));
            }
        }
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
        <add
            name             = "DemoConnection"
            connectionString = "Server=.;Database=BLToolkitData;Integrated Security=SSPI"
            providerName     = "System.Data.SqlClient" />
    </connectionStrings>
</configuration>

CreateSql

Clone this wiki locally