如果一个实体有多个关系并且我尝试同时插入数据,那么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实体是相同的。这是由于实施的覆盖等于错误造成的。这实际上是问题的根源:
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);
...
答案 0 :(得分:1)
不确定为什么抛出该特定错误,但由于您的Entity.Id定义,EF似乎变得混乱。如果将PK字段移动到Shoe和Watch类定义,它就可以工作。此外,如果您将watch和shoe对象添加到各自的DbContext集,然后通过集合将它们添加到Person对象,它也可以。在任何情况下,以某种方式稍微更明确地解决问题。
答案 1 :(得分:1)
我不确定实体框架的内部结构(虽然我可能会尝试看一看),但我认为你的问题可能是两件事的组合:
1)实体框架自动生成存储实体的集合的方式。
2)你有两个具有相同Guid的子对象,即使它们的类型不同,也会返回Equals(..)
为真。
如果您执行以下操作,您的代码将会运行:
定义Shoe
/ Watch
(或两者),并将它们添加到相应的集合中:
context.Set<Shoe>().Add(aShoe);
或为Watch
或Shoe
Watch tWatch = new Watch { Brand = "Casio", Id = new System.Guid("00000000-0000-0000-0000-000000000001") };
如果您没有执行上述任何一项操作,并且按照第三个示例操作,则可以按照调试程序进行操作,并发现您将使用Equals
来调用Watch
和Shoe
,结果是真的 - 我假设这是实体框架抛出异常的点。
希望能够了解更多关于EF内部人员的人能够指出为什么会出现这种情况。