DataRow的自定义属性

时间:2019-04-23 09:17:04

标签: c# datarow

我要实现的目标:我想拥有一个数据表,其中的不同类型的行具有不同的属性。一个示例是DataTable末尾的求和行(一旦工作,将有更多行)。

this question描述扩展DataRow类(不是可接受的类)的两个答案的启发,我实现了以下内容:

public class ProjectEffortTable : DataTable
{
    public ProjectEffortTable() : base() { }
    public ProjectEffortTable(String TableName) : base(TableName) { }
    protected ProjectEffortTable(System.Runtime.Serialization.SerializationInfo Info, System.Runtime.Serialization.StreamingContext Context) : base (Info, Context) { }
    public ProjectEffortTable(String TableName, String TableNamespace) : base(TableName, TableNamespace) { }

    protected override Type GetRowType()
    {
        return typeof(ProjectEffortRow);
    }
    protected override DataRow NewRowFromBuilder(DataRowBuilder Builder)
    {
        return new ProjectEffortRow(Builder);
    }
}
public class ProjectEffortRow : DataRow
{
    public ProjectEffortRow (DataRowBuilder Builder) : base (Builder)
    {
    }

    public Boolean IsSum { get; set; }
}

使用以下代码,我可以添加一个新的求和行:

var SumRow = ProjectEfforts.NewRow() as ProjectEffortRow;
SumRow.IsSum = true;
// calculate sums for all month columns
foreach (DataColumn Column in ProjectEfforts.Columns)
{
    Decimal Sum = 0;
    foreach (DataRow CurrentRow in ProjectEfforts.Rows)
    {
        if (CurrentRow[Column] is Double)
        {
            Sum += Convert.ToDecimal(CurrentRow[Column]);
        }
    }
    SumRow[Column] = Decimal.Truncate(Sum);
}
ProjectEfforts.Rows.Add(SumRow);

问题:数据表对象可以由用户操作(使用DataGridView),并且我需要将这些更改保存到我的数据模型中的数据库中(不保存总和行)。
要检查更改是否具有以下功能:

Boolean CheckForChanges()
{
    Boolean Changed = false;

    var ProjectChanges = DataTableObject.GetChanges();
    if (ProjectChanges != null)
    {
        for (var i = 0; i < ProjectChanges.Rows.Count; i++)
        {
            if (!(ProjectChanges.Rows[i] as ProjectEffortRow).IsSum)
            {
                Changed = true;
            }
        }
    }
    return Changed;
}

不幸的是,该方法始终返回true,因为似乎GetChanges()创建了一个新的DataTable,其中该属性的信息丢失了。

我不想做什么:我不想为每个属性在DataTable中添加列,因为这会将我的视图与数据模型紧密结合在一起。如果我为每个属性创建新列,则将在模型中执行此操作,并且需要在视图中隐藏所有这些列-我认为这很难看。

问题:是否可以通过某种方式创建一个包含自定义类型的DataRows的DataTable,以维护自定义属性?

在此先感谢您的帮助

1 个答案:

答案 0 :(得分:0)

经过更多思考后,我找到了迄今为​​止可以正常使用的解决方案。我不确定它的缩放程度如何,但是对于求和行我还是很满意的。关键是还可以用自定义代码实现GetChanges,因为该函数中已知关于汇总行的信息。 这是我当前的实现:

public class ProjectEffortTable : DataTable
{
    public ProjectEffortTable() : base() { }
    public ProjectEffortTable(String TableName) : base(TableName) { }
    protected ProjectEffortTable(System.Runtime.Serialization.SerializationInfo Info, System.Runtime.Serialization.StreamingContext Context) : base (Info, Context) { }
    public ProjectEffortTable(String TableName, String TableNamespace) : base(TableName, TableNamespace) { }

    protected override Type GetRowType()
    {
        return typeof(ProjectEffortRow);
    }
    protected override DataRow NewRowFromBuilder(DataRowBuilder Builder)
    {
        return new ProjectEffortRow(Builder);
    }
    public new ProjectEffortTable GetChanges()
    {
        var Changes = Clone() as ProjectEffortTable;
        foreach (ProjectEffortRow CurrentRow in Rows)
        {
            if ((CurrentRow.RowState != DataRowState.Unchanged) && (!CurrentRow.IsSum))
            {
                Changes.ImportRow(CurrentRow);
            }
        }
        if (Changes.Rows.Count == 0)
        {
            Changes = null;
        }
        return Changes;
    }
    public new ProjectEffortTable GetChanges(DataRowState RowStates)
    {
        var Changes = Clone() as ProjectEffortTable;
        foreach (ProjectEffortRow CurrentRow in Rows)
        {
            if ((CurrentRow.RowState == RowStates) && (!CurrentRow.IsSum))
            {
                Changes.ImportRow(CurrentRow);
            }
        }
        if (Changes.Rows.Count == 0)
        {
            Changes = null;
        }
        return Changes;
    }

    public void AddSumRow()
    {
        // add line with sum for each month column
        var SumRow = NewRow() as ProjectEffortRow;
        SumRow.IsSum = true;
        Rows.Add(SumRow);
        RecalculateSums();
    }
    public Boolean HasSumRow()
    {
        var SumRowFound = false;

        if ((Rows[Rows.Count - 1] as ProjectEffortRow).IsSum)
        {
            SumRowFound = true;
        }
        return SumRowFound;
    }
    public void RemoveSumRow()
    {
        if (HasSumRow())
        {
            Rows[Rows.Count - 1].Delete();
        }
    }

    private void RecalculateSums()
    {
        if (!HasSumRow())
        {
            throw new ApplicationException("Recalculation of sum triggered without sum row being present");
        }

        foreach (DataColumn Column in Columns)
        {
            Decimal Sum = 0;
            foreach (ProjectEffortRow CurrentRow in Rows)
            {
                if ((CurrentRow[Column] is Double) && (!CurrentRow.IsSum))
                {
                    Sum += Convert.ToDecimal(CurrentRow[Column]);
                }
            }
            Rows[Rows.Count - 1][Column] = Decimal.Truncate(Sum);
        }
    }
}