我按照以下方式设置了3个实体。
public class Person
{
[Key]
public int PersonId { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
[Key]
public int LocationId { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
public virtual ICollection<Value> Values{get; set; }
}
public class Value
{
[Key]
public int ValueId { get; set; }
public int LocationId { get; set; }
public virtual Location Location { get; set; }
}
使用流畅的Api,我已经设置了从Location到Person以及从Value到Location的外键配置。
// Person to Location(s)
modelBuilder.Entity<Person>()
.HasMany(e => e.Locations)
.WithRequired(e => e.Person)
.WillCascadeOnDelete(true);
// Location to Value(s)
modelBuilder.Entity<Location>()
.HasMany(e => e.Values)
.WithRequired(e => e.Location)
.WillCascadeOnDelete(false);
我要做的是创建一个新人,添加一个位置并在该位置添加一个值。
所以我自然会先创建一个人
[pseudo code]
var newPerson = new Person();
然后创建位置
[pseudo code]
var newLocation = new Location { Person = newPerson };
然后最后是值
[pseudo code]
var newValue = new Value { Location = newLocation };
DbContext.Values.Add(NEWVALUE); DbContext.SaveChanges();
正在发生的事情是,如果我想要的话,我能够成功地使用新创建的人保存位置,但是当我尝试再次降低另一个级别并添加上面的值时,它会抱怨Value和Location之间的外键约束
我已经设法通过首先将位置添加到上下文并执行保存更改来使其工作,但这意味着我的代码不是事务安全的。
答案 0 :(得分:1)
您可以保存此人,因为它不包含外键,这意味着它没有Locationid的属性,但在值的情况下,它需要Locationid,这是定义一个的全部目的关系。
当您定义两个表之间的关系时,您无法避免在没有另一个表的外键的情况下将记录保存在其中一个表中。添加位置,保存更改,在下一行中添加您的值,然后保存更改。此过程不会以任何方式使您的应用程序易受攻击。
如果您仍然不想这样做,那么不要定义与实体框架的关系,而是在您的值表中使Locationid唯一并自己执行自定义验证,但我不会建议。< / p>
答案 1 :(得分:1)
您已在Persons
和Locations
之间建立了正确的一对多关系:Person
有零个或多个Locations
,每个Location
}只属于一个人。如果Person
抓住存在,那么他的Locations
也会抓住存在。
但是,您已对Locations
和Values
之间的关系进行了不同的建模。显然,如果Location
抓住存在,则Values
不必因WillCasscaseOnDelete(false)
而被删除。如果LocationId
被删除,Location
的价值是什么意思?
您的解决方案取决于您打算建模的内容:
WillCascadeOnDelete(true)
。