আইটিটিটি চেঞ্জট্র্যাকার একাধিক উদাহরণ দ্বারা সত্তা অবজেক্টটি রেফারেন্স করা যায় না। সত্তা সম্পর্কিত সত্তা সম্পর্কিত ফ্রেমওয়ার্কে যুক্ত করার সময় ৪.১


165

আমি কর্মচারীর বিশদটি সংরক্ষণ করার চেষ্টা করছি, যার সাথে শহরের উল্লেখ রয়েছে। তবে যতবারই আমি আমার পরিচিতিটি সংরক্ষণ করার চেষ্টা করি যা যাচাই করা হয় আমি ব্যতিক্রম পাই "ADO.NET সত্তা ফ্রেমওয়ার্ক একটি সত্তা অবজেক্ট আইএনটিটিচেনজ ট্র্যাকার একাধিক উদাহরণ দ্বারা রেফারেন্স করা যায় না"

আমি অনেকগুলি পোস্ট পড়েছি তবে এখনও কী করা উচিত তার সঠিক ধারণা পাচ্ছি না ... আমার সেভ বোতামের ক্লিক কোডটি নীচে দেওয়া হয়েছে

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দুটি পৃথক প্রসঙ্গে যুক্ত হয়েছেন যা ব্যতিক্রম অভিযোগ করে compla

আপনি পরিষেবা ক্লাসের বাইরে একটি প্রসঙ্গ তৈরি করে এবং ইনজেকশনের মাধ্যমে এবং উভয় পরিষেবায় এটি ব্যবহার করে এটি ঠিক করতে পারেন:

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

আপনার পরিষেবা শ্রেণিগুলি কিছুটা সংগ্রহস্থলের মতো দেখায় যা কেবলমাত্র একক সত্তার ধরণের জন্য দায়ী। এই ক্ষেত্রে আপনি যখন পরিষেবাগুলির জন্য পৃথক প্রসঙ্গ ব্যবহার করবেন তখন সত্তাগুলির মধ্যে সম্পর্ক জড়িত হওয়ার সাথে সাথে আপনার সর্বদা সমস্যা হবে।

আপনি এমন একটি একক পরিষেবাও তৈরি করতে পারেন যা ঘনিষ্ঠভাবে সম্পর্কিত সংস্থাগুলির একটি সেটগুলির জন্য দায়ী, যেমন EmployeeCityService(যার একক প্রসঙ্গ রয়েছে) এবং আপনার Button1_Clickপদ্ধতির পুরো ক্রিয়াকলাপকে এই পরিষেবার একটি পদ্ধতির উপর অর্পণ করতে পারেন।


4
উত্তরে কিছু ব্যাকগ্রাউন্ডের তথ্য অন্তর্ভুক্ত না করা সত্ত্বেও আপনি যেভাবে এটি সন্ধান করেছিলেন তা পছন্দ করি।
ড্যানিয়েল কুমাক

দেখে মনে হচ্ছে এটি আমার সমস্যার সমাধান করবে, নতুন প্রসঙ্গ উদাহরণটি কীভাবে লিখব তা সম্পর্কে আমার ঠিক ধারণা নেই :(
অর্টান্ড ২und

12
ওআরএম অ্যাবস্ট্রাক্ট করা হ'ল হলুদ লিপস্টিকটি টার্ডের উপরে রাখার মতো।
রনি ওভারবাই

আমি এখানে কিছু অনুপস্থিত হতে পারে তবে কিছু ওআরএম-তে (বিশেষত এন্টি ফ্রেমওয়ার্ক) ডেটা প্রসঙ্গটি সর্বদা সংক্ষিপ্ত করা উচিত। একটি স্থিতিশীল বা পুনরায় ব্যবহৃত প্রসঙ্গে পরিচয় করিয়ে দেওয়া চ্যালেঞ্জ এবং সমস্যার সম্পূর্ণ অন্য সেটকে উপস্থাপন করবে।
মেরিটিম

@ মারিতিম এটি ব্যবহারের উপর নির্ভর করে। ওয়েব অ্যাপ্লিকেশনগুলিতে এটির সাধারণত একটি রাউন্ড্রিপ থাকে। ডেস্কটপ অ্যাপ্লিকেশনগুলিতে, আপনি প্রতি পিছু একটি ব্যবহার করতে পারেন 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
বলুন আপনি দুটি প্রসঙ্গ ব্যবহার করতে চান? (স্কোপ ইস্যু বা কোনও কিছুর কারণে) আপনি কীভাবে প্রসঙ্গ থেকে বিচ্ছিন্ন হন এবং প্রসঙ্গে দুটি সংযুক্ত করেন?
নুলভক্সপপুলি

আপনার যদি এটির মতো স্মিথ করার দরকার হয় তবে সম্ভবত আপনি এটি ভুল উপায়ে করছেন ... আমি একটি প্রসঙ্গ ব্যবহার করার পরামর্শ দিই।
পাভেল শ্লেইনিক

3
এমন উদাহরণ রয়েছে যেখানে আপনি কোনও আলাদা উদাহরণ ব্যবহার করতে চান, যেমন কোনও আলাদা ডাটাবেসের দিকে নির্দেশ করার সময়।
জে

1
এটি সমস্যার সহায়ক সরলীকরণ; তবে এটি প্রকৃত উত্তর সরবরাহ করে না।
BrainSlugs83

9

এটি একটি পুরানো থ্রেড, তবে অন্য একটি সমাধান, যা আমি পছন্দ করি তা হ'ল কেবলমাত্র সিটি আপডেট করুন এবং কর্মচারীকে গর্ত মডেল সিটি বরাদ্দ করবেন না ... এটি করার জন্য যে কর্মচারীর মতো দেখা উচিত:

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

তারপরে এটি যথেষ্ট পরিমাণ কার্যনির্বাহী:

e1.CityId=city1.ID;

5

বিকল্প হিসাবে ইনজেকশন এবং আরও খারাপ সিঙ্গলটন, আপনি অ্যাড করার আগে ডিটাচ পদ্ধতিতে কল করতে পারেন ।

সত্ত্বা ফ্রেমওয়ার্ক 6: ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);

