Entity Framework:“ Store update, insert หรือ delete statement ส่งผลต่อจำนวนแถวที่ไม่คาดคิด (0)” [ปิด]


324

ฉันใช้ Entity Framework เพื่อเติมการควบคุมกริด บางครั้งเมื่อฉันอัปเดตฉันได้รับข้อผิดพลาดต่อไปนี้:

ปรับปรุงร้านแทรกหรือลบคำสั่งส่งผลกระทบต่อจำนวนแถวที่ไม่คาดคิด (0) อาจมีการแก้ไขหรือลบรายการเนื่องจากมีการโหลดรายการ รีเฟรชรายการ ObjectStateManager

ฉันไม่สามารถหาวิธีทำให้เกิดสิ่งนี้ได้ แต่มันอาจมีบางอย่างที่เกี่ยวข้องกับการที่ฉันเข้าใกล้อัพเดต มีใครเห็นสิ่งนี้หรือไม่มีใครรู้ว่าข้อความแสดงข้อผิดพลาดหมายถึงอะไร

แก้ไข: น่าเสียดายที่ฉันไม่มีอิสระที่จะทำซ้ำปัญหาที่ฉันมีอยู่ที่นี่เพราะฉันก้าวออกจากโครงการนี้และจำไม่ได้ว่าในที่สุดฉันก็พบทางออกถ้านักพัฒนารายอื่นแก้ไขหรือถ้าฉันแก้ไขมัน ดังนั้นฉันไม่สามารถยอมรับคำตอบใด ๆ


ผมได้รับข้อผิดพลาดนี้ด้วยการแนะนำของที่นโยบาย SQL Server ระดับแถวรักษาความปลอดภัยที่ปรับปรุงไปยังแถวที่ได้รับอนุญาตให้อยู่ในสภาพที่ไม่สามารถจะกลับมาอ่าน (เป็นคำกริยา FILTER พิเศษกับภาค BLOCK อนุญาต) EntityFramework ต้องการแถวที่อัปเดตเพื่ออ่านกลับหลังการอัพเดทมิฉะนั้นจะถือว่าเป็นข้อผิดพลาดเกิดขึ้นพร้อมกัน
xr280xr

ปัญหาอาจเป็นการกำหนดขอบเขตที่ไม่ถูกต้องสำหรับ DBContext stackoverflow.com/questions/49154250/ของคุณ(ตัวอย่างนี้ใช้สำหรับ ASPNET Identity แต่ใช้กับบริบทใด ๆ )
Simon_Weaver

โดยไม่คำนึงถึงบริบทของข้อผิดพลาดนี้เป็นความคิดที่ดีที่จะใส่เบรกพอยต์ไม่ว่าที่ใดก็ตามที่บริบทกำลังถูกสร้างอินสแตนซ์ คุณคาดหวังหรือไม่ว่าจะถูกทำให้เป็นอินสแตนซ์หนึ่งครั้งเมื่อคุณโหลดหน้าเว็บ แต่มันกดปุ่มเบรกพอยต์นั้น 5 ครั้งหรือไม่? จากนั้นคุณอาจจะมีสภาพการแข่งขัน ดูRequest.Uriเพื่อดู URL คำขอจริง ในกรณีของฉันฉันมีตรรกะการติดตามบางอย่างที่เข้าชมไซต์ของฉันและโหลดบริบทโดยไม่จำเป็นจากฐานข้อมูล (และบางครั้งก็ปรับปรุงเช่นกัน) ดังนั้นหน้าจริงที่ฉันกำลังดีบั๊กจึงมีข้อมูลที่ถูก stomped โดยตรรกะรหัสติดตามโง่
Simon_Weaver

เพิ่ม @ Html.AntiForgeryToken () ในมุมมอง
Vikas Sharma

คำตอบ:


199

นั่นเป็นผลข้างเคียงของคุณสมบัติที่เรียกว่าการเกิดพร้อมกันในแง่ดี

ไม่แน่ใจ 100% ว่าจะเปิด / ปิดใน Entity Framework แต่โดยทั่วไปสิ่งที่บอกคุณคือระหว่างที่คุณดึงข้อมูลออกจากฐานข้อมูลและเมื่อคุณบันทึกการเปลี่ยนแปลงของคุณคนอื่นจะเปลี่ยนข้อมูล (ซึ่งหมายความว่าเมื่อคุณไป เพื่อบันทึก 0 แถวได้รับการปรับปรุงจริง) ในแง่ SQL ประโยคupdateของแบบสอบถามwhereประกอบด้วยค่าดั้งเดิมของทุกฟิลด์ในแถวและหากมีผลกระทบกับ 0 แถวมันจะรู้ว่ามีบางอย่างผิดปกติ

