0

データベースに、挿入と更新で設定される読み取り専用フィールドを持つテーブルがいくつかあります。つまり、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イベントに到達するまでに失われます。

明らかに、これらの列を同時実行チェックやハードコーディングを伴うその他の方法に参加させない「ソリューション」がありますが、理想的なソリューションは、必要に応じて適切な情報を動的に追加し、これが動的ソリューションとして残るようにします。

4

1 に答える 1

0

i Drovani、データ監査が必要だと思います (Steve Sheldon のA Method to Handle Audit Fields in LINQ to SQL を参照)。EF4 のモデルでこれを行うと、次のようになります。

partial void OnContextCreated()
{
    // Register the handler for the SavingChanges event. 
    this.SavingChanges += new EventHandler(context_SavingChanges);
}

private static void context_SavingChanges(object sender, EventArgs e)
{
    // handle auditing
    AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Added));
    AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Modified), InsertMode: false);
}

internal static class AuditingHelperUtility
{
    internal static void ProcessAuditFields(IEnumerable<Object> list, bool InsertMode = true)
    {
        foreach (var item in list)
        {
            IAuditable entity = item as IAuditable;
            if (entity != null)
            {
                if (InsertMode)
                {
                    entity.InsertedBy = GetUserId();
                    entity.InsertedOn = DateTime.Now;
                }

                entity.UpdatedBy = GetUserId();
                entity.UpdatedOn = DateTime.Now;
            }
        }
    }
}

残念ながら、これは EF v1 では不可能です。

于 2010-12-12T11:39:27.350 に答える