সত্ত্বা ফ্রেমওয়ার্ক 4: cs.Detach(city1);

আর একটি উপায় আছে, যদি আপনার প্রথম ডিবিসিএনটেক্সট অবজেক্টের প্রয়োজন না হয়। কেবল কীওয়ার্ড ব্যবহার করে এটি মোড়ানো :

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;আপডেট করতে ব্যবহার করতে সক্ষম হয়েছি । স্বপ্নের মতো কাজ করেছেন
পিটার স্মিথ

হ্যাঁ, পিটার রাষ্ট্রকে পরিবর্তিত হিসাবে চিহ্নিত করার জন্য আমার উল্লেখ করা উচিত।
রোমান হে

আমার অ্যাপ্লিকেশন প্রারম্ভকালে (গ্লোবাল.এক্স্যাক্স) যুক্তিতে আমি উইজেটের একটি তালিকা লোড করছিলাম .. রেফারেন্স অবজেক্টগুলির একটি সাধারণ তালিকা যা আমি স্মৃতিতে আটকে রেখেছি। যেহেতু আমি বিবৃতি ব্যবহার করে আমার EF প্রসঙ্গটি করছিলাম, তাই আমি ভেবেছিলাম যে পরে যখন আমার কন্ট্রোলার objects অবজেক্টগুলিকে ব্যবসায়ের গ্রাফে বরাদ্দ করার কাছাকাছি পৌঁছেছে তখন (আরে, সেই পুরানো প্রসঙ্গটি চলে গেছে, তাই না?) - এই উত্তরটি আমাকে বাঁচিয়েছিল ।
bkwdesign

4

আমার একই সমস্যা ছিল তবে @ স্লুমার সমাধান (যদিও কিছু ক্ষেত্রে দুর্দান্ত) এর সাথে আমার সমস্যাটি হ'ল এটি প্রস্তাব দেয় যে আমি প্রসঙ্গটি পরিষেবাটিতে প্রেরণ করব যা বোঝায় যে প্রসঙ্গটি আমার নিয়ামক থেকে উপলব্ধ। এটি আমার নিয়ামক এবং পরিষেবা স্তরগুলির মধ্যে দৃ tight় সংযোগকে জোর করে।

আমি ডিপেন্ডেন্সি ইনজেকশনটি পরিষেবা / সংগ্রহস্থল স্তরগুলিকে কন্ট্রোলারে ইনজেক্ট করতে ব্যবহার করছি এবং যেমন নিয়ামকের কাছ থেকে প্রসঙ্গে অ্যাক্সেস নেই।

আমার সমাধানটি ছিল পরিষেবা / সংগ্রহস্থল স্তরগুলি প্রসঙ্গটির একই উদাহরণটি ব্যবহার করুন - সিঙ্গলটন।

প্রসঙ্গ একক ক্লাস:

তথ্যসূত্র: http://msdn.microsoft.com/en-us/library/ff650316.aspx
এবং http://csharpindepth.com/Articles/ জেনারাল / সিংলটন.এএসপিএক্স

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
এটি আসলেই খারাপ পরামর্শ। আপনি যদি ডিআই ব্যবহার করছেন (আমি এখানে প্রমাণগুলি দেখছি না?) তবে আপনার ডিআই কনটেইনারটিকে আজীবন প্রসঙ্গটি পরিচালনা করা উচিত এবং এটি সম্ভবত প্রতি অনুরোধ হওয়া উচিত।
কেসি 20

