データベースに、挿入と更新で設定される読み取り専用フィールドを持つテーブルがいくつかあります。つまり、AddDate(DateTime)、AddUserName(string)、LastModDate(DateTime)、LastModUserName(string)です。
これらの値を持つすべてのテーブルは、次のインターフェイスから継承するように設定されています。
public interface IUserTrackTable
{
string AddUserName { get; set; }
DateTime AddDate { get; set; }
string LastModUserName { get; set; }
DateTime LastModDate { get; set; }
}
そのため、Edit.aspxページには次のメソッドがあります。
protected void DetailsDataSource_Updating(object sender, LinqDataSourceUpdateEventArgs e)
{
IUserTrackTable newObject = e.NewObject as IUserTrackTable;
if (newObject != null)
{
newObject.LastModUserName = User.Identity.Name;
newObject.LastModDate = DateTime.Now;
}
}
ただし、このメソッドにヒットするまでに、e.OriginalObjectは4つのフィールドすべての値をすでに失っているため、実際の更新中にChangeConflictExceptionがスローされます。InitイベントハンドラーのDetailsView1.DataKeyNames配列に4つの列名を追加しようとしました。
protected void Page_Init(object sender, EventArgs e)
{
// other things happen before this
var readOnlyColumns = table.Columns.Where(c => c.Attributes.SingleOrDefaultOfType<ReadOnlyAttribute>(ReadOnlyAttribute.Default).IsReadOnly).Select(c => c.Name);
DetailsView1.DataKeyNames = DetailsView1.DataKeyNames.Union<string>(readOnlyColumns).ToArray<string>();
DetailsView1.RowsGenerator = new CustomFieldGenerator(table, PageTemplates.Edit, false);
// other things happen after this
}
私はそのコードをPostBackでのみ発生させようとしましたが、それでも何も起こりません。ラウンドトリップを行うためにすべての列の値を取得する方法に迷っています。
CustomFieldGeneratorは、C#ビットの詳細に従って、ReadOnlyAttributeを処理するだけです。
更新:さらに調査した後、値はDetailsView_ItemUpdatingイベントへのラウンドトリップを行います。すべての値はe.OldValuesディクショナリにあります。ただし、LinqDataSource_Updatingイベントに到達するまでに失われます。
明らかに、これらの列を同時実行チェックやハードコーディングを伴うその他の方法に参加させない「ソリューション」がありますが、理想的なソリューションは、必要に応じて適切な情報を動的に追加し、これが動的ソリューションとして残るようにします。