web-dev-qa-db-ja.com

EFコアに新しいエンティティを追加した後にエンティティを更新する方法

ClientClientSecretの2つのテーブルがあります。テーブルの構造は次のとおりです。

_public class Client
    {
        public int Id { get; set; }
        public string ClientId { get; set; }
        public string ClientName { get; set; }
    public List<ClientSecret> ClientSecrets { get; set; }
    }

public class ClientSecret
{
        public int Id { get; set; }
        public string Description { get; set; }
        public string Value { get; set; }
        public DateTime? Expiration { get; set; }
        public Client Client { get; set; }
}
_

何よりも、新しいClientを作成してClientIdClientNameを設定し、DBからこのオブジェクトの新しいIdを取得する必要があります。

私はこれを試しました(__dbContext_はコンストラクターのDIシステムを介して取得しています):

_var newClient = new Client();
newClient.ClientName = client.ClientName;
newClient.ClientId = client.ClientId;
_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

var newClientId = newClient.Id;
var clientToUpdate = await _dbContext.Clients.Where(x => x.Id == newClientId).SingleOrDefaultAsync();

clientToUpdate.ClientSecrets.AddRange(secrets);
_dbContext.Clients.Update(clientToUpdate);
await _dbContext.SaveChangesAsync();
_

テーブルClientはこのテーブルに新しいレコードを作成するためにClientSecretsを必要とするため、最初にClientIdを作成する必要があります。

このエラーメッセージが表示されました:

次の行で失敗しました:_dbContext.Clients.Update(clientToUpdate);

InvalidOperationException:エンティティタイプ 'Client'のインスタンスは、同じキーを持つこのタイプの別のインスタンスがすでに追跡されているため、追跡できません。新しいエンティティを追加するとき、ほとんどのキータイプでは、キーが設定されていない場合(つまり、キープロパティにそのタイプのデフォルト値が割り当てられている場合)、一意の一時キー値が作成されます。新しいエンティティのキ​​ー値を明示的に設定する場合は、それらが既存のエンティティまたは他の新しいエンティティ用に生成された一時的な値と衝突しないようにしてください。既存のエンティティをアタッチするときは、特定のキー値を持つ1つのエンティティインスタンスのみがコンテキストにアタッチされていることを確認してください。

この問題を修正するにはどうすればよいですか?

6
Jenan

同じキーを持つこのタイプの別のインスタンスがすでに追跡されているため、エンティティタイプ「クライアント」のインスタンスを追跡できません

_dbContext.Clients.Add(newClient);で作成されたclientのインスタンスがすでに存在します。

更新されたエントリを添付する前に、最初のエントリを切り離す必要があります

_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

切り離すためのコードを追加する

_dbcontext.Entry(newClient).State = EntityState.Detached;
7
user6448640

生のSQLクエリを作成するときと同じようにEFCoreを使用しています。これは、ORMの多くの利点を上回っています。

EF Coreは関係自体を把握できるため、ClientIdClientSecretsは必要ありません。

var newClient = new Client
{
    ClientName = client.ClientName,
    ClientId = client.ClientId,
    ClientSecrets = secrets.ToList() // or ToArray or whatever it is
};

_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

ClientSecretがClientクラスへの逆参照を必要とすることは問題ではありません。モデルにシークレットを追加することで、ClientSecretClientの関係を確立します。

ここで保存すると、EF Coreは、最初にClientを追加してから、ClientSecretsを追加する必要があることを認識します。

2
Tseng