แนวคิดที่อยู่เบื้องหลังคือคุณจะไม่เขียนทับการเปลี่ยนแปลงที่แอปพลิเคชันของคุณไม่รู้เกิดขึ้น - โดยทั่วไปแล้วจะมีมาตรการด้านความปลอดภัยเล็ก ๆ น้อย ๆ ที่โยนโดย. NET ในการอัปเดตทั้งหมดของคุณ

หากมีความสอดคล้องกันอัตราต่อรองจะเกิดขึ้นภายในตรรกะของคุณเอง (EG: คุณกำลังอัปเดตข้อมูลด้วยตัวเองในวิธีอื่นระหว่างการเลือกและการอัปเดต) แต่อาจเป็นเพียงสภาพการแข่งขันระหว่างสองแอปพลิเคชัน


34
สิ่งนี้เกิดขึ้นในสภาพแวดล้อมแบบผู้ใช้เดี่ยว (บนเครื่อง dev ของฉัน) ดังนั้นฉันไม่คิดว่ามันจะเป็นสภาพการแข่งขัน ฉันผูกพันกับการควบคุมกริดแบบกำหนดเองกับ EntityDataSource ดังนั้นฉันไม่แน่ใจว่าเกิดอะไรขึ้นเบื้องหลัง แต่ฉันไม่มีรหัสพิเศษของตัวเองที่กำลังแก้ไขตาราง มีวิธีในการเปลี่ยนการตั้งค่าการทำงานพร้อมกันนี้หรือไม่?
Strongopinions

3
ฉันคิดว่าคุณสามารถทำตามคอลัมน์ในโมเดลเอนทิตีของคุณ (อยู่ในหน้าต่างคุณสมบัติ) แต่สิ่งนี้คือสิ่งที่จะป้องกันไม่ให้คุณเห็นข้อผิดพลาด แต่จะไม่อัปเดตอะไรเลย คุณสามารถดูคำสั่ง SQL ไปยังฐานข้อมูลของคุณ (EG: SQL Server Profiler สำหรับ MSSQL) ได้หรือไม่? วิธีนี้คุณสามารถดูว่ามีการสร้างการอัปเดตใดและควรจะสามารถเห็นได้ว่าเหตุใดการอัปเดตนั้นจึงไม่ส่งผลกระทบต่อแถวใด ๆ
fyjham

9
หากเอนทิตีมีคุณสมบัติการประทับเวลาตรวจสอบให้แน่ใจว่าคุณได้เก็บข้อมูลไว้ในมุมมองของคุณและตรวจสอบให้แน่ใจว่าเอนทิตีเติมข้อมูลเวลาที่ถูกต้อง
anIBMer

ฉันมีคอลัมน์ประทับเวลาและเมื่อฉันพูดถึงมันแล้ว EF6.1 ก็ทำงานได้ตามที่คาดหวังขอบคุณสำหรับเคล็ดลับ @anelBMer
JQII

3
หากคุณใช้การประทับเวลาวัตถุ tje ที่คุณต้องการลบจำเป็นต้องมีชุด PK และคุณสมบัติ RowVersion เพื่ออัปเดตให้สำเร็จ! ฉันกำลังตั้งค่าคุณสมบัติ rowVersion (การประทับเวลา) หลังจากที่ฉันได้แนบวัตถุกับ DbSet ที่เกี่ยวข้องนั่นเป็นสาเหตุที่มันไม่ทำงาน เยี่ยมมาก!
ตำนาน

394

ฉันพบปัญหานี้และมันเกิดจากช่อง ID (คีย์) ของเอนทิตี ดังนั้นเมื่อบริบทไปบันทึกข้อมูลมันไม่สามารถหา ID = 0 ตรวจสอบให้แน่ใจว่าได้วางจุดพักในคำสั่งการปรับปรุงของคุณและตรวจสอบว่า ID ของกิจการได้รับการตั้งค่าแล้ว

จากความคิดเห็นของ Paul Bellora

ฉันมีปัญหาตรงนี้เกิดจากการลืมใส่รหัสที่ซ่อนอยู่ในหน้าแก้ไข. cshtml


