我想要实现的目标:我想拥有一个DataTable,其中包含具有不同属性的不同类型的行。一个例子是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);
问题:DataTable对象可以由用户操作(使用DataGridView),我需要将这些更改保存到我的数据模型中的数据库中(不保存sum行)。 如果具有以下功能,请检查更改:
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添加列,因为这会将我的视图与数据模型紧密耦合。如果我为每个属性创建了新列,我会在模型中执行此操作,并且需要在视图中隐藏所有这些列 - 我认为这些列非常难看。
问题:是否有可能以某种方式创建一个DataTable,其中包含维护自定义属性的自定义类型的DataRows?
在此先感谢您的帮助
在思考了一些之后,我找到了一个迄今为止工作正常的解决方案我不确定它的扩展程度如何,但对于总和,我非常满意。关键是还要使用自定义代码实现GetChanges,因为有关sum行的信息在该函数中是已知的。 这是我目前的实施:
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);
}
}
}