ASP.NET MVC - การแนบเอนทิตีประเภท 'MODELNAME' ล้มเหลวเนื่องจากเอนทิตีอื่นประเภทเดียวกันมีค่าคีย์หลักเดียวกันอยู่แล้ว


122

สรุปได้ว่ามีข้อยกเว้นเกิดขึ้นระหว่างการโพสต์โมเดล wrapper และเปลี่ยนสถานะของรายการหนึ่งเป็น 'Modified' ก่อนที่จะเปลี่ยนสถานะสถานะจะถูกตั้งค่าเป็น 'แยกออก' แต่การเรียก Attach () จะทำให้เกิดข้อผิดพลาดเดียวกัน ฉันใช้ EF6

โปรดค้นหารหัสของฉันด้านล่าง (ชื่อรุ่นถูกเปลี่ยนเพื่อให้อ่านง่ายขึ้น)

แบบ

// Wrapper classes
        public class AViewModel
        {
            public A a { get; set; }
            public List<B> b { get; set; }
            public C c { get; set; }
        }   

ตัวควบคุม

        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            if (!canUserAccessA(id.Value))
                return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

            var aViewModel = new AViewModel();
            aViewModel.A = db.As.Find(id);

            if (aViewModel.Receipt == null)
            {
                return HttpNotFound();
            }

            aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
            aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();

            return View(aViewModel);
        }

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(AViewModel aViewModel)
        {
            if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
                return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

            if (ModelState.IsValid)
            {
                db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(aViewModel);
        }

ดังที่แสดงไว้ด้านบนบรรทัด

db.Entry(aViewModel.a).State = EntityState.Modified;

โยนข้อยกเว้น:

การแนบเอนทิตีประเภท 'A' ล้มเหลวเนื่องจากเอนทิตีประเภทเดียวกันมีค่าคีย์หลักเดียวกันอยู่แล้ว สิ่งนี้สามารถเกิดขึ้นได้เมื่อใช้เมธอด "แนบ" หรือตั้งค่าสถานะของเอนทิตีเป็น "ไม่เปลี่ยนแปลง" หรือ "แก้ไข" หากเอนทิตีใด ๆ ในกราฟมีค่าคีย์ที่ขัดแย้งกัน อาจเป็นเพราะเอนทิตีบางรายการยังใหม่และยังไม่ได้รับค่าคีย์ที่สร้างจากฐานข้อมูล ในกรณีนี้ให้ใช้เมธอด "เพิ่ม" หรือสถานะเอนทิตี "เพิ่ม" เพื่อติดตามกราฟจากนั้นตั้งค่าสถานะของเอนทิตีที่ไม่ใช่ใหม่เป็น "ไม่เปลี่ยนแปลง" หรือ "แก้ไข" ตามความเหมาะสม

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


คุณได้ลองแนบเอนทิตีของคุณก่อนตั้งค่าEntityStateหรือไม่ เนื่องจากเอนทิตีของคุณมาจากคำขอโพสต์จึงไม่ควรติดตามโดยบริบทปัจจุบันฉันเดาว่า บริษัท พิจารณาว่าคุณพยายามเพิ่มรายการที่มี ID ที่มีอยู่
Réda Mattar

ฉันได้ลองสิ่งนี้แล้วและผลลัพธ์ก็เหมือนกันทุกประการ :( ด้วยเหตุผลบางประการในบริบทที่คิดว่าฉันกำลังสร้างรายการใหม่ แต่ฉันเพิ่งอัปเดตรายการที่มีอยู่ ...
Chris Ciszak

ฉันตรวจสอบสถานะของ 'a' ก่อนที่จะเกิดข้อผิดพลาดและสถานะของวัตถุนี้คือ 'แยกออก' แต่เรียก db As.Attach (aViewModel.a) ส่งข้อความเดียวกันทั้งหมดหรือไม่ ความคิดใด ๆ ?
Chris Ciszak

5
ฉันเพิ่งเห็นการอัปเดตของคุณคุณตั้งค่าขอบเขตอายุบริบทของคุณอย่างไร เป็นต่อคำขอหรือไม่? หากdbอินสแตนซ์เหมือนกันระหว่างการกระทำทั้งสองของคุณก็สามารถอธิบายปัญหาของคุณได้เนื่องจากรายการของคุณโหลดโดยเมธอด GET (จากนั้นติดตามโดยบริบท) และอาจไม่รู้จักอินสแตนซ์ในวิธีการ POST ของคุณเนื่องจากเอนทิตีดึงมาก่อน .
Réda Mattar

1
ไม่canUserAccessA()โหลดกิจการโดยตรงหรือเป็นความสัมพันธ์ของ entitiy อีกหรือไม่?
CodeCaster

คำตอบ:


155

แก้ไขปัญหา!

Attachวิธีนี้อาจช่วยใครบางคนได้ แต่จะไม่ช่วยในสถานการณ์นี้เนื่องจากเอกสารกำลังถูกติดตามอยู่แล้วในขณะที่โหลดในฟังก์ชันตัวควบคุมแก้ไข GET สิ่งที่แนบมาจะทำให้เกิดข้อผิดพลาดเดียวกัน

ปัญหาที่ฉันพบที่นี่เกิดจากฟังก์ชันcanUserAccessA()ที่โหลดเอนทิตี A ก่อนอัปเดตสถานะของวัตถุก. Detachedนี้ได้รับการกวดขันขึ้นนิติบุคคลติดตามและมันก็เปลี่ยนสถานะของวัตถุที่จะ

วิธีแก้ไขคือแก้ไขcanUserAccessA()เพื่อไม่ให้ติดตามวัตถุที่ฉันกำลังโหลด AsNoTracking()ควรเรียกใช้ฟังก์ชันขณะสอบถามบริบท

// User -> Receipt validation
private bool canUserAccessA(int aID)
{
    int userID = WebSecurity.GetUserId(User.Identity.Name);
    int aFound = db.Model.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();

    return (aFound > 0); //if aFound > 0, then return true, else return false.
}

ด้วยเหตุผลบางอย่างฉันไม่สามารถใช้.Find(aID)ด้วยได้AsNoTracking()แต่มันก็ไม่สำคัญเท่าที่ฉันสามารถทำได้โดยการเปลี่ยนแบบสอบถาม

หวังว่านี่จะช่วยทุกคนที่มีปัญหาคล้าย ๆ กัน!


10
เล็กน้อยและมีประสิทธิภาพมากขึ้น: if (dbAs AsNoTracking (). Any (x => x.aID == aID && x.UserID == userID))
เบรนต์

11
หมายเหตุ: คุณจำเป็นต้องใช้using System.Data.Entity; AsNoTracking()
Maxime

ในกรณีของฉันอัปเดตเฉพาะฟิลด์ยกเว้นรหัสเอนทิตีทำงานได้ดี: var entity = context.Find (entity_id); entity.someProperty = newValue; context.Entry (เอนทิตี) .Property (x => x.someProperty) .IsModified = true; context.SaveChanges ();
Anton Lyhin

3
ความช่วยเหลือมากมาย ฉันเพิ่ม. AsNoTracking () ก่อน FirstOrDefault () ของฉันและมันใช้งานได้
coggicc

110

ที่น่าสนใจ:

_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);

หรือถ้าคุณยังไม่ใช่คนทั่วไป:

_dbContext.Set<UserEntity>().AddOrUpdate(entityToBeUpdatedWithId);

ดูเหมือนจะแก้ปัญหาได้อย่างราบรื่น


1
เยี่ยมมากที่ทำงานได้อย่างสมบูรณ์แบบในสถานการณ์ของฉันที่ฉันต้องการอัปเดตเรกคอร์ดหลายรายการด้วยตารางการเข้าร่วมที่กำหนดเองในแอปที่ไม่ได้เชื่อมต่อ แม้ว่าเอนทิตีจะถูกดึงจากฐานข้อมูล แต่ฉันก็ได้รับข้อผิดพลาดในการอ้างอิง ฯลฯ ฉันกำลังใช้ "context.Entry (score) .State = System.Data.Entity.EntityState.Modified;" แต่สุดท้ายก็ใช้ได้! ขอบคุณ!!
firecape

5
นี้ได้ผล คำแนะนำอื่น ๆ ทั้งหมดเกี่ยวกับการแนบและการใช้ notracking ล้มเหลวเนื่องจากฉันทำ noTracking อยู่แล้ว ขอบคุณสำหรับการแก้ปัญหา
Khainestar

3
นี้ทำงานสำหรับฉันในขณะที่การอัปเดตผู้ปกครองและเด็กหน่วยงานภายในหน่วยเดียวกันในการทำงาน ขอบคุณมาก
Ian

55
สำหรับใครก็ตามที่กำลังมองหาAddOrUpdateเป็นวิธีการขยายในSystem.Data.Entity.Migrationsเนมสเปซ
นิค

1
@Artyomska น่าเสียดายที่ฉันไม่รู้จัก
guneysus

15

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

แทนที่จะตั้งค่าสถานะโดยตรงให้ลองทำสิ่งต่อไปนี้:

//db.Entry(aViewModel.a).State = EntityState.Modified;
db.As.Attach(aViewModel.a); 
db.SaveChanges();

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

ปรับปรุง:

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

นี่คือคำอธิบายเพิ่มเติม:

http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/


3
สวัสดี Kaspars ขอบคุณสำหรับการป้อนข้อมูล วิธีการแนบแสดงข้อผิดพลาดเดียวกันกับที่กล่าวถึงในคำถามของฉัน ปัญหาคือ canUserAccessA () ฟังก์ชั่นโหลดเอนทิตีเช่นเดียวกับ CodeCaster ที่สังเกตเห็นข้างต้น แต่บอกว่าฉันสนใจคำแนะนำของคุณเกี่ยวกับความปลอดภัยมาก คุณช่วยแนะนำได้ไหมว่าฉันควรทำอย่างไรเพื่อป้องกันพฤติกรรมดังกล่าว
Chris Ciszak

อัปเดตคำตอบของฉันพร้อมข้อมูลเพิ่มเติมเกี่ยวกับวิธีป้องกันช่องโหว่ด้านความปลอดภัย
Kaspars Ozols

13

ลองสิ่งนี้:

var local = yourDbContext.Set<YourModel>()
                         .Local
                         .FirstOrDefault(f => f.Id == yourModel.Id);
if (local != null)
{
  yourDbContext.Entry(local).State = EntityState.Detached;
}
yourDbContext.Entry(applicationModel).State = EntityState.Modified;

11

สำหรับฉันแล้วสำเนาในเครื่องคือต้นตอของปัญหา สิ่งนี้แก้ไขได้

var local = context.Set<Contact>().Local.FirstOrDefault(c => c.ContactId == contact.ContactId);
                if (local != null)
                {
                    context.Entry(local).State = EntityState.Detached;
                }

10

กรณีของฉันคือฉันไม่สามารถเข้าถึงบริบท EF โดยตรงจากแอป MVC ของฉัน

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

ตัวอย่างรหัส (นามธรรม):

MVC

public ActionResult(A a)
{
  A aa = repo.Find(...);
  // some logic
  repo.Detach(aa);
  repo.Update(a);
}

กรุ

void Update(A a)
{
   context.Entry(a).EntityState = EntityState.Modified;
   context.SaveChanges();
}

void Detach(A a)
{
   context.Entry(a).EntityState = EntityState.Detached;
}

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

3

ฉันคิดว่าฉันจะแบ่งปันประสบการณ์ของฉันเกี่ยวกับเรื่องนี้แม้ว่าฉันจะรู้สึกโง่เล็กน้อยที่ไม่รู้ตัวเร็วกว่านี้

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

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

การแก้ไขเป็นเพียงการเปลี่ยนที่เก็บจากการสร้างบริบทใหม่หนึ่งครั้งในตัวสร้างเป็นวิธีการต่อไปนี้:

    private DbContext GetDbContext()
    {
        return this.GetDbContext(false);
    }


    protected virtual DbContext GetDbContext(bool canUseCachedContext)
    {
        if (_dbContext != null)
        {
            if (canUseCachedContext)
            {
                return _dbContext;
            }
            else
            {
                _dbContext.Dispose();
            }
        }

        _dbContext = new ModelContext();

        return _dbContext;
    }

    #region IDisposable Members

    public void Dispose()
    {
        this.Dispose(true);
    }

    protected virtual void Dispose(bool isDisposing)
    {
        if (!_isDisposed)
        {
            if (isDisposing)
            {
                // Clear down managed resources.

                if (_dbContext != null)
                    _dbContext.Dispose();
            }

            _isDisposed = true;
        }
    }

    #endregion

สิ่งนี้ช่วยให้เมธอดที่เก็บสามารถรีเฟรชอินสแตนซ์บริบทของตนใหม่ตามการใช้งานแต่ละครั้งโดยการเรียกGetDbContextใช้หรือใช้อินสแตนซ์ก่อนหน้าหากต้องการโดยระบุ true


2

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

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

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

สิ่งที่ฉันรู้ในภายหลังคือฉันต้องอ่านบันทึกจากฐานข้อมูล:

Student student = db.Students.Find(s => s.StudentID == ViewModel.StudentID);

และอัปเดตวัตถุนี้ ทุกอย่างใช้งานได้แล้ว


2

ฉันมีปัญหากับ var ท้องถิ่นและฉันเพิ่งแยกมันออกดังนี้:

if (ModelState.IsValid)
{
    var old = db.Channel.Find(channel.Id);
    if (Request.Files.Count > 0)
    {
        HttpPostedFileBase objFiles = Request.Files[0];
        using (var binaryReader = new BinaryReader(objFiles.InputStream))
        {
            channel.GateImage = binaryReader.ReadBytes(objFiles.ContentLength);
        }

    }
    else
        channel.GateImage = old.GateImage;
    var cat = db.Category.Find(CatID);
    if (cat != null)
        channel.Category = cat;
    db.Entry(old).State = EntityState.Detached; // just added this line
    db.Entry(channel).State = EntityState.Modified;
    await db.SaveChangesAsync();
    return RedirectToAction("Index");
}
return View(channel);

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


@Artjom B ปัญหาสาเหตุของวัตถุที่โหลดด้วยคีย์เดียวกันดังนั้นก่อนอื่นเราจะถอดวัตถุนั้นออกและทำการอัปเดตเพื่อหลีกเลี่ยงความขัดแย้งระหว่างวัตถุสองชิ้นที่มีคีย์เดียวกัน
lvl4fi4

2

ฉันมีปัญหาที่คล้ายกันหลังจากตรวจสอบ 2-3 วันพบว่า ".AsNoTracking" ควรถูกลบออกเนื่องจาก EF ไม่ได้ติดตามการเปลี่ยนแปลงและถือว่าไม่มีการเปลี่ยนแปลงใด ๆ เว้นแต่จะแนบวัตถุ นอกจากนี้หากเราไม่ใช้. AsNoTracking EF จะรู้โดยอัตโนมัติว่าจะบันทึก / อัปเดตออบเจ็กต์ใดจึงไม่จำเป็นต้องใช้ Attach / Added



2

ฉันพบข้อผิดพลาดนี้ที่

  • สองวิธีคือ A & B ในตัวควบคุมเดียวทั้งสองใช้อินสแตนซ์เดียวกันของ ApplicationDbContext และ
  • วิธีการ A เรียกว่าวิธี B
    private ApplicationDbContext db;
    // api methods
    public JsonResult methodA(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return methodB()
    }

    public JsonResult methodB(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return new JsonResult();
    }

ฉันเปลี่ยนวิธี B ให้มีคำสั่งใช้และอาศัยเฉพาะdb2 ในเครื่อง หลังจาก:

    private ApplicationDbContext db;    
    // api methods    
    public JsonResult methodA(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return methodB()
    }

    public JsonResult methodB(string id){
        using (var db2 = new ApplicationDbContext())
        {
            Resource resource = db2.Resources.Find(id);
            db2.Entry(resource).State = EntityState.Modified;
            db2.SaveChanges();
        }
        return new JsonResult();
    }

1

คล้ายกับสิ่งที่ Luke Puplett พูดปัญหาอาจเกิดจากการกำจัดหรือสร้างบริบทของคุณไม่ถูกต้อง

ในกรณีของฉันฉันมีคลาสที่ยอมรับบริบทที่เรียกว่าContextService:

public class ContextService : IDisposable
{
    private Context _context;

    public void Dispose()
    {
        _context.Dispose();
    }
    public ContextService(Context context)
    {
        _context = context;
    }
//... do stuff with the context

บริการบริบทของฉันมีฟังก์ชันที่อัปเดตเอนทิตีโดยใช้อ็อบเจ็กต์เอนทิตีที่สร้างอินสแตนซ์:

        public void UpdateEntity(MyEntity myEntity, ICollection<int> ids)
        {
            var item = _context.Entry(myEntity);
            item.State = EntityState.Modified;
            item.Collection(x => x.RelatedEntities).Load();
            myEntity.RelatedEntities.Clear();
            foreach (var id in ids)
            {
                myEntity.RelatedEntities.Add(_context.RelatedEntities.Find(id));
            }
            _context.SaveChanges();
        }

ทั้งหมดนี้เป็นเรื่องปกติคอนโทรลเลอร์ของฉันที่ฉันเริ่มต้นบริการนั้นมีปัญหา แต่เดิมคอนโทรลเลอร์ของฉันมีลักษณะดังนี้:

    private static NotificationService _service = 
        new NotificationService(new NotificationContext());
    public void Dispose()
    {
    }

ฉันเปลี่ยนเป็นสิ่งนี้และข้อผิดพลาดหายไป:

    private static NotificationService _service;
    public TemplateController()
    {
        _service = new NotificationService(new NotificationContext());
    }
    public void Dispose()
    {
        _service.Dispose();
    }

1

ปัญหานี้อาจพบได้ในระหว่างViewModelการEntityModelทำแผนที่ (โดยใช้AutoMapperฯลฯ ) และการพยายามรวมcontext.Entry().Stateและcontext.SaveChanges()บล็อกการใช้งานดังที่แสดงด้านล่างจะช่วยแก้ปัญหาได้ โปรดทราบว่าcontext.SaveChanges()วิธีนี้ใช้สองครั้งแทนที่จะใช้หลังจากนั้นif-blockเนื่องจากต้องใช้บล็อกด้วย

public void Save(YourEntity entity)
{
    if (entity.Id == 0)
    {
        context.YourEntity.Add(entity);
        context.SaveChanges();
    }
    else
    {
        using (var context = new YourDbContext())
        {
            context.Entry(entity).State = EntityState.Modified;
            context.SaveChanges(); //Must be in using block
        }
    }            
}

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


1

นี่คือสิ่งที่ฉันทำในกรณีที่คล้ายกัน

สถานการณ์นั้นหมายความว่ามีเอนทิตีเดียวกันอยู่แล้วในบริบทดังนั้นการติดตามสามารถช่วยได้

ขั้นแรกให้ตรวจสอบจาก ChangeTracker ว่าเอนทิตีอยู่ในบริบทหรือไม่

var trackedEntries=GetContext().ChangeTracker.Entries<YourEntityType>().ToList();

var isAlreadyTracked =
                    trackedEntries.Any(trackedItem => trackedItem.Entity.Id ==myEntityToSave.Id);

ถ้ามีอยู่

  if (isAlreadyTracked)
            {
                myEntityToSave= trackedEntries.First(trackedItem => trackedItem.Entity.Id == myEntityToSave.Id).Entity;
            } 

else
{
//Attach or Modify depending on your needs
}

1

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

     ActivityEntity activity = new ActivityEntity();
      activity.name="vv";
    activity.ID = 22 ; //sample id
   var savedActivity = context.Activities.Find(22);

            if (savedActivity!=null)
            {
                context.Entry(savedActivity).State = EntityState.Detached;
                context.SaveChanges();

                activity.age= savedActivity.age;
                activity.marks= savedActivity.marks; 

                context.Entry(activity).State = EntityState.Modified;
                context.SaveChanges();
                return activity.ID;
            }

1

ฉันแก้ปัญหานี้ด้วยบล็อก "ใช้"

using (SqlConnection conn = new SqlConnection(connectionString))

    {

       // stuff to do with data base
    }

    // or if you are using entity framework 
    using (DataBaseEntity data = new DataBaseEntity)
{

    }

นี่คือที่ที่ฉันได้รับแนวคิดhttps://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum = vcses เป็นภาษาสเปน (ค้นหาคำตอบที่สอง)


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

1

คุณสามารถใช้วิธีการเพิ่มเช่น;

_dbContext.Entry(modelclassname).State = EntityState.Added;

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

_dbContext.Set<modelclassname>().AddOrUpdate(yourmodel);

0

ล้างสถานะทั้งหมด

dbContextGlobalERP.ChangeTracker.Entries () โดยที่ (e => e.Entity! = null) .ToList (). ForEach (e => e.State = EntityState.Detached);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.