3
+1 ฉันมีปัญหาเดียวกันและสิ่งนี้ช่วยค้นหาวิธีแก้ปัญหา ปรากฎว่าฉันมี [ผูก (ยกเว้น = "OrderID")] ในรูปแบบการสั่งซื้อของฉันซึ่งทำให้มูลค่าของรหัสกิจการเป็นศูนย์ใน HttpPost
Daily

2
นั่นคือสิ่งที่ฉันหายไป ID วัตถุของฉันคือ 0
Azhar Khorasany

4
@ Html.HiddenFor (model => model.productID) - ทำงานได้อย่างสมบูรณ์แบบ ฉันพลาด productID บนหน้าแก้ไข (MVC RAZOR)
Ravi Ram

2
ฉันมีปัญหาที่คล้ายกัน แต่ด้วยการบิด สำหรับฉันปัญหาคือฉันไม่ได้ติดตั้งตาราง sql อย่างถูกต้อง เขตข้อมูลคีย์หลักของฉันไม่ได้ถูกตั้งค่าเป็นการเพิ่มอัตโนมัติ ดังนั้น EF จะส่งบันทึกฉันพยายามแทรก w / oa key ซึ่งไม่เป็นไรถ้าคุณจำบอก sql ว่าฟิลด์นั้นเป็นฟิลด์ Identity ที่เพิ่มขึ้นอัตโนมัติซึ่งฉันลืม: <
Agile Noob

1
ปัญหาเดียวกัน แต่ใช้คีย์ผสม ไม่ได้ตั้งค่าคีย์หนึ่งรายการ
obaylis

113

ว้าวคำตอบมากมาย แต่ฉันได้รับข้อผิดพลาดนี้เมื่อฉันทำสิ่งที่แตกต่างออกไปเล็กน้อยซึ่งไม่มีใครพูดถึง

เรื่องสั้น ๆ สั้น ๆ ถ้าคุณสร้างวัตถุใหม่และบอก EF ว่ามันถูกดัดแปลงโดยใช้EntityState.Modifiedแล้วมันจะโยนข้อผิดพลาดนี้เพราะมันยังไม่มีอยู่ในฐานข้อมูล นี่คือรหัสของฉัน:

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);

ขอขอบคุณที่โพสต์สิ่งนี้ นั่นเป็นปัญหาของฉันเช่นกันฉันได้คัดลอกโค้ดบางส่วนที่ตั้งค่าสถานะเป็น EntityState.Modified
clayRay

23

ฉันกำลังเผชิญกับข้อผิดพลาดที่น่ากลัวนี้ ... :) จากนั้นฉันก็รู้ว่าฉันลืมที่จะตั้ง

@Html.HiddenFor(model => model.UserProfile.UserId)

สำหรับคีย์หลักของวัตถุที่กำลังอัปเดต! ฉันมักจะลืมสิ่งนี้ง่าย ๆ แต่สิ่งที่สำคัญมาก!

โดยวิธีการ: HiddenForสำหรับ ASP.NET MVC


3
ดูเหมือนว่าข้อบกพร่องด้านความปลอดภัยในการจัดเก็บUserIdในรูปแบบมีแนวโน้มที่จะแฮ็กเกอร์ ... นี้ควรจะมีประชากรหลังจากนั้นHttpContext.Current.User.Identity.Name
Serj Sagan

@SerjSagan คุณถูกต้อง ... แต่ตราบใดที่คุณตรวจสอบฝั่งเซิร์ฟเวอร์เพื่อยืนยันชื่อผู้ใช้และชื่อผู้ใช้ปัจจุบันคุณก็พร้อมใช้งาน
Leniel Maccaferri

1
ประเด็นของฉันคือทำไมถึงต้องเก็บไว้ในที่ที่HiddenForคุณจะต้องเอามันออกมาจากไหนHttpContext... ฉันจะไม่ใส่คุณสมบัตินี้ในแบบฟอร์มเลยซึ่งจะบังคับให้ฉันเติมด้านเซิร์ฟเวอร์เสมอ ...
Serj Sagan

16

ตรวจสอบว่าคุณลืมแอตทริบิวต์ "DataKeyNames" ใน GridView มันเป็นสิ่งที่จำเป็นเมื่อทำการแก้ไขข้อมูลภายใน GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx


+1 โซลูชั่นที่สมบูรณ์แบบและเรียบง่ายสำหรับฉัน ฉันเชื่อมโยง GridView กับ EntityDataSource และไม่ได้ตั้งค่านี้เป็นคีย์หลักของฉันบนวัตถุ
Andez

