8

attachを使用してEF5.xを使用してテーブルを更新しようとしています。このテーブルには、必須のその他のフィールドがありますが、既存の行です。だから私はフェッチなしで更新しようとしています。useridは、テーブルの主キーです。ステータスを更新しようとしています。ただし、パスワードが必要であるというEntityValidationErrorsがスローされます。これは、別の必須フィールドですが、主キーではありません。これは既存の行の更新であるため、更新に必要なフィールドを提供する必要があるのはなぜですか?

    var webUser = new WebUser() { UserId = webUserId, OnlineStatus = (sbyte)status };
    using (var dbxupdate = new xEntities())
    {
        try
        {
            dbxupdate.WebUsers.Attach(webUser);
dbxupdate.Entry(webUser).State = EntityState.Modified;
            dbxupdate.Entry(webUser).Property(x => x.OnlineStatus).IsModified = true;
            dbxupdate.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                }
            }
        }
    }
4

4 に答える 4

16

.Attach()実際には、次のような切り離されたシナリオでエンティティを更新する場合にのみ役立ちます。

User entity = null;

using (var db = new DbContext()) {
    entity = (from p in db.Users
              where p.Id == 1
              select p).FirstOrDefault();

    System.Diagnostics.Trace.WriteLine(entity.Name); //Outputs "Jane Doe"
}

entity.Name = "John Doe" //Modified while no longer connected to database

using (var db = new DbContext()) {
    db.Users.Attach(entity);
    db.Entry(entity).Property(a => a.Name).IsModified = true;
    db.SaveChanges();

    System.Diagnostics.Trace.WriteLine(entity.Name); //Now outputs "John Doe"
}

シナリオでは、作成しているエンティティはそのキーによって取得されておらず、データベースはそれを完全に新しいエンティティとして扱っています。パスワードはnull許容フィールドではないと思います。これにより、EFが変更を保存しようとしたときにエラーがスローされます。このようなエラーがなかった場合、EFは、変更していないフィールドを自動的に無効にしてから、エンティティを保存します(これは、探している結果でもありません)。

本当に必要な変更を加えるには、次のようなものを試してください。

using (var db = new DbContext()) {
    db.Users
        .Single(a => (a.Id == 1))
        .OnlineStatus = ((sbyte)status);
    db.SaveChanges();
}

次に、必要な他のエラー処理/検証コードを追加します。または、一度に複数のフィールドに変更を加えるために、エンティティを変数に格納することもできます。EFは、変更された値を自動的に判別し、それらの変更を行うために必要なSQLのみを生成する必要があります。つまり、次のようなものがある場合:

using (var db = new DbContext()) {
    foreach (var item in entityList) {
        var entity = db.Users.Single(a => (a.Id == item.Id));

        entity.Name = item.Name;
        entity.Address = item.Address;
    }

    db.SaveChanges();
}

その場合、EFは、このコードによって実際に影響を受けるエンティティ/フィールドのみを更新する必要があります。名前またはアドレスが同じままの場合、EFは変更をデータベースに保存するときに、そのエンティティのそのフィールドをスキップします。

于 2012-12-31T21:42:15.133 に答える
2

エンティティは、データベースにアタッチされているかデータベースからロードされているかに関係なく、保存時に検証されます。検証属性または検証メソッドを使用する場合、エンティティは保存するために検証に合格する必要があります。

パスワードフィールドに属性がある場合[Required]は、かなり行き詰まっていると思います。おそらく、エンティティをロードしてから、単に添付するのではなく、情報を更新する必要があります。

于 2012-12-31T20:15:46.477 に答える
0

usingこれを試してください:最初の行を(ステートメント内に配置する)コードに置き換え ます。コードは続行します...エンティティを更新するには、そのインスタンスを取得する必要があります。それ以外の場合は、宣言されていないプロパティが値を取得する新しいプロパティを作成しています。
var wu = dbxupdate.webUsers.single(i=>i.id== webUserId);
wu.OnlineStatus = whatever;

null

于 2012-12-31T20:28:51.777 に答える
0

エンティティフレームワークでは、他のフィールドに適切な値を設定せずにフィールドを更新することはできません。したがって、ジョブにはストアドプロシージャを使用することをお勧めします。もう1つの方法は、レコードをフェッチしてからフィールドを更新することです。

于 2012-12-31T20:35:26.700 に答える