エンティティに複数の関係があり、それらに同時にデータを挿入しようとすると、EF は InvalidCastException をスローします。
例として、次のドメイン クラスを想像してください。
public class Person : Entity<Guid>
{
public string Name { get; set; }
public ICollection<Watch> Watches { get; set; }
public ICollection<Shoe> Shoes { get; set; }
}
public class Shoe : Entity<Guid>
{
public string Brand { get; set; }
}
public class Watch : Entity<Guid>
{
public string Brand { get; set; }
}
ユースケース #1 (完璧に動作):
using (var context = new MultipleRelationshipsContext())
{
var watches =
new List<Watch>() {
new Watch { Brand = "Rolex" }
};
context.Set<Person>().Add(
new Person
{
Name = "Warren Buffett",
Watches = watches
}
);
}
使用例 #2 (これも完璧に機能します):
using (var context = new MultipleRelationshipsContext())
{
var shoes =
new List<Shoe>() {
new Shoe { Brand = "Cole Haan" }
};
context.Set<Person>().Add(
new Person
{
Name = "Barack Obama",
Shoes = shoes
}
);
}
使用例 #3 (InvalidCastException):
using (var context = new MultipleRelationshipsContext())
{
var watches =
new List<Watch>() {
new Watch { Brand = "Casio" }
};
var shoes =
new List<Shoe>() {
new Shoe { Brand = "New Balance" }
};
context.Set<Person>().Add(
new Person
{
Name = "Steve Jobs",
Watches = watches,
Shoes = shoes
}
);
}
EntityFrameworkMultipleRelationships.Entities.Watch
3 番目のケースでは、EF が 'から ' ' にキャストできないことを示す InvalidCastException がスローされEntityFrameworkMultipleRelationships.Entities.Shoe
ます。
私は EF の初心者ですが、ここで何か問題が発生していると思います。
可能な解決策を指摘するヒントをいただければ幸いです。
PD .: できるだけ早く自分自身をテストするには、次の VS2012 ソリューションをダウンロードしてください: https://dl.dropboxusercontent.com/u/22887057/EntityFrameworkMultipleRelationships.zip。README.txt に従って、コード ファースト パターンに従ってデータベースを作成します。
アップデート
@Chris が指摘したように、問題は、EF が靴と時計のエンティティを同じと見なすことでした。これは、不適切に実装されたオーバーライドされた Equals が原因でした。これが実際に問題の原因です。
public abstract class Entity<T>
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("Id")]
public T Id { get; set; }
public override bool Equals(object obj)
{
Entity<T> entityOfT = obj as Entity<T>;
if (entityOfT == null)
return false;
return object.Equals(this.Id, entityOfT.Id);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
2 つの異なるエンティティ タイプ (Watch
と などShoe
) の ID が同じ場合、EF はそれらを等しいと見なします。
オーバーライドされた Equals にランタイム タイプ チェックを追加すると、エンティティ タイプが考慮されるため、この問題が解決されます。
...
return this.GetType() == entityOfT.GetType() && object.Equals(this.Id, entityOfT.Id);
...