इकाई वस्तु IEntityChangeTracker के कई उदाहरणों द्वारा संदर्भित नहीं की जा सकती। इकाई फ्रेमवर्क 4.1 में इकाई से संबंधित वस्तुओं को जोड़ने के दौरान


165

मैं कर्मचारी विवरणों को बचाने की कोशिश कर रहा हूं, जिसमें सिटी के संदर्भ हैं। लेकिन हर बार मैं अपने संपर्क को बचाने की कोशिश करता हूं, जो कि मान्य है मुझे अपवाद मिलता है "ADO.Net इकाई फ्रेमवर्क एक इकाई वस्तु को IEntityChangeTracker के कई उदाहरणों द्वारा संदर्भित नहीं किया जा सकता है"

मैंने बहुत सारी पोस्ट पढ़ी थी लेकिन फिर भी सही अंदाजा नहीं लग रहा था कि क्या करना है ... मेरा सेव बटन क्लिक कोड नीचे दिया गया है

protected void Button1_Click(object sender, EventArgs e)
    {
        EmployeeService es = new EmployeeService();
        CityService cs = new CityService();

        DateTime dt = new DateTime(2008, 12, 12);
        Payroll.Entities.Employee e1 = new Payroll.Entities.Employee();

        Payroll.Entities.City city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value));

        e1.Name = "Archana";
        e1.Title = "aaaa";
        e1.BirthDate = dt;
        e1.Gender = "F";
        e1.HireDate = dt;
        e1.MaritalStatus = "M";
        e1.City = city1;        

        es.AddEmpoyee(e1,city1);
    }

और कर्मचारी कोड

public string AddEmpoyee(Payroll.Entities.Employee e1, Payroll.Entities.City c1)
        {
            Payroll_DAO1 payrollDAO = new Payroll_DAO1();
            payrollDAO.AddToEmployee(e1);  //Here I am getting Error..
            payrollDAO.SaveChanges();
            return "SUCCESS";
        }

जवाबों:


241

क्योंकि ये दो लाइनें ...

EmployeeService es = new EmployeeService();
CityService cs = new CityService();

... कंस्ट्रक्टर में एक पैरामीटर न लें, मुझे लगता है कि आप कक्षाओं के भीतर एक संदर्भ बनाते हैं। जब आप लोड city1...

Payroll.Entities.City city1 = cs.SelectCity(...);

... आप city1संदर्भ में संलग्न करते हैं CityService। बाद में आप एक जोड़ने के city1नए के लिए एक संदर्भ के रूप में Employee e1और जोड़ने e1 के लिए इस संदर्भ सहितcity1 में संदर्भ के लिए EmployeeService। परिणामस्वरूप आप city1दो अलग-अलग संदर्भों से जुड़ गए हैं जो अपवाद के बारे में शिकायत करता है।

आप इसे सेवा वर्गों के बाहर एक संदर्भ बनाकर और इसे दोनों सेवाओं में इंजेक्ट और उपयोग करके ठीक कर सकते हैं:

EmployeeService es = new EmployeeService(context);
CityService cs = new CityService(context); // same context instance

आपकी सेवा कक्षाएं रिपॉजिटरी की तरह दिखती हैं जो केवल एक इकाई प्रकार के लिए जिम्मेदार हैं। ऐसे मामले में जब आप सेवाओं के लिए अलग-अलग संदर्भों का उपयोग करते हैं तो संस्थाओं के बीच संबंध शामिल होते ही आपको हमेशा परेशानी होगी।

आप एक एकल सेवा भी बना सकते हैं, जो एक EmployeeCityService(जो एक संदर्भ है) की तरह निकट से संबंधित संस्थाओं के एक सेट के लिए ज़िम्मेदार है और आपके ऑपरेशन में Button1_Clickइस सेवा की एक विधि के लिए पूरे ऑपरेशन को दर्शाता है।


4
मुझे यह पसंद है कि क्या आपने इसका पता लगाया, भले ही उत्तर में कुछ पृष्ठभूमि जानकारी शामिल न हो।
डैनियल Kmak

