184

市との参照を持つ従業員の詳細を保存しようとしています。しかし、検証済みの連絡先を保存しようとするたびに、 「ADO.Net Entity Framework An entity object cannot be referenced by multiple instances of 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";
        }
4

13 に答える 13

253

この2行だから…

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

...コンストラクターでパラメーターを取らないでください。クラス内でコンテキストを作成すると思います。ロードするとcity1...

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

...city1のコンテキストにを添付しますCityService。後でcity1、 new への参照として aをEmployee e1追加しe1 、この参照をcity1のコンテキストに追加しますEmployeeService。その結果city1、例外が不平を言う2つの異なるコンテキストに接続しました。

これを修正するには、サービス クラスの外部にコンテキストを作成し、それを両方のサービスに挿入して使用します。

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

サービス クラスは、単一のエンティティ タイプのみを担当するリポジトリに少し似ています。このような場合、サービスに個別のコンテキストを使用すると、エンティティ間の関係が関係するとすぐに、常に問題が発生します。

(単一のコンテキストを持つ) などの一連の密接に関連するエンティティを担当する単一のサービスを作成し、メソッド内の操作全体をこのサービスのメソッドにEmployeeCityService委任することもできます。Button1_Click

于 2012-04-17T15:35:29.510 に答える
32

再現する手順は次のように簡略化できます。

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

1つだけ使用するとEntityContext、これを解決できます。他の解決策については、他の回答を参照してください。

于 2015-01-09T12:32:29.477 に答える
9

これは古いスレッドですが、私が好む別の解決策は、単に cityId を更新し、穴モデル City を Employee に割り当てないことです...これを行うには、Employee は次のようになります。

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

次に、次の割り当てで十分です。

e1.CityId=city1.ID;
于 2014-11-09T02:57:37.910 に答える
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;
  [...]

コンテキストを一度インスタンス化して、それをサービス/リポジトリ層のコンストラクターに渡すなど、他のソリューションも存在します。これは、作業単位パターンを実装していることについて私が読んだ別のソリューションです。もっとあると確信しています...

于 2012-12-20T17:26:24.643 に答える
3

私の場合、ASP.NET Identity Framework を使用していました。組み込みメソッドを使用してエンティティUserManager.FindByNameAsyncを取得しました。ApplicationUser次に、別の で新しく作成されたエンティティでこのエンティティを参照しようとしましたDbContext。これにより、最初に見た例外が発生しました。

メソッドからApplicationUserのみを使用して新しいエンティティを作成し、その新しいエンティティを参照することで、これを解決しました。IdUserManager

于 2015-03-02T02:40:10.687 に答える
1

この場合、エラーが非常に明確であることがわかります。Entity Framework は、 の複数のインスタンス、IEntityChangeTrackerまたは通常は の複数のインスタンスを使用してエンティティを追跡できませんDbContext。解決策は次のとおりです。 のインスタンスを 1 つ使用しますDbContext。単一のリポジトリを介して必要なすべてのエンティティにアクセスします (の 1 つのインスタンスに応じてDbContext)。または、この特定の例外をスローするリポジトリ以外のリポジトリを介してアクセスされるすべてのエンティティの追跡をオフにします。

.Net Core Web API で制御パターンの反転に従うと、次のような依存関係を持つコントローラーがあることがよくあります。

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!

3 つのリポジトリはすべて要求ごとに異なるインスタンスに依存DbContextするため、この問題を回避して別々のリポジトリを維持するための 2 つのオプションがあります。DbContext の注入を変更して、呼び出しごとに 1 回だけ新しいインスタンスを作成します。

// 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);
于 2018-09-28T15:20:43.877 に答える
-3

エラーの原因:

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

誰かが貴重な時間を節約してくれることを願っています

于 2015-09-09T11:50:51.320 に答える