Entity Frameworkを使用してグリッドコントロールを作成しています。時々私がアップデートをするとき、私は以下のエラーを得ます:
ストアの更新、挿入、または削除ステートメントが、予期しない行数(0)に影響しました。エンティティがロードされてからエンティティが変更または削除された可能性があります。 ObjectStateManagerエントリを更新します。
これを再現する方法がわかりません。しかし、それは私がどれほど密接に私が更新をするかと関係があるかもしれません。誰かがこれを見たことがありますか、それともエラーメッセージが何を参照しているのか知っていますか?
編集:残念ながら、私はこのプロジェクトから離れ、他の開発者が解決したのか、それとも解決したのかを思い出していないため、ここで発生していた問題を再現することはもはや自由です。したがって、私は答えを受け入れることができません。
これは楽観的同時実行性と呼ばれる機能の副作用です。
Entity Frameworkでのオン/オフの切り替え方法は100%確信できませんが、基本的に言っているのは、データベースからデータを取得してから変更を保存するまでの間です。それを保存するために、0行が実際に更新されました。 SQLの用語では、それらのupdate
クエリのwhere
句には、行内のすべてのフィールドの元の値が含まれています。0行に影響がある場合は、問題があることがわかります。
その背後にある考え方は、あなたのアプリケーションが起こったことを知らなかった変更をあなたが上書きすることにならないということです - それは基本的にすべてのあなたの更新に関して.NETによってもたらされる少し安全対策です。
それが一貫していれば、それはあなた自身のロジックの中で起こっている可能性があります(例えば、選択と更新の間に別の方法であなた自身がデータを自分で更新している)。
私はこれに遭遇し、それはエンティティのID(キー)フィールドが設定されていないことが原因でした。そのため、コンテキストがデータを保存しようとしたときに、ID = 0が見つかりませんでした。更新ステートメントに必ずブレークポイントを設定し、エンティティのIDが設定されていることを確認してください。
Paul Belloraのコメントより
.cshtml編集ページに隠しIDの入力を含めるのを忘れたために、この問題が発生しました。
うわー、多くの答えが、私は私が他に誰も言及していないことをわずかに異なる何かをしたときに私はこのエラーを得た。
長い話を簡単に言うと、新しいオブジェクトを作成し、EntityState.Modified
を使用してそのオブジェクトが変更されたことをEFに通知すると、データベースにはまだ存在しないため、このエラーが発生します。これが私のコードです:
MyObject foo = new MyObject()
{
someAttribute = someValue
};
context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();
はい、これはダフトに思えますが、問題のメソッドは以前はfoo
が渡されていましたが、今はsomeValue
が渡されるだけでfoo
自体が作成されるために発生しました。
簡単に修正できます、EntityState.Modified
をEntityState.Added
に変更するか、その行全体を次のように変更してください。
context.MyObject.Add(foo);
私はこれと同じ怖いエラーに直面していました... :)それから私は私が設定するのを忘れていたことに気づきました
@Html.HiddenFor(model => model.UserProfile.UserId)
更新されるオブジェクトの主キー用です。私はこの単純な、しかし非常に重要なことを忘れがちです!
ちなみにHiddenFor
はASP.NET MVC用です。
GridViewの "DataKeyNames"属性を忘れていないか確認してください。 GridView内でデータを変更するときは必須です
http://msdn.Microsoft.com/ja-jp/library/system.web.ui.webcontrols.gridview.datakeynames.aspx
問題は2つの事柄のどちらかによって引き起こされます: -
Concurrency Mode: Fixed
で行を更新しようとしましたが、オプティミスティック同時実行性によりデータが保存されませんでした。すなわちサーバーデータを受信してからサーバーデータを保存するまでの間に、行データが変更されることがありました。StoreGeneratedPattern = Computed
)とその行を更新しようとしても、お手数です存在しません。PKの一部がdatetime列であり、挿入されているレコードがその列の値としてDateTime.Nowを使用していたため、これと同じエラーが発生しました。エンティティフレームワークはミリ秒の精度で値を挿入し、次にミリ秒の精度で挿入したばかりの値を探します。しかし、SqlServerは値を第2精度に丸めていたため、エンティティフレームワークはミリ秒の精度値を見つけることができませんでした。
解決策は、挿入する前にDateTime.Nowからミリ秒を切り捨てることでした。
私は同じ問題を抱えていて、@ webtrifusionの 答え が解決策を見つけるのに役立ちました。
私のモデルは、エンティティのIDにBind(Exclude)
属性を使用していたため、HttpPostではエンティティのIDの値がゼロになっていました。
namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
[ScaffoldColumn(false)]
public int OrderID { get; set; }
[ScaffoldColumn(false)]
public System.DateTime OrderDate { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Username { get; set; }
}
}
私は同じ問題を抱えていた、私はそれがnullだったRowVersionによって引き起こされたことを理解する。あなたのIdとあなたのRowVersionがnullでないことを確認してください。
詳細については、このチュートリアルを参照してください。
私もこのエラーに出くわしました。それが判明した問題は、私が保存しようとしていたテーブルのトリガーが原因でした。トリガは 'INSTEAD OF INSERT'を使用しました。これは0行がそのテーブルに挿入されたことを意味するため、エラーになります。幸いなことに、トリガ機能が正しくなかった可能性がありますが、それは何らかの形でコード内で処理されるべき有効な操作である可能性があると思います。これがいつか誰かに役立つことを願っています。
編集中にエンティティのIDまたは主キーをビューの非表示フィールドとして含める
すなわち
@Html.HiddenFor(m => m.Id)
これで問題は解決します。
また、モデルに未使用のアイテムが含まれている場合はそれも含めてコントローラに投稿してください
主キーのBoundFieldを明示的に含める必要があります。ユーザーに主キーを見せたくない場合は、cssで非表示にする必要があります。
<asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden"
HeaderStyle-CssClass="hidden" />
'hidden'は、表示が 'none'に設定されているcssのクラスです。
私の場合は[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]
行がトリックでした。
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
モデル優先からコード優先に変更した後、このエラーが発生し始めました。私は複数のスレッドがデータベースを更新していて、その中には同じ行を更新するものがあります。私がmodel-firstの使用に問題がなかった理由はわかりませんが、別の並行性デフォルトを使用すると仮定します。
発生する可能性がある条件を把握して1か所で処理するために、DbContextクラスに次のオーバーロードを追加しました。
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
public class MyDbContext: DbContext {
...
public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
try {
return SaveChanges();
}
catch (DbUpdateConcurrencyException ex) {
foreach (DbEntityEntry entry in ex.Entries) {
if (refreshMode == RefreshMode.ClientWins)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
else
entry.Reload();
}
return SaveChanges();
}
}
}
次に該当する場合はSaveChanges(true)
と呼びます。
@Html.HiddenFor(model => model.RowVersion)
私のrowversionはnullだったので、私の問題を解決した見解にこれを追加しなければなりませんでした
async
メソッドを使用しているときに散発的にこのエラーが発生しました。同期方式に切り替えてから発生していません。
散発的なエラー:
[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
var file = new Models.File() { Id = id, CustomerId = customerId };
db.Files.Attach(file);
db.Files.Remove(file);
await db.SaveChangesAsync();
return Ok();
}
常に動作します。
[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
var file = new Models.File() { Id = id, CustomerId = customerId };
db.Files.Attach(file);
db.Files.Remove(file);
db.SaveChanges();
return Ok();
}
テーブルとフォームの両方に主キーとedmxが更新されていることを確認してください。
私は更新中のエラーが原因であることがわかった: - テーブルに主キーがない - 編集ビュー/フォームに主キーがない(例:@Html.HiddenFor(m=>m.Id
)
私は同じ問題を抱えていました。私の場合は、主キーを更新しようとしましたが、これは許可されていません。
DB内のいくつかの行を(ループ内で)削除し、同じテーブルに新しい行を追加したときに、このエラーが発生しました。
私にとっての解決策は、各ループ反復で動的に新しいコンテキストを作成することでした
主キーがなく、DATETIME(2、3)列があるテーブルでこの問題に遭遇しました(そのため、エンティティの「主キー」はすべての列の組み合わせでした)...挿入を実行するとき、タイムスタンプはより正確な時刻(2018-03-20 08:29:51.8319154)は(2018-03-20 08:29:51.832)に切り捨てられたため、キーフィールドの検索は失敗します。
public void Save(object entity)
{
using (var transaction = Connection.BeginTransaction())
{
try
{
SaveChanges();
transaction.Commit();
}
catch (OptimisticConcurrencyException)
{
if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
this.Refresh(RefreshMode.StoreWins, entity);
else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
Detach(entity);
AcceptAllChanges();
transaction.Commit();
}
}
}
私もこのエラーがありました。エンティティが実際に使用しているデータベースコンテキストを認識していない、またはモデルが異なる場合があります。これには、EntityState.Modifiedを設定します。 EntityState.Addedに。
これをする:
if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}
これにより、エンティティは、作業中の州を使用または追加していることを認識します。この時点ですべての正しいモデル値を設定する必要があります。バックグラウンドで行われた可能性のある変更を失わないように注意してください。
お役に立てれば。
まあ、私はこれと同じ問題を抱えています。しかし、これは私自身のミスによるものです。実際に私はそれを追加するのではなくオブジェクトを保存していました。だからこれは矛盾でした。
Sql Server環境でこの問題をデバッグする1つの方法は、SqlServerのコピーに含まれているSql Profilerを使用するか、Expressバージョンを使用している場合は以下のリンクでCodePlexからExpress Profilerのコピーを無料で入手します。
Sql Profilerを使用すると、EFからDBに送信されているものすべてにアクセスできます。私の場合、これは次のようになりました。
exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go
これをSql Serverのクエリウィンドウにコピーして実行しました。確かに、実行されましたが、0件のレコードがこのクエリの影響を受けたため、EFからエラーが返されました。
私の場合、問題はCategoryIDが原因でした。
データベースに送信されたID EFによって識別されるCategoryIDがなかったため、影響を受けるレコードは0個です。
これはEFのせいではなく、むしろバグのあるnull合体 "??"です。ナンセンスをデータ層に送信していたView Controllerでのステートメント.
上記の答えのどれも私の状況とそれに対する解決策を完全にカバーしていませんでした。
MVC5コントローラでエラーがスローされたコード:
if (ModelState.IsValid)
{
db.Entry(object).State = EntityState.Modified;
db.SaveChanges(); // line that threw exception
return RedirectToAction("Index");
}
編集ビューからオブジェクトを保存しているときにこの例外が発生しました。それを投げたのは、保存するために戻ったときに、オブジェクトの主キーを形成するプロパティを変更したからです。したがって、その状態をModifiedに設定してもEFには意味がありません - 以前に保存されたものではなく、新しいエントリでした。
これを解決するには、A)オブジェクトの追加の保存呼び出しを変更するか、B)編集時に主キーを変更しないでください。私はB)をしました。
あなたのedmxファイルで "function Imports"へのマッピングを作成しようとしている場合、これはこのエラーを引き起こす可能性があります。 edmxの特定のエンティティのマッピング詳細にある挿入、更新、削除のフィールドをクリアするだけで、うまくいきます。私がそれを明らかにしたことを願っています。
受け入れられた答えが「あなたのアプリケーションが起こったことを知らなかった変更を上書きしてしまうことはないだろう」と言ったとき、私のオブジェクトは懐疑的でした。新しく作成されました。しかし、それが判明した、同じテーブルの計算列を更新していたテーブルにINSTEAD OF UPDATE, INSERT- TRIGGER
が添付されていました。
これをAFTER INSERT, UPDATE
に変更すると、正常に動作していました。
これは、datetimeとdatetime2が一致しないために起こりました。奇妙なことに、それはテスターが問題を発見する前にうまくいきました。私のCode Firstモデルは主キーの一部としてDateTimeを含んでいました:
[Key, Column(Order = 2)]
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;
生成された列は日時列です。 SaveChangesを呼び出すと、EFは次のSQLを生成しました。
-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))
Datetime列をdatetime2値と一致させようとしていたため、結果が返されませんでした。考えられる唯一の解決策は、列をdatetime2に変更することでした。
[Key, Column(Order = 2, TypeName = "DateTime2")]
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;
あなたがユニークな制約状況に挿入しようとしているならば、これはまた起こるでしょう、すなわちあなたが雇用者ごとに1つのタイプのアドレスを持つことができて、同じ雇用主と同じタイプの2番目を挿入しようとするなら、あなたは同じ問題を得るでしょう。
または
これは、割り当てられているすべてのオブジェクトプロパティに、以前と同じ値が割り当てられている場合にも発生する可能性があります。
using(var db = new MyContext())
{
var address = db.Addresses.FirstOrDefault(x => x.Id == Id);
address.StreetAddress = StreetAddress; // if you are assigning
address.City = City; // all of the same values
address.State = State; // as they are
address.ZipCode = ZipCode; // in the database
db.SaveChanges(); // Then this will throw that exception
}
同じ問題がありました。
私はEF 6、Code First + Migrationsを使用しています。問題は、私たちのDBAがテーブルにエラーを投げかけた制約を作成したことです。
誤って保存せずにオブジェクトを更新しようとしたときに、この問題が発生しました。
私は持っていた
if (IsNewSchema(model))
unitOfWork.SchemaRepository.Update(schema);
else
unitOfWork.SchemaRepository.Insert(schema);
あるべきときに
if (IsNewSchema(model))
unitOfWork.SchemaRepository.Insert(schema);
else
unitOfWork.SchemaRepository.Update(schema);
私はTelerikのRadGridを使ってこれに遭遇しました。私は主キーを読み取り専用に設定されたグリッドバウンド列として持っていました。列がdisplay = "false"でreadonly = "true"の場合は問題なく動作します。 gridbound列のdisplay = falseと表示用に別のテンプレート列を追加することで解決しました
<telerik:GridBoundColumn HeaderText="Shouldnt see" Display="false"
UniqueName="Id" DataField="Id">
</telerik:GridBoundColumn>
<telerik:GridTemplateColumn HeaderText="Id" UniqueName="IdDisplay">
<ItemTemplate>
<asp:Label ID="IDLabel" runat="server"
Text='<%# Eval("Id") %>'></asp:Label>
</ItemTemplate>
</telerik:GridTemplateColumn>
AutoMapperを使用している人のために、外部キーを持つエンティティを別のエンティティに更新する場合は、すべての外部エンティティがそれらの主キーは、生成されたデータベースに設定されます(またはMySQLの場合は自動インクリメントされます)。
例えば:
public class BuyerEntity
{
[Key]
public int BuyerId{ get; set; }
public int Cash { get; set; }
public List<VehicleEntity> Vehicles { get; set; }
public List<PropertyEntity> Properties { get; set; }
}
車両とプロパティは、購入者以外のテーブルに格納されています。新しいバイヤーを追加すると、AutoMapperとEFは自動的にVehiclesテーブルとPropertiesテーブルを更新するので、どちらのテーブルにも自動インクリメントが設定されていないと(私は行っていません)、エラーが表示されます。 OPの質問.
データベースに存在しないオブジェクトをアタッチすると、この例外が発生しました。オブジェクトは別のコンテキストからロードされたものと想定していましたが、ユーザーが初めてサイトにアクセスした場合は、オブジェクトは最初から作成されています。自動インクリメントの主キーがあるので、私は置き換えることができます
context.Users.Attach(orderer);
と
if (orderer.Id > 0) {
context.Users.Attach(orderer);
}
データベースに存在しないIDでレコードを更新しようとすると、これが発生することがあります。
私はこの例外を得ました、そして私は私のdatabase's table
の自動インクリメントとしてid
カラムをセットしました、そして、それはそれでうまく働きました
並列ループで作業中に誰かがこの問題に遭遇した場合に備えて、これをスローします。
Parallel.ForEach(query, deet =>
{
MyContext ctx = new MyContext();
//do some stuff with this to identify something
if(something)
{
//Do stuff
ctx.MyObjects.Add(myObject);
ctx.SaveChanges() //this is where my error was being thrown
}
else
{
//same stuff, just an update rather than add
}
}
私はそれを次のように変更しました。
Parallel.ForEach(query, deet =>
{
MyContext ctxCheck = new MyContext();
//do some stuff with this to identify something
if(something)
{
MyContext ctxAdd = new MyContext();
//Do stuff
ctxAdd .MyObjects.Add(myObject);
ctxAdd .SaveChanges() //this is where my error was being thrown
}
else
{
MyContext ctxUpdate = new MyContext();
//same stuff, just an update rather than add
ctxUpdate.SaveChanges();
}
}
これが「ベストプラクティス」であるかどうかはわかりませんが、各並列操作に独自のコンテキストを使用させることで、問題を解決しました。
(コンテキスト内で)2つのテーブルから複数の行が削除されている作業単位(SaveChanges(False)が削除の1つに含まれている)で、同じコンテキストでSaveChanges(false)を使用し、その後SaveChanges()を使用すると、このエラーが発生します。呼び出し関数SaveChanges()で呼び出されていました....解決策は不要なSaveChangesを削除することでした(false)。
これはちょうど私に起こりました。 Aurora(AWS MySQL)を実行していて、レコードをテーブルに追加しようとしました。モデル内の[Key]と表示されたフィールドは、テーブル内の自動インクリメントされたフィールドにマッピングされていました。これは主キーとして設定されていましたが、自動インクリメントに設定されていませんでした。自動インクリメントに設定すると、問題が解決しました。
最近、EF5をEF6サンプルプロジェクトにアップグレードしようとしています。サンプルプロジェクトのテーブルには、10進(5,2)型の列があります。データベース移行は正常に完了しました。しかし、初期データシードで例外が発生しました。
モデル:
public partial class Weather
{
...
public decimal TMax {get;set;}
public decimal TMin {get;set;}
...
}
間違った設定:
public partial class WeatherMap : EntityTypeConfiguration<Weather>
{
public WeatherMap()
{
...
this.Property(t => t.TMax).HasColumnName("TMax");
this.Property(t => t.TMin).HasColumnName("TMin");
...
}
}
データ:
internal static Weather[] data = new Weather[365]
{
new Weather() {...,TMax = 3.30M,TMin = -12.00M,...},
new Weather() {...,TMax = 5.20M,TMin = -10.00M,...},
new Weather() {...,TMax = 3.20M,TMin = -8.00M,...},
new Weather() {...,TMax = 11.00M,TMin = -7.00M,...},
new Weather() {...,TMax = 9.00M,TMin = 0.00M,...},
};
問題は、シードデータには精度の値がありますが、設定には精度とスケールのパラメータがないことです。サンプル表では、TMaxフィールドとTMinフィールドは10進数(10,0)で定義されています。
正しい設定:
public partial class WeatherMap : EntityTypeConfiguration<Weather>
{
public WeatherMap()
{
...
this.Property(t => t.TMax).HasPrecision(5,2).HasColumnName("TMax");
this.Property(t => t.TMin).HasPrecision(5,2).HasColumnName("TMin");
...
}
}
私のサンプルプロジェクトは、MySql 5.6.14、Devart.Data.MySql、MVC4、.Net 4.5.1、EF6.01で実行されます。
宜しくお願いします。
「マルチパート」フォームデータを投稿する「enctype」の記載を忘れていました。今直面しているもう1つのシナリオの1つ...
私たちの場合、このエラーは、エンティティのプロパティがどれも「本当に」変更されていない場合にエンティティを変更済みとしてマークすることによって発生しました。たとえば、プロパティに同じ値を割り当てた場合、コンテキストではデータベースではない更新としてそれが表示されることがあります。
基本的に、あるプロパティを他のプロパティの連結値で再設定するスクリプトを実行しました。変更がないことを意味する多くのレコードについては、変更されたものとしてそれらにフラグを立てました。 DBは、おそらくその例外を引き起こした異なる数の更新されたオブジェクトを返しました。
プロパティ値を確認し、異なる場合は新しい値を割り当てることで解決しました。
私は今日同様の問題を抱えていました、それはそれほど楽観的な同時エラーではないのでここでそれを文書化します。
私は古いシステムを新しいデータベースに変換しています、そしてそれは私が新しいシステムにスクリプトを書かなければならなかった何千もの実体を持っています。しかし、正気を保つために、私はオリジナルのユニークなIDを保持することを選んだので、それを新しいオブジェクトに注入してそれを保存しようとしていました。
私が抱えていた問題は、MVC Scaffoldingを使ってベースリポジトリを作成し、それらがUpdateOrInsertメソッド内にパターンを持っているということです。 。
Guidが設定されているため、データベースに実際には存在しない行を変更しようとしていました。
私はこれが他の人に役立つことを願っています!
ON DELETE CASCADE規則(RefTable1、RefTable2)を持つ別の2つのテーブル外部キーによって参照されていたテーブル(ParentTable)から項目を削除するときに同じ問題が発生しました。参照テーブルの1つ(RefTable1)で "AFTER DELETE"トリガが発生するため、問題が発生します。 RefTable2レコードも削除されたため、このトリガはParentTableから関連レコードを削除していました。 Entity Frameworkは、コード内で明示的にParentTableレコードを削除するように設定されていましたが、後の操作の後にRefTable1から関連レコードを削除してからRefTable2からレコードを削除していました。
代わりに新しいユーザーを登録するとき、私はMvc IDでこの問題を抱えていました:
var result = await UserManager.CreateAsync(user);
私がやっていた:
var result = await UserManager.UpdateAsync(user);