เรารู้ว่า Kendo UI ไม่สนับสนุนคีย์ผสม แต่ในกรณีที่ฉันเพิ่มคอลัมน์ใหม่ที่ต่อแป้นของฉันเข้ากับหนึ่งแล้วเกิดอะไรขึ้น
Branislav

15

ปัญหาเกิดจากสิ่งใดสิ่งหนึ่งในสองสิ่ง: -

  1. คุณพยายามอัปเดตแถวที่มีคุณสมบัติอย่างน้อยหนึ่งรายการConcurrency Mode: Fixed.. และการเกิดขึ้นพร้อมกันในแง่ดีทำให้ไม่สามารถบันทึกข้อมูลได้ กล่าวคือ บางคนเปลี่ยนข้อมูลแถวระหว่างเวลาที่คุณได้รับข้อมูลเซิร์ฟเวอร์และเมื่อคุณบันทึกข้อมูลเซิร์ฟเวอร์ของคุณ
  2. คุณพยายามอัปเดตหรือลบแถว แต่ไม่มีแถวอยู่ อีกตัวอย่างหนึ่งของคนที่เปลี่ยนข้อมูล (ในกรณีนี้การลบ) ในระหว่างการเรียกคืนและบันทึกหรือคุณแบนเราพยายามที่จะอัปเดตเขตข้อมูลที่ไม่ใช่ตัวตน (เช่น. StoreGeneratedPattern = Computed) และแถวนั้นไม่มีอยู่

1
สิ่งนี้อาจเกิดขึ้นได้หากคุณสมบัติของวัตถุทั้งหมดที่ได้รับมอบหมายมีการกำหนดค่าเดียวกันกับที่เคยมีมาก่อน
Serj Sagan

+1 สำหรับอันที่สอง ฉันมี StoreGeneratedPattern = ไม่มีการเปลี่ยนเป็น StoreGeneratedPattern = ตัวตนได้รับการแก้ไขปัญหา ขอบคุณ
tkt986

12

ฉันได้รับข้อผิดพลาดเดียวกันนี้เนื่องจากส่วนหนึ่งของ PK เป็นคอลัมน์วันที่และการบันทึกที่ถูกแทรกใช้ DateTime ตอนนี้เป็นค่าสำหรับคอลัมน์นั้น เฟรมเวิร์กเอนทิตีจะแทรกค่าด้วยความแม่นยำมิลลิวินาทีแล้วมองหาค่าที่เพิ่งแทรกด้วยความแม่นยำมิลลิวินาที อย่างไรก็ตาม SqlServer มีการปัดเศษค่าเป็นความแม่นยำที่สองและดังนั้นเฟรมเวิร์กเอนทิตีไม่สามารถค้นหาค่าความแม่นยำมิลลิวินาที

การแก้ปัญหาคือการตัดทอนมิลลิวินาทีจาก DateTime ตอนนี้ก่อนที่จะแทรก


2
เรามีปัญหาเดียวกันยกเว้นเราแทรกเข้าไปในDateคอลัมน์ที่มีDateTimeค่า
adam0101

1
กันที่นี่ เรามีบันทึกคลังข้อมูลและใช้การประทับเวลาเป็นส่วนหนึ่งของคีย์ การประทับเวลาในคลังข้อมูลคือ SQL DateTime แต่การประทับเวลาใน C # ไม่ตรงกัน ฉันเปลี่ยนชนิดข้อมูล SQL เป็น DateTime2 (7) อัปเดตโมเดล EF และแก้ไขทั้งหมดแล้ว
mmcfly

การเปลี่ยนคอลัมน์เป็น Datetime2 (7) ก็เหมาะกับฉันเช่นกัน ขอบคุณ @mmcfly
Dzejms

10

ฉันมีปัญหาเดียวกันและคำตอบของ @ webtrifusion ช่วยหาวิธีแก้ปัญหา

โมเดลของฉันใช้Bind(Exclude)แอตทริบิวต์ใน ID ของเอนทิตีซึ่งทำให้ค่าของ ID เอนทิตีเป็นศูนย์ใน HttpPost

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; }
    }
}   

ปัญหาที่คล้ายกันเพื่อเหตุผลด้านความปลอดภัยฉันมีการผูก (รวม = บางฟิลด์) ID ไม่ได้อยู่ในรายการ นอกจากนี้ฉันเพิ่มมันเป็นอินพุตที่ซ่อนอยู่ จะต้องลบสิ่งที่สร้างขึ้นโดย MVC หรือ ID ไม่ได้อยู่ที่นั่นเลย ขอบคุณสำหรับความช่วยเหลือ
MusicAndCode