ऐसा लगता है कि यह मेरी समस्या को हल कर देगा, मुझे अभी पता नहीं है कि नया संदर्भ उदाहरण कैसे लिखें :(
Ortund

12
ओआरएम को सार करना एक हल्दी पर पीली लिपस्टिक लगाने जैसा है।
रोनी ओवरबी

मुझे यहां कुछ याद आ रहा है, लेकिन कुछ ORM (विशेष रूप से EntityFramework) में डेटा संदर्भ को हमेशा छोटा किया जाना चाहिए। एक स्थिर या पुन: उपयोग किए गए संदर्भ का परिचय चुनौतियों और समस्याओं के एक पूरे अन्य सेट को पेश करेगा।
Maritim

@Maritim यह उपयोग पर निर्भर करता है। वेब एप्लिकेशन में, इसका आम तौर पर एक राउंडट्रिप है। डेस्कटॉप एप्लिकेशन में, आप प्रति भी एक का उपयोग कर सकते हैं Form(क्या कभी, यह सिर्फ काम की एक इकाई का प्रतिनिधित्व करता है) प्रति Thread(क्योंकि DbContextथ्रेडसेफ़ होने की गारंटी नहीं है)।
लकी लिली

30

पुन: पेश करने के लिए कदम इसे सरल बनाया जा सकता है:

var contextOne = new EntityContext();
var contextTwo = new EntityContext();

var user = contextOne.Users.FirstOrDefault();

var group = new Group();
group.User = user;

contextTwo.Groups.Add(group);
contextTwo.SaveChanges();

त्रुटि के बिना कोड:

var context = new EntityContext();

var user = context.Users.FirstOrDefault();

var group = new Group();
group.User = user; // Be careful when you set entity properties. 
// Be sure that all objects came from the same context

context.Groups.Add(group);
context.SaveChanges();

केवल एक का उपयोग EntityContextकरने से यह हल हो सकता है। अन्य समाधानों के लिए अन्य उत्तरों का संदर्भ लें।


2
आपको संदर्भ का उपयोग करने की इच्छा है? (शायद गुंजाइश के मुद्दों या कुछ के कारण) आप संदर्भ से कैसे अलग हो सकते हैं और संदर्भ से जुड़ सकते हैं?
NullVoxPopuli

यदि आपको इस तरह से एसएमएस करने की आवश्यकता है, तो सबसे अधिक संभावना है कि आप इसे गलत तरीके से कर रहे हैं ... मैं एक संदर्भ का उपयोग करने का सुझाव देता हूं।
पावेल श्लेनिक

3
ऐसे उदाहरण हैं जहां आप एक अलग उदाहरण का उपयोग करना चाहते हैं, जैसे कि एक अलग डेटाबेस में इंगित करते समय।
Jay

1
यह समस्या का एक सहायक सरलीकरण है; लेकिन यह एक वास्तविक उत्तर प्रदान नहीं करता है।
ब्रेनस्लग्स83

9

यह एक पुराना धागा है, लेकिन एक अन्य समाधान, जिसे मैं पसंद करता हूं, बस सिटी अपडेट करना है और होल मॉडल सिटी को कर्मचारी को असाइन नहीं करना है ... ऐसा करने के लिए कि कर्मचारी को दिखना चाहिए:

public class Employee{
    ...
    public int? CityId; //The ? is for allow City nullable
    public virtual City City;
}

तब यह पर्याप्त काम कर रहा है:

e1.CityId=city1.ID;

5

वैकल्पिक रूप से इंजेक्शन और इससे भी बदतर सिंगलटन, आप Add से पहले Detach विधि को कॉल कर सकते हैं ।

EntityFramework 6: ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);

EntityFramework 4: cs.Detach(city1);

एक और तरीका है, अगर आपको पहले DBContext ऑब्जेक्ट की आवश्यकता नहीं है। बस इसे कीवर्ड का उपयोग करके लपेटें :

Payroll.Entities.City city1;
using (CityService cs = new CityService())
{
  city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value));
}

