如果一个实体有多个关系并且我尝试在它们上同时插入数据,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
}
);
}
在第三种情况下,抛出 InvalidCastException 表示 EF 无法从 'EntityFrameworkMultipleRelationships.Entities.Watch
转换为 ' EntityFrameworkMultipleRelationships.Entities.Shoe
'。
我是 EF 新手,但我认为这里出了点问题。
我会感谢任何提示指出可能的解决方案!
PD.:为了尽快测试自己,请下载此 VS2012 解决方案:https ://dl.dropboxusercontent.com/u/22887057/EntityFrameworkMultipleRelationships.zip 。按照 README.txt 遵循代码优先模式创建数据库。
更新
正如@Chris 指出的那样,问题在于 EF 认为 Shoe 和 Watch 实体是相同的。这是由实施不当的重写 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();
}
}
如果两个不同的实体类型(如Watch
和Shoe
)具有相同的 Id,则 EF 将它们视为相等。
添加运行时类型检查以覆盖 Equals 会考虑实体类型,因此可以解决此问题。
...
return this.GetType() == entityOfT.GetType() && object.Equals(this.Id, entityOfT.Id);
...