10

ฉันมีปัญหาเดียวกันฉันคิดว่าเกิดจาก RowVersion ซึ่งเป็นโมฆะ ตรวจสอบว่าคุณIdของคุณและRowVersionมีความไม่เป็นโมฆะ

สำหรับข้อมูลเพิ่มเติมดูที่บทช่วยสอนนี้

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application


รุ่นแถวเป็นโมฆะในกรณีของฉัน
Prakash

ในกรณีของฉันฉันได้ลบฟิลด์รหัสใน [Bind (รวม = คุณสมบัติ) ของฉันออกโดยไม่ได้ตั้งใจ เพิ่มกลับและทำงานได้ดี
Caverman

8

ฉันเริ่มได้รับข้อผิดพลาดนี้หลังจากเปลี่ยนจาก model-first เป็น code-first ฉันมีหลายกระทู้ที่ปรับปรุงฐานข้อมูลซึ่งบางคนอาจปรับปรุงแถวเดียวกัน ฉันไม่รู้ว่าทำไมฉันจึงไม่มีปัญหาในการใช้แบบจำลองก่อนสมมติว่ามันใช้ค่าเริ่มต้นที่เห็นพ้องกัน

เพื่อจัดการกับมันในที่เดียวที่รู้ถึงเงื่อนไขที่อาจเกิดขึ้นฉันได้เพิ่มโอเวอร์โหลดต่อไปนี้ในคลาส 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)ใช้ได้ทุกที่


1
ตกลงคนอื่น ๆ กำลังอ่านเกี่ยวกับปัญหานี้แสดงให้เห็นว่าพวกเขาสามารถเปิดใช้งานได้อย่างไร แต่คำตอบนี้มีคำตอบที่ดี ฉันใช้รูปแบบการอัปเดตต่อเนื่อง (ไม่มีปุ่มบันทึกที่นี่ที่รัก) และได้รับสิ่งนี้ในการอัปเดตกริดเมื่อเธรด EF ล้มเหลวและแก้ไขมัน งานที่ยอดเยี่ยมชื่อที่ดีของฉัน .. คุณทำให้ฉันดูเหมือนเป็นฮีโร่ - ยืนอยู่บนไหล่ของยักษ์ !!
Tony Trembath-Drake

ช่วยฉันด้วยดูที่นี่เพื่อดูตัวเลือกเพิ่มเติม
Zvi Redler

7

คุณต้องรวม BoundField ของคีย์หลักอย่างชัดเจน หากคุณไม่ต้องการให้ผู้ใช้เห็นคีย์หลักคุณต้องซ่อนมันผ่าน css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

โดยที่ 'ซ่อน' เป็นคลาสใน css ที่ตั้งค่าการแสดงผลเป็น 'none'


1
ใช่คุณทำให้ฉันรู้สึกว่าฉันลบฟิลด์ id ที่ซ่อนอยู่ใน ASP.NET MVC ขอบคุณ @Paulo! :)
Tomasz Iniewicz

7

ในขณะที่แก้ไขรวมถึงรหัสหรือคีย์หลักของกิจการเป็นเขตข้อมูลที่ซ่อนอยู่ในมุมมอง

กล่าวคือ

      @Html.HiddenFor(m => m.Id)

ที่แก้ปัญหา

นอกจากนี้หากโมเดลของคุณมีรายการที่ไม่ได้ใช้ก็รวมไว้ด้วยและโพสต์สิ่งนั้นลงในคอนโทรลเลอร์


7

ฉันเจอข้อผิดพลาดนี้ด้วย ปัญหาที่เกิดขึ้นนั้นเกิดจาก Trigger บนโต๊ะที่ฉันพยายามบันทึก ทริกเกอร์ใช้ 'INSTEAD OF INSERT' ซึ่งหมายถึง 0 แถวที่เคยแทรกเข้าไปในตารางนั้นดังนั้นข้อผิดพลาด โชคดีที่ในกรณีที่ฟังก์ชันทริกเกอร์ไม่ถูกต้อง แต่ฉันคิดว่ามันอาจเป็นการทำงานที่ถูกต้องที่ควรจัดการในโค้ด หวังว่านี่จะช่วยใครซักคนในหนึ่งวัน


