EntityFramework的AddOrUpdate导致错误的外键更新

Ant*_*lov 7 c# entity-framework

假设我有许多国家,每个国家都有许多城市.我可以使用以下模型来表示:

public class Country
{
    public virtual int Id { get; set; }
    [Required]
    public virtual string Name { get; set; }

    public virtual ICollection<City> Cities { get; set; }
}

public class City
{
    public virtual int Id { get; set; }
    [Required]
    public virtual string Name { get; set; }

    public virtual Country Country { get; set; }
    public virtual int CountryId { get; set; }
}

class TestContext : DbContext
{
    public DbSet<City> Cities { get; set; }
    public DbSet<Country> Countries { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

实体框架正确识别外键并生成表.

但是,如果我现在尝试播种一些测试数据:

static class Program
{
    static void Main()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TestContext>());
        using (var db = new TestContext())
        {
            db.Database.Initialize(true);
            db.Database.Log = Console.Write;

            var country = db.Countries.Create();
            country.Name = "France";
            db.Countries.AddOrUpdate(a => a.Name, country);

            var city = db.Cities.Create();
            city.Name = "Paris";
            city.Country = country;
            db.Cities.AddOrUpdate(q => q.Name, city);

            db.SaveChanges();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第一次运行时,一切正常,数据库中的CountryId字段设置正确.但是,当我第二次运行它时,db.SaveChanges()尝试将Paris的CountryId设置为0,这违反了不可为空的外键约束.

问题似乎是尽管city并且country是变更跟踪代理,但该CountryId属性永远不会更新.但是,手动更新它并没有帮助.

这是预期的行为,如果是这样,我怎么能在AddOrUpdate不改变的情况下使用?通过设置外键来执行所有操作似乎不是一个选项,因为这些代码在第一次运行时不可用.

Erk*_*rel 2

AFAIKAddOrUpdate不支持导航属性。此外,当AddOrUpdate没有通过输入获取任何属性时,它将使用属性的默认值保存它。

在您的情况下,您使用导航属性。

 city.Name = "Paris";
 city.Country = country;
Run Code Online (Sandbox Code Playgroud)

但由于缺乏支持导航属性,因此AddOrUpdate不会在内部分配。city.CountryId=country.Id所以你的city.CountryId值变成0,这是int的默认值。

您应该自己分配外键。

 var city = db.Cities.Create();
 city.Name = "Paris";
 city.Country = country;
 db.Cities.AddOrUpdate(q => q.Name, city);
Run Code Online (Sandbox Code Playgroud)

应该是这样的

 var city = db.Cities.Create();
 city.Name = "Paris";
 city.Country = country;
 //Assign foreign key by manually.
 city.CountryId = country.Id;
 db.Cities.AddOrUpdate(q => q.Name, city);
Run Code Online (Sandbox Code Playgroud)

我没有测试过。