3
এইটা খারাপ. খারাপ। খারাপ। খারাপ। খারাপ। বিশেষত এটি যদি কোনও ওয়েব অ্যাপ্লিকেশন হয়, যেহেতু স্থির বস্তুগুলি সমস্ত থ্রেড এবং ব্যবহারকারীর মধ্যে ভাগ করা হয়। এর অর্থ হ'ল আপনার ওয়েবসাইটের এক সাথে একাধিক ব্যবহারকারী আপনার ডেটা প্রসঙ্গে স্ট্যাম্পিং করবে, এটি সম্ভবত দুর্নীতিগ্রস্থ হবে, আপনি যে পরিবর্তনগুলি করতে চান নি সেগুলি সংরক্ষণ করে বা এমনকি এলোমেলো ক্র্যাশ তৈরি করে। DbContexts থ্রেড জুড়ে কখনও ভাগ করা উচিত। তারপরে সমস্যা আছে যে স্ট্যাটিকস কখনই ধ্বংস হয় না, তাই এটি বসে এবং আরও বেশি স্মৃতি ব্যবহার করে
চলবে

3

আমার ক্ষেত্রে, আমি এএসপি.এনইটি আইডেন্টিটি ফ্রেমওয়ার্ক ব্যবহার করছিলাম। সত্তা UserManager.FindByNameAsyncপুনরুদ্ধারে আমি বিল্ট ইন পদ্ধতিটি ব্যবহার করেছি ApplicationUser। আমি তখন এই সত্তাকে অন্যরকম নতুন তৈরি করা সত্তায় রেফারেন্স দেওয়ার চেষ্টা করেছি DbContext। এর ফলে আপনি মূলত যে ব্যতিক্রমটি দেখেছেন তার ফলস্বরূপ।

আমি ApplicationUserকেবল পদ্ধতি Idথেকে একটি নতুন সত্তা তৈরি করে UserManagerএবং সেই নতুন সত্তাকে উল্লেখ করে সমাধান করেছি re


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সংগ্রহই অনুরোধ অনুসারে বিভিন্ন দৃষ্টান্তের উপর নির্ভরশীল , তাই সমস্যাটি এড়াতে এবং পৃথক সংগ্রহস্থলগুলি বজায় রাখার জন্য আমার কাছে দুটি বিকল্প রয়েছে: ডাবকনটেক্সট-এর ইনজেকশন পরিবর্তন করে কেবলমাত্র একবার কলে একবার নতুন ইভেন্ট তৈরি করতে হবে:

// 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

একটি প্রকল্পের জন্য আইওসি বাস্তবায়নের পরে আমি এই একই সমস্যার মুখোমুখি হয়েছি (এএসপি.নেট এমভিসি ইএফ 6.2)।

সাধারণত আমি একটি নিয়ামক তৈরির ক্ষেত্রে ডেটা প্রসঙ্গে শুরু করতে এবং আমার সমস্ত সংগ্রহস্থল আরম্ভ করার জন্য একই প্রসঙ্গটি ব্যবহার করব।

তবে আইওসি ব্যবহার করে সংগ্রহস্থলগুলি ইনস্ট্যান্ট করার জন্য তাদের সকলের আলাদা আলাদা প্রসঙ্গ তৈরি হয়েছিল এবং আমি এই ত্রুটি পেতে শুরু করেছি।

আপাতত আমি আরও ভাল উপায়ের কথা ভাবার সময় একটি সাধারণ প্রসঙ্গের সাহায্যে সঞ্চিতাগুলি নতুন করে ফিরতে চলে এসেছি।


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 db = new ApplicationDbContext();
 db.Entry(entOrder).State = EntityState.Added;
 db.SaveChanges();

সুতরাং সমস্যাটি সমাধান করার জন্য, আমি এএসপি.এনইটি এমভিসি-র অন্তর্নির্মিত ইউজারম্যানেজারটি ব্যবহার না করে একই অ্যাপ্লিকেশনবিবি কনটেক্সট ব্যবহার করেছি।

এর পরিবর্তে:

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

আমি আমার বিদ্যমান অ্যাপ্লিকেশনডিবি কনটেক্সট উদাহরণটি ব্যবহার করেছি:

//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

আশা করি কেউ কিছু মূল্যবান সময় সাশ্রয় করেন


আমি নিশ্চিত না যে এই প্রশ্নের উত্তর দেয়। সম্ভবত কিছু প্রসঙ্গ সাহায্য করবে।
স্টুয়ার্ট সিগেলার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.