2
สามารถหลอกให้เอนทิตีเชื่อว่ามีการเพิ่มแถวโดยส่งกลับคำสั่ง SELECT (พร้อมคอลัมน์คีย์หลัก) จากทริกเกอร์
jahu

1
หากต้องการขยายความคิดเห็นโดย @jahu ฉันต้องได้รับ id จริงของไอเท็มที่เพิ่งแทรกใหม่เพื่อส่งคืนจากทริกเกอร์ของฉันและชื่อคอลัมน์ต้องตรงกับคอลัมน์ข้อมูลประจำตัวของตารางทริกเกอร์ (ในกรณีของฉันจริง ๆ แล้วเป็นมุมมอง ไม่มีตัวตนของตัวเอง แต่ฉันหลอก edmx ให้เชื่อว่ามันทำ) ทริกเกอร์ของฉันกำลังแทรกลงในตารางที่แยกต่างหากดังนั้นฉันเพิ่งเพิ่มบรรทัดสุดท้ายในทริกเกอร์ของฉัน:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister

โปรดดูคำถามนี้: stackoverflow.com/questions/5820992/…
J. Polfer

ในกรณีของฉันฉันกำลังทำการลบในเอนทิตีในคอลเลกชันลูก แต่มีทริกเกอร์ในการลบสำหรับเอนทิตีลูกใดอันหนึ่งที่ทำให้เอนทิตีลูกอื่นถูกลบ สิ่งนี้ทำให้เกิดข้อผิดพลาดเนื่องจากแถว N - 1 ได้รับผลกระทบเนื่องจากทริกเกอร์ลบหนึ่งในเอนทิตีชายด์เองก่อนเฟรมเวิร์กเอนทิตีพยายามลบ
skeletank

6

ฉันเจอปัญหานี้ในตารางที่ไม่มีคีย์หลักและมีคอลัมน์ DATETIME (2, 3) (ดังนั้นคีย์หลักของเอนทิตีคือการรวมกันของคอลัมน์ทั้งหมด) ... เมื่อทำการแทรกเวลา เวลาที่แม่นยำยิ่งขึ้น (2018-03-20 08: 29: 51.8319154) ที่ถูกตัดทอนเป็น (2018-03-20 08: 29: 51.832) ดังนั้นการค้นหาในเขตข้อมูลคีย์จึงล้มเหลว


5

ฉันยังมีข้อผิดพลาดนี้ มีบางสถานการณ์ที่เอนทิตีอาจไม่ได้รับรู้ถึงบริบทฐานข้อมูลจริงที่คุณใช้หรือรุ่นอาจแตกต่างกัน สำหรับสิ่งนี้ตั้ง: EntityState.Modified; เพื่อ EntityState.Added;

เพื่อทำสิ่งนี้:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

สิ่งนี้จะทำให้มั่นใจได้ว่านิติบุคคลรู้ว่าคุณกำลังใช้หรือเพิ่มสถานะที่คุณกำลังทำงาน ณ จุดนี้จำเป็นต้องตั้งค่ารุ่นที่ถูกต้องทั้งหมด ระวังอย่าทำให้การเปลี่ยนแปลงที่เกิดขึ้นในพื้นหลังหลวม

หวังว่านี่จะช่วยได้


1
คุณเป็นกูรู! มันใช้งานได้สำหรับฉัน!
Hernaldo Gonzalez

5
  @Html.HiddenFor(model => model.RowVersion)

การสลับแถวของฉันเป็นโมฆะดังนั้นต้องเพิ่มสิ่งนี้ลงในมุมมองที่แก้ไขปัญหาของฉันได้


ไม่ผ่าน RowVersion จากมุมมองไปยังการแก้ไขการกระทำรวมทั้งฉันลืมที่จะทำแบบจำลองที่มีผลผูกพันกับ RowVersion ในเวลาที่คุณบันทึกวัตถุเป็น db คุณต้องมีค่าก่อนหน้าของ RowVersion ที่ส่งไปยัง db พร้อมกับวัตถุสำหรับการตรวจสอบพร้อมกัน คุณทำผิดพลาดเมื่อคุณต้องการสิ่งต่าง ๆ เร็วขึ้น!
Dhanuka777

5

บรรทัด[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]ใช้กลอุบายในกรณีของฉัน:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }

4

เพียงตรวจสอบให้แน่ใจว่าทั้งตารางและแบบฟอร์มมีคีย์หลักและอัปเดต edmx