1
मैंने निम्नलिखित का उपयोग किया: dbContext1.Entry(backgroundReport).State = System.Data.Entity.EntityState.Detached'अलग करने के लिए और फिर dbContext2.Entry(backgroundReport).State = System.Data.Entity.EntityState.Modified;अद्यतन करने के लिए उपयोग करने में सक्षम था । एक सपने की तरह काम किया
पीटर स्मिथ

हाँ, पीटर। मुझे संशोधित राज्य के रूप में चिह्नित करना चाहिए।
रोमन ओ

अपने एप्लिकेशन स्टार्टअप (Global.asax) लॉजिक में मैं विजेट्स की एक सूची लोड कर रहा था .. संदर्भ वस्तुओं की एक सरल सूची जिसे मैं मेमोरी में स्टैश करता हूं। जब से मैं बयानों का उपयोग करते हुए अपने ईएफ संदर्भ के अंदर कर रहा था, मैंने सोचा कि बाद में कोई समस्या नहीं होगी जब मेरे नियंत्रक को उन वस्तुओं को एक व्यापार ग्राफ में असाइन करने के लिए मिला (हे, वह पुराना संदर्भ चला गया है, ठीक है?) - इस उत्तर ने मुझे बचाया? ।
bkwdesign

4

मुझे भी यही समस्या थी लेकिन @ Slauma के समाधान (हालांकि कुछ मामलों में महान) के साथ मेरा मुद्दा यह है कि यह सिफारिश करता है कि मैं उस संदर्भ को सेवा में पास कर दूं जिसका अर्थ है कि संदर्भ मेरे नियंत्रक से उपलब्ध है। यह मेरे नियंत्रक और सेवा परतों के बीच तंग युग्मन को भी बाध्य करता है।

मैं कंट्रोलर में सर्विस / रिपॉजिटरी लेयर को इंजेक्ट करने के लिए डिपेंडेंसी इंजेक्शन का इस्तेमाल कर रहा हूं और इस तरह कंट्रोलर से कॉन्टेक्स्ट तक पहुंच नहीं है।

मेरा समाधान था कि सेवा / रिपॉजिटरी परतें संदर्भ के एक ही उदाहरण का उपयोग करें - सिंगलटन।

प्रसंग एकल वर्ग:

संदर्भ: http://msdn.microsoft.com/en-us/library/ff650316.aspx
और http://csharpindepth.com/Articles/General/Singleton.aspx

public sealed class MyModelDbContextSingleton
{
  private static readonly MyModelDbContext instance = new MyModelDbContext();

  static MyModelDbContextSingleton() { }

  private MyModelDbContextSingleton() { }

  public static MyModelDbContext Instance
  {
    get
    {
      return instance;
    }
  }
}  

रिपोजिटरी क्लास:

