OOP数据结构表示由两个外键索引的表

时间:2012-08-28 20:26:50

标签: c# wpf oop .net-4.0

我的任务是将“表驱动”程序转换为面向对象程序。过去所做的一切都是通过在内存中创建大型表,添加和删除行和列以及将所有内容解析为字符串来完成的。这太可怕了。这些表直接反映了存储所有内容的底层数据库的结构。

对于这个问题,我有Layer个对象,有大约100个属性,我有Event个对象,还有大约20个属性。然后,我为每个Layer/Event对设置了大约10个计算值。这些存储为第三个表,外键指向其他每个表。

我想创建一个适当的面向对象的类来存储这些数据,并像在字典中那样快速访问值。

我的第一个想法是将结果索引到字典中,但我觉得它的用法不直观:

struct EventLayerResult { Decimal sum = 0; Long events = 0; Decimal average; ...}
//Performing Calculations
Dictionary<Tuple<Event,Layer>, EventLayerResult> _EventLayerResults ...;
foreach(Event evt in _Events)
    foreach(Layer lyr in _Layers)
        EventLayerResult elr = newLayerLosses[Tuple.Create(evt, lyr)];
        elr.sum += currentValue;
        elr.events += 1;
        elr.average += elr.Sum/elr.Events;
        etc...
//Using results
EventLayerResult temp = _EventLayerResults.TryGetValue(Tuple.Create(evt, lyr))
someLoss = temp == null ? 0 : temp.expectedLoss;

我不喜欢每次创建值时都必须调用Tuple.Create或创建临时对象的新实例。此外,与表不同,如果我想在UI中绑定此表,我不能只绑定到Field =“Layer”,Field =“Event”,Field =“Loss”等,我必须想出来提取Key.LayerKey.EventValue.Loss等的复杂绑定表达式。出于这个原因,我想避免这样的数据结构。

我可以将它包装在一个对象中,这个对象可以让我轻松查找Event / Layer组合的每个值,但我不相信我应该为每个计算属性创建一个'get'方法,以便我可以使用它像这样:

thisSum = _EventLayerResults.getSum(evt, lyr);
thisEvent = _EventLayerResults.getExpectedLoss(evt, lyr);

我还认为绑定到这种结构中包含的完整结果列表是不可能的。

我最后的想法(我认为最接近我必须使用的解决方案)是一个简单的对象/结构集合,其中包含我需要引用的所有字段:

class EventLayerResult { Event oevent; Layer layer; Decimal sum; Long events...}
ObservableCollection<EventLayerResult> _EventLayerResults = ....
_EventLayerResults.Add( new EventLayerResult(){ oevent = evt, layer = lyr } );

这很容易绑定,但问题是这个集合没有“索引”。我正在寻找O(Nevts * Nlyrs)的时间来查找特定的事件/图层结果,除非我开始添加所有这些额外的行李,如自定义包装类,监视集合添加事件并索引集合项目在字典中等等。

我无法想象其他人每次想要将由两个外键索引的简单表转换为对象模型时都会经历所有这些。是否有一种我不知道的标准方法或数据结构可以使这种数据集易于使用?

1 个答案:

答案 0 :(得分:0)

到目前为止,我提出的最佳解决方案是使用字典包装外键上的Collection和index,就像我在OP中建议的那样。看起来好像很多工作:

public class EventGroupIDLayerTuple : Tuple<Int32, Layer>
{
    public EventGroupIDLayerTuple(Int32 EventGroupID, Layer Layer) : base(EventGroupID, Layer) { }
    public Int32 EventGroupID { get { return this.Item1; } }
    public Layer Layer { get { return this.Item2; } }
}
public class EventGroupLayerResult
{
    public Int32 EventGroupID { get; set; }
    public Layer Layer { get; set; }
    //Computed Values
    public Decimal Sum { get; set; }
    public Decimal Average { get; set; }
    //...
}

/// <summary>ObservableCollection of computed EventGroup/Layer results that are also indexed
/// in a dictionary for rapid retrieval.</summary>
public class EventGroupLayerResultCollection : ObservableCollection<EventGroupLayerResult>
{
    Dictionary<EventGroupIDLayerTuple, EventGroupLayerResult> _Index = 
        new Dictionary<EventGroupIDLayerTuple,EventGroupLayerResult>();

    public EventGroupLayerResultCollection() : base() { }

    /// <summary>Will return the result for the specified eventGroupID/Layer
    /// combination, or create a new result and return it.</summary>
    public EventGroupLayerResult this[Int32 eventGroupID, Layer layer]
    {
        get
        {
            EventGroupLayerResult retval;
            if( !_Index.TryGetValue(new EventGroupIDLayerTuple(eventGroupID, layer), out retval) )
            {
                retval = new EventGroupLayerResult() { EventGroupID = eventGroupID, Layer = layer };
                this.Add(retval);
            }
            return retval;
        }
    }

    public bool Contains(Int32 eventGroupID, Layer layer)
    {
        return _Index.ContainsKey(new EventGroupIDLayerTuple(eventGroupID, layer));
    }

    #region Index Maintenance
    protected override void ClearItems()
    {
        _Index.Clear();
        base.ClearItems();
    }
    protected override void InsertItem(int index, EventGroupLayerResult item)
    {
        _Index.Add(new EventGroupIDLayerTuple(item.EventGroupID, item.Layer), item);
        base.InsertItem(index, item);
    }
    protected override void RemoveItem(int index)
    {
        _Index.Remove(new EventGroupIDLayerTuple(this[index].EventGroupID, this[index].Layer));
        base.RemoveItem(index);
    }
    protected override void SetItem(int index, EventGroupLayerResult item)
    {
        _Index.Remove(new EventGroupIDLayerTuple(this[index].EventGroupID, this[index].Layer));
        _Index.Add(new EventGroupIDLayerTuple(item.EventGroupID, item.Layer), item);
        base.SetItem(index, item);
    }
    #endregion
}

这段代码让我可以快速创建/访问/修改集合中的元素,如下所示:

eventGroupLayerResults[evt.GroupID, lyr].Sum += value;

虽然仍允许我轻松地将集合绑定到UI。

更好的解决方案仍然会受到赞赏,因为我必须覆盖一堆ObservableCollection方法来执行此操作。