ฉันพบว่าข้อผิดพลาดระหว่างการอัปเดตมักเป็นเพราะ: - ไม่มีคีย์หลักในตาราง - ไม่มีคีย์หลักในมุมมองแก้ไข / ฟอร์ม (เช่น@Html.HiddenFor(m=>m.Id)


4

ผมมีปัญหาเหมือนกัน. ในกรณีของฉันฉันพยายามอัปเดตคีย์หลักซึ่งไม่ได้รับอนุญาต


4

ฉันได้รับข้อผิดพลาดนี้เป็นระยะเมื่อใช้ 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();
}

แม้ว่าสิ่งนี้จะแก้ไขปัญหาของฉันได้ แต่มันก็ชี้ไปที่ปัญหาพื้นฐานที่กล่าวถึงก่อนหน้าในโพสต์นี้เกี่ยวกับรุ่น PKs & Row ฉันละเลยที่จะเพิ่มแผนที่สคีมาสำหรับตารางใหม่ที่ซับซ้อนยิ่งขึ้นเนื่องจากความจริงที่ว่า PK ไม่ปฏิบัติตามกฎการตั้งชื่อ <ชื่อตาราง> รหัส
midohioboarder

3

ฉันพบข้อผิดพลาดเมื่อฉันลบบางแถวใน DB (ในลูป) และการเพิ่มแถวใหม่ในตารางเดียวกัน

วิธีแก้ปัญหาสำหรับฉันคือการสร้างบริบทใหม่ในการวนซ้ำแต่ละรอบ


ฉันต้องทำสิ่งเดียวกันยังไม่แน่ใจว่าทำไมปัญหาเกิดขึ้นตั้งแต่แรก แต่ใช้งานได้
Jed Grant

3
    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();
                }
        }
    }

คุณช่วยอธิบายได้อย่างชัดเจนว่านี่หมายถึงอะไรและ ObjectStateManager คืออะไร ฉันกำลังลองสิ่งนี้ในคลาสที่เก็บฐานของเรา แต่ได้รับข้อผิดพลาด
นาโอมิ

3

สิ่งนี้จะเกิดขึ้นหากคุณพยายามแทรกลงในสถานการณ์ที่มีข้อ จำกัด ที่ไม่เหมือนใครเช่นถ้าคุณมีที่อยู่เพียงประเภทเดียวต่อนายจ้างและคุณพยายามแทรกวินาทีที่สองประเภทเดียวกันกับนายจ้างคนเดียวกันคุณจะได้รับปัญหาเดียวกัน .

หรือ

สิ่งนี้อาจเกิดขึ้นได้หากคุณสมบัติของวัตถุทั้งหมดที่กำหนดให้พวกเขาถูกกำหนดด้วยค่าเดียวกันกับที่เคยมีมาก่อน

        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
        }

2

หากคุณพยายามสร้างการแมปในไฟล์ edmx ของคุณไปที่ "function Imports" สิ่งนี้อาจส่งผลให้เกิดข้อผิดพลาดนี้ เพียงแค่ล้างฟิลด์สำหรับแทรกอัปเดตและลบที่อยู่ในรายละเอียดการแมปสำหรับเอนทิตีที่กำหนดใน edmx ของคุณและควรจะทำงานได้ ฉันหวังว่าฉันจะทำให้มันชัดเจน


2

ฉันได้รับข้อยกเว้นนี้เมื่อติดวัตถุที่ไม่มีอยู่ในฐานข้อมูล ฉันคิดว่าวัตถุถูกโหลดจากบริบทที่แยกต่างหาก แต่ถ้าเป็นครั้งแรกที่ผู้ใช้เข้าชมเว็บไซต์วัตถุนั้นจะถูกสร้างขึ้นใหม่ เรามีคีย์หลักที่เพิ่มขึ้นโดยอัตโนมัติดังนั้นฉันสามารถแทนที่

context.Users.Attach(orderer);

กับ

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}

2

ฉันมีปัญหาเดียวกันนี้ แต่นี่เป็นเพราะความผิดพลาดของฉันเอง ที่จริงฉันบันทึกวัตถุแทนการเพิ่ม ดังนั้นนี่คือความขัดแย้ง


2

วิธีหนึ่งในการแก้ไขปัญหานี้ในสภาพแวดล้อมของ sql server คือการใช้ตัวสร้างโปรไฟล์ sql ที่มาพร้อมกับสำเนาของ SqlServer ของคุณหรือหากใช้เวอร์ชัน Express รับสำเนาของตัวสร้างโปรไฟล์ด่วนฟรีจาก CodePlex ตามลิงค์ด้านล่าง:

