1

私は、Entity Framework 5 で使用するために多くの場所で推奨されている次のコードを使用しています。

    foreach (var entry in this.ChangeTracker.Entries()
                 .Where(
                      e => e.Entity is IAuditableTable &&
                     (e.State == EntityState.Added) ||
                     (e.State == EntityState.Modified)))
    {
        IAuditableTable e = (IAuditableTable)entry.Entity;
        if (entry.State == EntityState.Added)
        {
            if (e.CreatedBy == 0) 
                e.CreatedBy = 1;
            if (e.CreatedDate == DateTime.MinValue) 
                e.CreatedDate = DateTime.Now;
        }
        if (e.ModifiedBy == 0) 
            e.ModifiedBy = 1;
        if (e.ModifiedDate == DateTime.MinValue) 
            e.ModifiedDate = DateTime.Now;
    }

これは EF5 でうまく機能します。これを追加するだけです:

public partial class Objective : AuditableTable
{

そして以下を持っています:

public abstract class AuditableTable : IAuditableTable
{
    public virtual byte[] Version { get; set; }
    public int CreatedBy { get; set; }
    public DateTime CreatedDate { get; set; }
    public int ModifiedBy { get; set; }
    public DateTime ModifiedDate { get; set; }
}

でも。このようなクラスがある場合:

public partial class Objective : AuditableTable
{
    public Objective()
    {
        this.ObjectiveDetails = new List<ObjectiveDetail>();
    }
    public int ObjectiveId { get; set; }
    public int Number { get; set; }
    public string Text { get; set; }
    public virtual ICollection<ObjectiveDetail> ObjectiveDetails { get; set; }
}

その後、コードが機能せず、次の行でエラーが発生しますIAuditableTable e = (IAuditableTable)entry.Entity;。ObjectiveDetail クラスを IAuditableTable にキャストしようとしています。

"Unable to cast object of type 'Models.Core.ObjectiveDetail' to type 'Models.Core.IAuditableTable'."

ObjectiveDetailもIAuditableTable から継承するか、次の追加のチェックを追加しない限り、チェック コードを動作させることはできませんif (entry.Entity is IAuditableTable) {。メソッド本体の実行を停止します。

私の質問はです。コードを機能させるために、この二次チェックをコードに追加する必要があるのはなぜですか? また、このコードを IAuditableTable から継承するクラスに対してのみ機能させるより良い方法はありますか? e => e.Entity is IAuditableTableクラスに IAuditable を実装していない他のクラスのオブジェクトが含まれている場合、これは機能しないようです。

動作する私のコードは次のとおりです。

foreach (var entry in this.ChangeTracker.Entries()
             .Where(
                  e => e.Entity is IAuditableTable &&
                 (e.State == EntityState.Added) ||
                 (e.State == EntityState.Modified)))
{
    // I do not know why the following line is needed. My code will not work
    // unless I have the following line for classes that contain classes that
    // do not inherit from IAuditableTable
    if (entry.Entity is IAuditableTable) {
        IAuditableTable e = (IAuditableTable)entry.Entity;
        if (entry.State == EntityState.Added)
        {
            if (e.CreatedBy == 0) 
                e.CreatedBy = 1;
            if (e.CreatedDate == DateTime.MinValue) 
                e.CreatedDate = DateTime.Now;
        }
        if (e.ModifiedBy == 0) 
            e.ModifiedBy = 1;
        if (e.ModifiedDate == DateTime.MinValue) 
            e.ModifiedDate = DateTime.Now;
    }
}
4

1 に答える 1

1

問題は、演算子 && および || のデフォルトの優先順位にあります。whereメソッドの条件で。

現在使用している条件には AND 条件と OR 条件がありますが、演算子 &&,|| の方法を解決するブラケットを追加していません。解決されます:

this.ChangeTracker.Entries()
         .Where(
              e => e.Entity is IAuditableTable &&
             (e.State == EntityState.Added) ||
             (e.State == EntityState.Modified))

したがって、デフォルトでは次のように解釈されます。

(e.Entity is IAuditableTable && (e.State == EntityState.Added))
|| (e.State == EntityState.Modified)

これには、(エンティティが IAuditable かつ追加された) または変更された場合にレコードが含まれます。そのためIAuditableTable、そうでない場合でも、エンティティが変更された場合はループに含まれます。

必要なロジックについては、|| を囲む角かっこを追加する必要があります。エンティティが追加または変更されたことを確認する条件:

e.Entity is IAuditableTable && 
((e.State == EntityState.Added) || (e.State == EntityState.Modified))

この方法では、IAuditable AND (変更または追加された) の場合にのみ含まれます。

于 2013-08-11T09:33:51.623 に答える