public class ProjectRepository : IProjectRepository
{
  MyModelDbContext context = MyModelDbContextSingleton.Instance;
  [...]

अन्य समाधान मौजूद हैं जैसे कि एक बार संदर्भ को तत्काल देना और इसे आपकी सेवा / रिपॉजिटरी लेयर के कंस्ट्रक्टर्स में पास करना या एक और मैंने पढ़ा जिसके बारे में यूनिट ऑफ़ वर्क पैटर्न लागू कर रहा है। मुझे पूरा भरोसा है कि वहां और अधिक चीजे हैं...


9
... जैसे ही आप कोशिश करते हैं और मल्टीथ्रेडिंग का उपयोग करते हैं यह टूट नहीं जाता है?
कैफीक

8
एक संदर्भ को जरूरत से ज्यादा खुला नहीं रहना चाहिए, इसे हमेशा के लिए खुला रखने के लिए एक सिंगलटन का उपयोग करना बहुत ही आखिरी चीज है जिसे आप करना चाहते हैं।
enzi

3
मैंने इस अनुरोध के प्रति अच्छा कार्यान्वयन देखा है। स्टेटिक कीवर्ड का उपयोग करना गलत है, लेकिन यदि आप अनुरोध के आरंभ में संदर्भ को तुरंत समाप्त करने के लिए इस पैटर्न को बनाते हैं और अनुरोध के अंत में इसका निपटान करते हैं, तो यह एक कानूनी समाधान होगा।
ऐडिन

1
यह वास्तव में बुरी सलाह है। यदि आप DI का उपयोग कर रहे हैं (मुझे यहां साक्ष्य नहीं दिख रहे हैं?) तो आपको अपने DI कंटेनर को जीवनकाल का प्रबंधन करने देना चाहिए और यह संभवतः प्रति-अनुरोध होना चाहिए।
केसी

3
ये गलत है। खराब। खराब। खराब। खराब। विशेष रूप से अगर यह एक वेब अनुप्रयोग है, क्योंकि सभी थ्रेड और उपयोगकर्ताओं के बीच स्थिर ऑब्जेक्ट साझा किए जाते हैं। इसका मतलब यह है कि आपकी वेबसाइट के एक साथ कई उपयोगकर्ता आपके डेटा संदर्भ पर जोर दे रहे हैं, संभावित रूप से इसे भ्रष्ट कर रहे हैं, उन परिवर्तनों को सहेज रहे हैं जिनका आपने इरादा नहीं किया था, या केवल यादृच्छिक क्रैश बना रहे थे। DbContexts को कभी भी थ्रेड में साझा नहीं किया जाना चाहिए। फिर समस्या यह है कि स्टैटिक्स कभी नष्ट नहीं होते हैं, इसलिए यह अधिक से अधिक मेमोरी का उपयोग करने के लिए
बैठेगा

3

मेरे मामले में, मैं ASP.NET पहचान फ्रेमवर्क का उपयोग कर रहा था। मैंने UserManager.FindByNameAsyncएक ApplicationUserइकाई को पुनः प्राप्त करने के लिए अंतर्निहित विधि का उपयोग किया था । मैंने तब एक अलग पर एक नई बनाई गई इकाई पर इस इकाई को संदर्भित करने का प्रयास किया DbContext। यह आपके द्वारा देखे गए अपवाद के परिणामस्वरूप हुआ।

मैंने ApplicationUserकेवल विधि Idसे एक नई इकाई बनाकर UserManagerऔर उस नई इकाई को संदर्भित करके इसे हल किया ।


1

मुझे भी यही समस्या थी और मैं उस वस्तु का नया उदाहरण बनाकर हल कर सकता था जिसे मैं अपडेट करने की कोशिश कर रहा था। फिर मैंने उस वस्तु को अपने भंडार में पारित कर दिया।


क्या आप कृपया नमूना कोड के साथ मदद कर सकते हैं। ? इसलिए यह स्पष्ट होगा कि आप क्या कहने की कोशिश कर रहे हैं
बीजे पटेल

1

इस स्थिति में, यह पता चला है कि त्रुटि बहुत स्पष्ट है: एंटिटी फ्रेमवर्क एक इकाई को कई उदाहरणों IEntityChangeTrackerया आमतौर पर, के कई उदाहरणों का उपयोग करके ट्रैक नहीं कर सकता है DbContext। समाधान हैं: एक उदाहरण का उपयोग करें DbContext; एक भंडार (एक उदाहरण के आधार पर DbContext) के माध्यम से सभी आवश्यक संस्थाओं तक पहुंच ; या इस विशेष अपवाद को फेंकने वाले के अलावा एक रिपॉजिटरी के माध्यम से एक्सेस किए गए सभी संस्थाओं के लिए ट्रैकिंग बंद करना।

जब .नेट कोर वेब एपीआई में नियंत्रण पैटर्न के व्युत्क्रम का अनुसरण किया जाता है, तो मुझे अक्सर लगता है कि मेरे पास निर्भरता जैसे नियंत्रक हैं:

private readonly IMyEntityRepository myEntityRepo; // depends on MyDbContext
private readonly IFooRepository fooRepo; // depends on MyDbContext
private readonly IBarRepository barRepo; // depends on MyDbContext
public MyController(
    IMyEntityRepository myEntityRepo, 
    IFooRepository fooRepo, 
    IBarRepository barRepo)
{
    this.fooRepo = fooRepo;
    this.barRepo = barRepo;
    this.myEntityRepo = myEntityRepo;
}

और जैसे उपयोग

...
myEntity.Foo = await this.fooRepository.GetFoos().SingleOrDefaultAsync(f => f.Id == model.FooId);
if (model.BarId.HasValue)
{
    myEntity.Foo.Bar = await this.barRepository.GetBars().SingleOrDefaultAsync(b => b.Id == model.BarId.Value);
}

...
await this.myEntityRepo.UpdateAsync(myEntity); // this throws an error!

चूंकि सभी तीन रिपॉजिटरी अलग-अलग पर निर्भर करती हैं DbContext प्रति अनुरोध उदाहरणों हैं, इसलिए समस्या से बचने और अलग रिपॉजिटरी बनाए रखने के लिए मेरे पास दो विकल्प हैं: कॉल के अनुसार केवल एक बार एक नया उदाहरण बनाने के लिए DbContext के इंजेक्शन को बदलें:

// services.AddTransient<DbContext, MyDbContext>(); <- one instance per ctor. bad
services.AddScoped<DbContext, MyDbContext>(); // <- one instance per call. good!

या, यदि बाल इकाई का उपयोग केवल पढ़ने के लिए किया जा रहा है, तो उस उदाहरण पर नज़र रखना बंद करें:

myEntity.Foo.Bar = await this.barRepo.GetBars().AsNoTracking().SingleOrDefault(b => b.Id == model.BarId);


0

मैं एक परियोजना के लिए IoC (ASP.Net MVC EF6.2) को लागू करने के बाद इसी समस्या से टकराया।

आमतौर पर मैं एक कंट्रोलर के कंस्ट्रक्टर में डेटा के संदर्भ को इनिशियलाइज़ करूंगा और अपने सभी रिपॉजिटरी को इनिशियलाइज़ करने के लिए उसी संदर्भ का उपयोग करूँगा।

हालाँकि, रिपॉजिटरी को तुरंत बनाने के लिए IoC का उपयोग करने से उन सभी का अलग संदर्भ हो गया और मुझे यह त्रुटि मिलने लगी।

अभी के लिए मैं एक सामान्य संदर्भ के साथ रिपॉजिटरी को नया करने के लिए वापस चला गया हूं, जबकि मैं बेहतर तरीके से सोचता हूं।


0

इस तरह मैंने इस मुद्दे का सामना किया। पहले मुझे अपनी बचत करने की आवश्यकता है, Orderजिसे मेरी ApplicationUserतालिका का संदर्भ चाहिए :