Express Profiler

ด้วยการใช้ Sql Profiler คุณสามารถเข้าถึงสิ่งที่ EF ถูกส่งไปยังฐานข้อมูล ในกรณีของฉันนี้รวมถึง:

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 รายการได้รับผลกระทบจากแบบสอบถามนี้

ในกรณีของฉันปัญหาเกิดจาก CategoryID

ไม่มี CategoryID ที่ระบุโดย ID EF ที่ส่งไปยังฐานข้อมูลดังนั้น 0 บันทึกที่ได้รับผลกระทบ

นี่ไม่ใช่ความผิดของ EF แต่เป็นความผิดพลาดที่เกิดจากการรวมตัวกัน "?" ทำรายการคำสั่งใน View Controller ที่ส่งข้อมูลไร้สาระไปยังระดับข้อมูล


2

ไม่มีคำตอบข้างต้นค่อนข้างครอบคลุมสถานการณ์ของฉันและการแก้ปัญหาไป

รหัสที่เกิดข้อผิดพลาดในคอนโทรลเลอร์ MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

ฉันได้รับข้อยกเว้นนี้เมื่อฉันบันทึกวัตถุจากมุมมองแก้ไข เหตุผลที่ทำให้มันเป็นเพราะเมื่อฉันกลับไปบันทึกฉันได้ปรับเปลี่ยนคุณสมบัติที่เกิดขึ้นเป็นคีย์หลักบนวัตถุ ดังนั้นการตั้งค่าสถานะเป็น Modified จึงไม่สมเหตุสมผลกับ EF - เป็นรายการใหม่ไม่ใช่รายการที่บันทึกไว้ก่อนหน้านี้

คุณสามารถแก้ไขได้โดย A) การแก้ไขการบันทึกการโทรเพื่อเพิ่มวัตถุหรือ B) เพียงแค่ไม่เปลี่ยนคีย์หลักในการแก้ไข ฉันทำ B)


2

เมื่อคำตอบที่ยอมรับตอบว่า " มันจะไม่จบลงด้วยการเปลี่ยนแปลงที่แอปพลิเคชันของคุณไม่ทราบว่าเกิดขึ้น " ฉันถูกสงสัยเพราะวัตถุของฉันถูกสร้างขึ้นใหม่ แต่มันกลับกลายเป็นว่ามีINSTEAD OF UPDATE, INSERT- TRIGGERแนบมากับตารางซึ่งกำลังอัพเดทคอลัมน์จากการคำนวณของตารางเดียวกัน

เมื่อฉันเปลี่ยนสิ่งนี้เป็นAFTER INSERT, UPDATEมันทำงานได้ดี


2

สิ่งนี้เกิดขึ้นกับฉันเนื่องจากความไม่ตรงกันระหว่างวันที่และเวลาและวันที่ 2 น่าแปลกที่มันทำงานได้ดีก่อนที่ผู้ทดสอบจะค้นพบปัญหา รหัสรุ่นแรกของฉันรวม 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))

เนื่องจากพยายามจับคู่คอลัมน์วันที่และเวลากับค่าวันที่และเวลาจึงไม่ส่งคืนผลลัพธ์ ทางออกเดียวที่ฉันคิดได้คือเปลี่ยนคอลัมน์เป็น datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

1
ความแปลกหน้าของมันทำงานกับไม่ได้ทำงานจะทำอย่างไรกับพื้นฐานรูปแบบ / ฐานของเทียบกับdatetime datetime2โดยพื้นฐานแล้วค่ามิลลิวินาทีบางส่วนจะประเมินเป็นคู่ แต่บางค่าจะไม่ตรงกัน DateTime2สิ่งเดียวกันที่เกิดขึ้นกับผมและผมก็เปลี่ยนไป
xr280xr

+1 ฉันหวังว่าฉันจะได้ +100 สำหรับคุณนี้ ในที่สุดฉันก็พบสิ่งนี้และตระหนักว่าจริงๆแล้วฉันมี Datetime เป็นส่วนหนึ่งของคีย์หลักของฉัน ใช่นี่แน่นอนมันแก้ไข ฉันอัปเดตคอลัมน์เป็น Datetime2 และใช้งานได้ ตอนนี้เนื้อของฉันอยู่กับ Entity Framework สำหรับคิดคำเส็งเคร็งซึ่งมันบังคับให้ฉันทำสิ่งนี้
Catchops
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.