私はEntity Framework 4.0を使用していますが、理解できない愚かな問題を抱えています。
2つのテーブルがあります。
Entity Frameworkは、次の2つのエンティティを作成しました。
次のコードを使用して連絡先を取得し、その特定の連絡先の連絡先タイプを更新しています。
Contact contact = dbContext.Contacts.Single(c => c.Id == 12345);
contact.ContactType.Id = 3;
次の例外をスローします。
The property 'Id' is part of the object's key information and cannot be modified.
とてもシンプルに見えます!わかりません!
フレームワークによって作成されたエンティティには、contact.ContactTypeIdプロパティがありません。自動的に削除し、Contactエンティティ内にContactTypeの関連付けを作成しました。
あなたが提案したように、それを機能させる方法は、データベースを照会し、contact.ContactTypeに割り当てることでContactTypeオブジェクトを作成することです。例えば:
Contact contact = dbContext.Contacts.Single(c => c.Id == 12345);
ContactType contactType = dbContext.ContactType.Single(c => c.Id == 3);
contact.ContactType = contactType;
この問題は、同じオブジェクトを複数回参照しているために発生します。これはEFの制限ではなく、2つの異なるIDを持つ同じオブジェクトを挿入しないようにするための安全機能です。したがって、あなたがやろうとしていることを達成するには、単に新しいオブジェクトを作成し、新しく作成されたオブジェクトをデータベースに追加するだけです。
**この問題はループ内で頻繁に発生します。 whileループまたはforeachループを使用している場合は、ループ本体内に新規作成オブジェクトがあることを確認してください。
これを試して:
Contact contact = dbContext.Contacts.Single(c => c.contactTypeId == 1234);
contact.contactTypeId = 4;
dbContext.AddObject(contact);
dbContext.SaveChanges();
試して
contact.ContactType = differentContactType;
または
contact.ContactTypeId = 3;
(連絡先の)ContactTypeのIDを3に設定しようとしています。
2つの別個のコンテキストから関連オブジェクトを同時に編集しているときに、このようなことが起こりました。例:
DataContext ctxA = new DataContext();
DataContext ctxB = new DataContext();
Author orwell = new Author {Name = "George Orwell" };
ctxA.Add(orwell);
ctxB.Add(new Book {Name = "1984", Author = orwell});
ctxA.SaveChanges();
ctxB.SaveChanges();
私のケースはもう少し複雑でした(これは明らかに非常に愚かです)が、本質的にはこれが私のケースでエラーを引き起こしていました。
私の場合の別の奇妙な動作私は主キーのないテーブルを持っていますEF自体はすべての列を使用して複合主キーを作成します:
<Key>
<PropertyRef Name="ID" />
<PropertyRef Name="No" />
<PropertyRef Name="Code" />
</Key>
そして、更新操作を行うたびに、この例外がスローされます。
プロパティ「コード」はオブジェクトのキー情報の一部であり、変更できません。
解決策:EFダイアグラムからテーブルを削除し、DBに移動して、問題を作成しているテーブルにプライマリキーを追加し、EFダイアグラムにテーブルを再追加します。
<Key>
<PropertyRef Name="ID" />
</Key>
最初に削除次の追加
簡単に
public static IEnumerable UserIntakeFoodEdit(FoodIntaked data)
{
DBContext db = new DBContext();
var q = db.User_Food_UserIntakeFood.AsQueryable();
var item = q.Where(f => f.PersonID == data.PersonID)
.Where(f => f.DateOfIntake == data.DateOfIntake)
.Where(f => f.MealTimeID == data.MealTimeIDOld)
.Where(f => f.NDB_No == data.NDB_No).FirstOrDefault();
item.Amount = (decimal)data.Amount;
item.WeightSeq = data.WeightSeq.ToString();
item.TotalAmount = (decimal)data.TotalAmount;
db.User_Food_UserIntakeFood.Remove(item);
db.SaveChanges();
item.MealTimeID = data.MealTimeID;//is key
db.User_Food_UserIntakeFood.Add(item);
db.SaveChanges();
return "Edit";
}
私はEF 4.0とWPFを使用していますが、同様の問題がありました。...非常に簡単な方法で(少なくとも私にとっては)それを解決する問題が見つかりました。
あなたと同じように、別のテーブルの外部キーによって参照されるテーブルのフィールド(つまり、Contact)を更新するのは簡単だと思ったからです(つまり、あなたの場合:ContactType)。
ただし、エラーメッセージ: "....はオブジェクトのキー情報の一部であり、変更できません。"プライマリキー(更新されなかった)を更新しようとした場合にのみ表示されます私の意図はまったくありません)。
EntityModelのXMLコードを詳しく見て、それを見つけました。
<EntityType Name="Contact">
<Key>
<PropertyRef Name="ID" />
<PropertyRef Name="contactTypeID" /> <!-- This second line caused my problem -->
</Key>
<Property Name="ID" Type="int" Nullable="false" />
...
...
</EntityType>
何らかの理由で(おそらくデータベース内でいくつかの愚かな間違いを犯した)、Visual StudioがデータベースからDataModelを自動生成したときに、そのテーブル(Contact)に追加しました。フィールド(ContactTypeID
)a secondPropertyRef
(second line)を更新したかった。
2番目のPropertyRef
:を削除しました
<PropertyRef Name="contactTypeID" />
両方で、ストアモデルと概念モデルおよび....問題が解決しました:-)
したがって、次のようになります。
<EntityType Name="Contact">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="int" Nullable="false" />
...
...
</EntityType>
更新と挿入は、赤ちゃんのようにスムーズに実行されるようになりました.... :-)
したがって、データモデルのXMLをチェックして、PKのみがPropertyRef
としてリストされていることを確認することをお勧めします。私のために働いた... :-)
関連付けには2つのタイプがあります。関連キーがナビゲーションプロパティとしてのみ表示される独立した関連付け。 2つ目は、外部キーとナビゲーションプロパティを使用して関連キーを変更できる外部キーの関連付けです。したがって、次のことができます。
//オプション1汎用オプション
var contacttype = new ContactType{Id = 3};
db.ContactTypes.Attach(contacttype);
customer.ContactType = contacttype;
オプション2外部キーオプション
contact.ContactTypeId = 3;
//汎用オプションは、外部キーと独立した関連付けで機能します
contact.ContactReference.EntityKey = new EntityKey("container.contactset","contacttypeid",3);
私の場合、主キーを欠落しているテーブルに設定し、mappind edmxを再実行しましたが、主キーがある場合に機能しました
<PropertyRef Name="id" />
ただし、主キーが設定されていない場合は、
<PropertyRef Name="id" />
<PropertyRef Name="col1" />
<PropertyRef Name="col2" />
juergen Finkの答えは回避策であることに注意してください
私の場合、オブジェクトを複製したいのですが、idを変更したいので、これを使用します
Common.DataContext.Detach(object);
魔法のように働く
これが何時間も苦労した後、私がPKを更新することはなく、間違いなくPKを持っていることを知っていたので、これが他の誰かを助けることを願っています。現在のPK値を表示するためにメニューバーにデータバインドされたPK値があり、これが問題の原因でした。
私の場合、IDフィールドのKEY属性を削除するとエラーが表示されました。
// [Key]
public long Id { get; set; }
そのため、属性を元の場所に戻すだけで、すべてが再び機能するようになりました!
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
追加する必要があります
db.Entry(contact).State = EntityState.Detached;
.SaveChanges();の後