EF6 - 在单个事务中保存更改后,虚拟属性不保存到数据库

时间:2017-08-22 11:32:53

标签: c# entity-framework

我按照以下方式设置了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之间的外键约束

我已经设法通过首先将位置添加到上下文并执行保存更改来使其工作,但这意味着我的代码不是事务安全的。

2 个答案:

答案 0 :(得分:1)

您可以保存此人,因为它不包含外键,这意味着它没有Locationid的属性,但在值的情况下,它需要Locationid,这是定义一个的全部目的关系。

当您定义两个表之间的关系时,您无法避免在没有另一个表的外键的情况下将记录保存在其中一个表中。添加位置,保存更改,在下一行中添加您的值,然后保存更改。此过程不会以任何方式使您的应用程序易受攻击。

如果您仍然不想这样做,那么不要定义与实体框架的关系,而是在您的值表中使Locationid唯一并自己执行自定义验证,但我不会建议。< / p>

答案 1 :(得分:1)

您已在PersonsLocations之间建立了正确的一对多关系:Person有零个或多个Locations,每个Location }只属于一个人。如果Person抓住存在,那么他的Locations也会抓住存在。

但是,您已对LocationsValues之间的关系进行了不同的建模。显然,如果Location抓住存在,则Values不必因WillCasscaseOnDelete(false)而被删除。如果LocationId被删除,Location的价值是什么意思?

您的解决方案取决于您打算建模的内容:

  • 如果你真的打算建立一对多的关系,那么一个位置有零个或多个值,而每个值只属于一个位置,你应该WillCascadeOnDelete(true)
  • 如果您的意思是值属于零或一个位置,则将正确的值建模为零或一关系。在这种情况下,如果没有Location
  • ,Value仍然可以存在
  • 如果您认为某个值可能属于多个位置,则会在“位置”和“值”之间建立一对多关系或多对多关系。在这种情况下,您可以删除没有其值的位置,因为这些值可能没有位置。