locked
About the Term "ChildCallbacks" and Explanation of a Function RRS feed

  • Question

  • User-234026806 posted

    Hi There;

    I am reading the book ".NET Domain-Driven Design" written by Tim McCarty,  and I cannot understand the code below. Could you please explain? 

    First of all, Company class shall be known: 

     public class Company : EntityBase
        {
            private string name;
            private string abbreviation;
            private Address headquartersAddress;
            private List<Address> addresses;
            private string phoneNumber;
            private string faxNumber;
            private string url;
            private string remarks;
    
            public Company()
                : this(null)
            {
            }
    
            public Company(object key)
                : base(key)
            {
                this.name = string.Empty;
                this.abbreviation = string.Empty;
                this.headquartersAddress = null;
                this.addresses = new List<Address>();
                this.phoneNumber = string.Empty;
                this.faxNumber = string.Empty;
                this.url = string.Empty;
                this.remarks = string.Empty;
            }
    
            public string Name
            {
                get { return this.name; }
                set { this.name = value; }
            }
    
            public string Abbreviation
            {
                get { return this.abbreviation; }
                set { this.abbreviation = value; }
            }
    
            public Address HeadquartersAddress
            {
                get { return this.headquartersAddress; }
                set 
                {
                    if (this.headquartersAddress != value)
                    {
                        this.headquartersAddress = value;
                        if (!this.addresses.Contains(value))
                        {
                            this.addresses.Add(value);
                        }
                    }
                }
            }
    
            public IList<Address> Addresses
            {
                get { return this.addresses; }
            }
    
            public string PhoneNumber
            {
                get { return this.phoneNumber; }
                set { this.phoneNumber = value; }
            }
    
            public string FaxNumber
            {
                get { return this.faxNumber; }
                set { this.faxNumber = value; }
            }
    
            public string Url
            {
                get { return this.url; }
                set { this.url = value; }
            }
    
            public string Remarks
            {
                get { return this.remarks; }
                set { this.remarks = value; }
            }
        }

    Here is the SqlCeRepositoryBase class that has been used in the Contact Repository class:

        public abstract class SqlCeRepositoryBase<T> : RepositoryBase<T> 
            where T : EntityBase
        {
            #region AppendChildData Delegate
    
            /// <summary>
            /// The delegate signature required for callback methods
            /// </summary>
            /// <param name="entityAggregate"></param>
            /// <param name="childEntityKey"></param>
            public delegate void AppendChildData(T entityAggregate, 
                object childEntityKeyValue);
    
            #endregion
    
            #region Private Fields
    
            private Database database;
            private IEntityFactory<T> entityFactory;
            private Dictionary<string, AppendChildData> childCallbacks;
            private string baseQuery;
            private string baseWhereClause;
    
            #endregion
    
            #region Constructors
    
            protected SqlCeRepositoryBase() 
                : this(null)
            {
            }
    
            protected SqlCeRepositoryBase(IUnitOfWork unitOfWork) 
                : base(unitOfWork)
            {
                this.database = DatabaseFactory.CreateDatabase();
                this.entityFactory = EntityFactoryBuilder.BuildFactory<T>();
                this.childCallbacks = new Dictionary<string, AppendChildData>();
                this.BuildChildCallbacks();
                this.baseQuery = this.GetBaseQuery();
                this.baseWhereClause = this.GetBaseWhereClause();
            }
    
            #endregion
    
            #region Abstract Methods
    
            protected abstract string GetBaseQuery();
            protected abstract string GetBaseWhereClause();
            protected abstract void BuildChildCallbacks();
            protected abstract override void PersistNewItem(T item);
            protected abstract override void PersistUpdatedItem(T item);
            protected abstract override void PersistDeletedItem(T item);
    
            #endregion
    
            #region Properties
    
            protected Database Database
            {
                get { return this.database; }
            }
    
            protected Dictionary<string, AppendChildData> ChildCallbacks
            {
                get { return this.childCallbacks; }
            }
    
            protected string BaseQuery
            {
                get { return this.baseQuery; }
            }
    
            #endregion
    
            #region Public Methods
    
            public override IList<T> FindAll()
            {
                StringBuilder builder = new StringBuilder(50);
                builder.Append(this.baseQuery);
                builder.Append(";");
                return this.BuildEntitiesFromSql(builder.ToString());
            }
    
            public override T FindBy(object key)
            {
                StringBuilder builder = this.GetBaseQueryBuilder();
                builder.Append(this.BuildBaseWhereClause(key));
                return this.BuildEntityFromSql(builder.ToString());
            }
    
            #endregion
    
            #region Protected Methods
    
            protected IDataReader ExecuteReader(string sql)
            {
                DbCommand command = this.database.GetSqlStringCommand(sql);
                return this.database.ExecuteReader(command);
            }
    
            protected virtual T BuildEntityFromSql(string sql)
            {
                T entity = default(T);
                using (IDataReader reader = this.ExecuteReader(sql))
                {
                    if (reader.Read())
                    {
                        entity = this.BuildEntityFromReader(reader);
                    }
                }
                return entity;
            }
    
            protected virtual T BuildEntityFromReader(IDataReader reader)
            {
                T entity = this.entityFactory.BuildEntity(reader);
                if (this.childCallbacks != null && this.childCallbacks.Count > 0)
                {
                    object childKeyValue = null;
                    DataTable columnData = reader.GetSchemaTable();
                    foreach (string childKeyName in this.childCallbacks.Keys)
                    {
                        if (DataHelper.ReaderContainsColumnName(columnData,
                            childKeyName))
                        {
                            childKeyValue = reader[childKeyName];
                        }
                        else
                        {
                            childKeyValue = null;
                        }
                        this.childCallbacks[childKeyName](entity, childKeyValue);
                    }
                }
                return entity;
            }
    
            protected virtual List<T> BuildEntitiesFromSql(string sql)
            {
                List<T> entities = new List<T>();
                using (IDataReader reader = this.ExecuteReader(sql))
                {
                    while (reader.Read())
                    {
                        entities.Add(this.BuildEntityFromReader(reader));
                    }
                }
                return entities;
            }
    
            protected virtual string BuildBaseWhereClause(object key)
            {
                return string.Format(this.baseWhereClause, key);
            }
    
            protected virtual StringBuilder GetBaseQueryBuilder()
            {
                StringBuilder builder = new StringBuilder(50);
                builder.Append(this.baseQuery);
                return builder;
            }
    
            #endregion
        }

    Here is the ContactRepository class 

       public class CompanyRepository : SqlCeRepositoryBase<Company>, ICompanyRepository
        {
            #region Private Fields
    
            #endregion
    
            #region Public Constructors
    
            public CompanyRepository()
                : this(null)
            {
            }
    
            public CompanyRepository(IUnitOfWork unitOfWork) 
                : base(unitOfWork)
            {
            }
    
            #endregion
    
            #region BuildChildCallbacks
    
            protected override void BuildChildCallbacks()
            {
                this.ChildCallbacks.Add("addresses",
                delegate(Company company, object childKeyName)
                {
                    this.AppendAddresses(company);
                });
            }
    
            #endregion
    
            #region GetBaseQuery
    
            protected override string GetBaseQuery()
            {
                return "SELECT * FROM Company";
            }
    
            #endregion
    
            #region GetBaseWhereClause
    
            protected override string GetBaseWhereClause()
            {
                return " WHERE CompanyID = '{0}';";
            }
    
            #endregion
    
            #region Unit of Work Implementation
    
            protected override void PersistNewItem(Company item)
            {
                StringBuilder builder = new StringBuilder(100);
                builder.Append(string.Format("INSERT INTO Company ({0},{1},{2},{3},{4},{5},{6}) ",
                    CompanyFactory.FieldNames.CompanyId,
                    CompanyFactory.FieldNames.CompanyName,
                    CompanyFactory.FieldNames.CompanyShortName,
                    CompanyFactory.FieldNames.Phone,
                    CompanyFactory.FieldNames.Fax,
                    CompanyFactory.FieldNames.Url,
                    CompanyFactory.FieldNames.Remarks));
                builder.Append(string.Format("VALUES ({0},{1},{2},{3},{4},{5},{6});",
                    DataHelper.GetSqlValue(item.Key),
                    DataHelper.GetSqlValue(item.Name),
                    DataHelper.GetSqlValue(item.Abbreviation),
                    DataHelper.GetSqlValue(item.PhoneNumber),
                    DataHelper.GetSqlValue(item.FaxNumber),
                    DataHelper.GetSqlValue(item.Url),
                    DataHelper.GetSqlValue(item.Remarks)));
    
                this.Database.ExecuteNonQuery(
                    this.Database.GetSqlStringCommand(builder.ToString()));
    
                // Now do the addresses
                this.InsertAddresses(item);
            }
    
            protected override void PersistUpdatedItem(Company item)
            {
                StringBuilder builder = new StringBuilder(100);
                builder.Append("UPDATE Company SET ");
    
                builder.Append(string.Format("{0} = {1}",
                    CompanyFactory.FieldNames.CompanyName,
                    DataHelper.GetSqlValue(item.Name)));
    
                builder.Append(string.Format(",{0} = {1}",
                    CompanyFactory.FieldNames.CompanyShortName,
                    DataHelper.GetSqlValue(item.Abbreviation)));
    
                builder.Append(string.Format(",{0} = {1}",
                    CompanyFactory.FieldNames.Phone,
                    DataHelper.GetSqlValue(item.PhoneNumber)));
    
                builder.Append(string.Format(",{0} = {1}",
                    CompanyFactory.FieldNames.Fax,
                    DataHelper.GetSqlValue(item.FaxNumber)));
    
                builder.Append(string.Format(",{0} = {1}",
                    CompanyFactory.FieldNames.Url,
                    DataHelper.GetSqlValue(item.Url)));
    
                builder.Append(string.Format(",{0} = {1}",
                    CompanyFactory.FieldNames.Remarks,
                    DataHelper.GetSqlValue(item.Remarks)));
    
                builder.Append(" ");
                builder.Append(this.BuildBaseWhereClause(item.Key));
    
                this.Database.ExecuteNonQuery(
                    this.Database.GetSqlStringCommand(builder.ToString()));
    
                // Now do the addresses
    
                // First, delete the existing ones
                this.DeleteAddresses(item);
    
                // Now, add the current ones
                this.InsertAddresses(item);
            }
    
            protected override void PersistDeletedItem(Company item)
            {
                // Delete the company addresses first
                this.DeleteAddresses(item);
    
                // Now delete the company
                string query = string.Format("DELETE FROM Company {0}",
                    this.BuildBaseWhereClause(item.Key));
                this.Database.ExecuteNonQuery(
                    this.Database.GetSqlStringCommand(query));
            }
    
            #endregion
    
            #region Private Callback and Helper Methods
    
            private void DeleteAddresses(Company company)
            {
                string query = string.Format("DELETE FROM CompanyAddress {0}",
                    this.BuildBaseWhereClause(company.Key));
                this.Database.ExecuteNonQuery(
                    this.Database.GetSqlStringCommand(query));
            }
    
            private void InsertAddresses(Company company)
            {
                foreach (Address address in company.Addresses)
                {
                    this.InsertAddress(address, company.Key, 
                        (company.HeadquartersAddress == address));
                }
            }
    
            private void InsertAddress(Address address, object key, 
                bool isHeadquartersAddress)
            {
                StringBuilder builder = new StringBuilder(100);
                builder.Append(string.Format("INSERT INTO CompanyAddress ({0},{1},{2},{3},{4},{5}) ",
                    CompanyFactory.FieldNames.CompanyId,
                    AddressFactory.FieldNames.Street,
                    AddressFactory.FieldNames.City,
                    AddressFactory.FieldNames.State,
                    AddressFactory.FieldNames.PostalCode,
                    CompanyFactory.FieldNames.IsHeadquarters));
                builder.Append(string.Format("VALUES ({0},{1},{2},{3},{4},{5});",
                    DataHelper.GetSqlValue(key),
                    DataHelper.GetSqlValue(address.Street),
                    DataHelper.GetSqlValue(address.City),
                    DataHelper.GetSqlValue(address.State),
                    DataHelper.GetSqlValue(address.PostalCode),
                    DataHelper.GetSqlValue(isHeadquartersAddress)));
    
                this.Database.ExecuteNonQuery(
                    this.Database.GetSqlStringCommand(builder.ToString()));
            }
    
            private void AppendAddresses(Company company)
            {
                string sql = string.Format
                    ("SELECT * FROM CompanyAddress WHERE CompanyID = '{0}'", 
                    company.Key);
                using (IDataReader reader = this.ExecuteReader(sql))
                {
                    Address address = null;
                    while (reader.Read())
                    {
                        address = AddressFactory.BuildAddress(reader);
                        company.Addresses.Add(address);
                        if (CompanyFactory.IsHeadquartersAddress(reader))
                        {
                            company.HeadquartersAddress = address;
                        }
                    }
                }
            }
    
            #endregion
        }

    The function that I cannot understand is BuildChildCallbacks function at the CompanyRepository class. What is its purpose? Especially  I wonder the purpose of delegate action.

    Thanks in advance. 

    Sunday, July 15, 2018 6:07 PM

All replies

  • User-330142929 posted

    Hi Varoulscuprens,

    First, I am also a beginner. I have not read this book. This is just my personal thought and is for reference only.

    Here the BuildChildCallbacks method allows each subclass object that inherits from SqlCeRepositoryBase<Company> to access each other. The parent class SqlRepositoryBase<Company> adds a linked list pointer for each subclass object, which is stored in its field, and then each subclass can access the parent class through this pointer, and the parent class object can also access the subclass method. In addition, It is also implemented that subclass objects can access each other.

    Feel Free to let me know if you have any questions.

    Best Regards

    Abraham

    Monday, July 16, 2018 3:39 PM