  ApplicationUser user = new ApplicationUser();
  user = UserManager.FindById(User.Identity.GetUserId());

  Order entOrder = new Order();
  entOrder.ApplicationUser = user; //I need this user before saving to my database using EF

समस्या यह है कि मैं अपनी नई Orderइकाई को बचाने के लिए एक नए ApplicationDbContext की शुरुआत कर रहा हूं :

 ApplicationDbContext db = new ApplicationDbContext();
 db.Entry(entOrder).State = EntityState.Added;
 db.SaveChanges();

इसलिए समस्या को हल करने के लिए, मैंने ASP.NET MVC के अंतर्निहित UserManager का उपयोग करने के बजाय एक ही ApplicationDbContext का उपयोग किया।

इसके अलावा:

user = UserManager.FindById(User.Identity.GetUserId());

मैंने अपने मौजूदा ApplicationDbContext उदाहरण का उपयोग किया:

//db instance here is the same instance as my db on my code above.
user = db.Users.Find(User.Identity.GetUserId()); 

-2

त्रुटि स्रोत:

ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.Name);
ApplicationDbContext db = new ApplicationDbContent();
db.Users.Uploads.Add(new MyUpload{FileName="newfile.png"});
await db.SavechangesAsync();/ZZZZZZZ

आशा है कि कोई अपना कीमती समय बचाता है


मुझे यकीन नहीं है कि यह सवाल का जवाब देता है। शायद कुछ संदर्भ में मदद मिलेगी।
स्टुअर्ट सीगलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.