vendredi 10 juin 2016

How would you model a tree structure and why? [on hold]

I have a tree hierarchy Eg. Community > Building > Floor > Apartment > .. in a relational database where starting from left to right, they have one to many relationship.

Now, I want to be able to copy any level of the hierarchy to another (matching)node in the tree and I have come up with two approaches and would appreciate any feedback on the advantages/disadvantages of each.

Approach # 1

public abstract class GenericItem
{
    public int ItemID { get; set; }
    public abstract int ItemType { get; }
    public string ItemName { get; set; }
    public string LocationPath { get; set; }
    public GenericItem Parent { get; set; }

    private SqlConnection _DBConn;
    public SqlConnection DBConn
    {
        get
        {
            if (_DBConn.IsNull())
                _DBConn = Parent.DBConn;

            return _DBConn;
        }
        set
        {
            _DBConn = value;
        }
    }

    private IEnumerable<GenericItem> _Children;
    public IEnumerable<GenericItem> Children
    {
        get
        {
            return _Children.IfNull(GetChildren());
        }
    }


    /// <summary>
    /// Creates a deep copy of itself and the children recursively
    /// </summary>
    protected void DeepCopyToParent(GenericItem newParent)
    {
        // Get a reference to the copy of this item, to which all the children will be copied to
        var copyParent = CopyMeToParent(newParent);
        foreach (var child in Children)
        {
            child.DeepCopyToParent(newParent);
        }
    }

    /// <summary>
    /// Copies this object and/or its descendants
    /// </summary>
    /// <param name="copyTarget">A GenericItem where this object needs to be copied. It can be either the of the same ItemType as the object or its parent type</param>
    /// <param name="deepCopy">Specifies whether to copy the entire hierarchy or just this object</param>
    public void CopyTo(GenericItem copyTarget)
    {
        // Only accept the item type or parent item type

        // Make sure that the hierarchy is copied in its entirety
        using (var tranScope = new TransactionScope())
        {
            DeepCopyToParent(copyTarget);

            tranScope.Complete();
        }
    }

    /// <summary>
    /// Gets all the immediate descendants of the current item
    /// </summary>
    /// <returns></returns>
    protected abstract IEnumerable<GenericItem> GetChildren();
    public abstract IEnumerable<GenericItem> GetSiblings();
    public abstract IEnumerable<GenericItem> GetSiblingsAndCousins();
    /// <summary>
    /// Copies only this object to the supplied parent object
    /// </summary>
    /// <param name="newParent"></param>
    /// <returns></returns>
    protected abstract GenericItem CopyMeToParent(GenericItem newParent);
}

public class Community : GenericItem
{
    public override int ItemType
    {
        get
        {
            return 1;
        }
    }

    public override IEnumerable<GenericItem> GetSiblings()
    {
        // Query the database and return the results
    }

    public override IEnumerable<GenericItem> GetSiblingsAndCousins()
    {
        // Query the database and return the results
    }

    protected override GenericItem CopyMeToParent(GenericItem newParent)
    {
        // Query the database and return the results
    }

    protected override IEnumerable<GenericItem> GetChildren()
    {
        // Query the database and return the results
    }
}

Approach # 2

public class GenericItem
{
    public int ItemID { get; set; }
    public abstract int ItemType { get; }
    public string ItemName { get; set; }
    public string LocationPath { get; set; }
    public GenericItem Parent { get; set; }

    private SqlConnection _DBConn;
    public SqlConnection DBConn
    {
        get
        {
            if (_DBConn.IsNull())
                _DBConn = Parent.DBConn;

            return _DBConn;
        }
        set
        {
            _DBConn = value;
        }
    }

    private IEnumerable<GenericItem> _Children;
    public IEnumerable<GenericItem> Children
    {
        get
        {
            return _Children.IfNull(GetChildren());
        }
    }


    /// <summary>
    /// Creates a deep copy of itself and the children recursively
    /// </summary>
    protected void DeepCopyToParent(GenericItem newParent)
    {
        // Get a reference to the copy of this item, to which all the children will be copied to
        var copyParent = CopyMeToParent(newParent);
        foreach (var child in Children)
        {
            child.DeepCopyToParent(newParent);
        }
    }

    /// <summary>
    /// Copies this object and/or its descendants
    /// </summary>
    /// <param name="copyTarget">A GenericItem where this object needs to be copied. It can be either the of the same ItemType as the object or its parent type</param>
    /// <param name="deepCopy">Specifies whether to copy the entire hierarchy or just this object</param>
    public void CopyTo(GenericItem copyTarget)
    {
        // Only accept the item type or parent item type

        // Make sure that the hierarchy is copied in its entirety
        using (var tranScope = new TransactionScope())
        {
            DeepCopyToParent(copyTarget);

            tranScope.Complete();
        }
    }

    /// <summary>
    /// Gets all the immediate descendants of the current item
    /// </summary>
    /// <returns></returns>
    protected abstract IEnumerable<GenericItem> GetChildren()
    {
        // Query a stored procedure which returns different items based on supplied parameters
    }
    public abstract IEnumerable<GenericItem> GetSiblings()
    {
        // Query a stored procedure which returns different items based on supplied parameters
    }
    public abstract IEnumerable<GenericItem> GetSiblingsAndCousins()
    {
        // Query a stored procedure which returns different items based on supplied parameters
    }
    /// <summary>
    /// Copies only this object to the supplied parent object
    /// </summary>
    /// <param name="newParent"></param>
    /// <returns></returns>
    protected abstract GenericItem CopyMeToParent(GenericItem newParent)
    {
        // A generic stored procedure which copies different item types
    }
}

My arguments for each: With the first approach(Composite Design Pattern), I get the flexibility of further extension, but also, if my hierarchy increases in depth with new type, I will have a lot of classes.

With the second approach, I just have to keep adding to the generic stored procs without worrying about refactoring C# code in multiple places, however, I lose the flexibility.

Please provide reasons for choosing one over the other and if you think both of these are bad implementations, feel free to do so.

Aucun commentaire:

Enregistrer un commentaire