假设我有许多国家/地区,每个国家都有多个城市。我可以使用以下模型来表示:
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; }
}
实体框架正确识别外键并生成表。
但是,如果我现在尝试播种一些测试数据:
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();
}
}
}
第一次运行时,一切正常,数据库中的CountryId字段设置正确。但是,当我第二次运行它时,db.SaveChanges()
会尝试将Paris的CountryId设置为0,这违反了不可为空的外键约束。
问题似乎是,尽管city
和country
是更改跟踪代理,但CountryId
属性永远不会更新。但是,手动更新它对此没有帮助。
这是预期的行为,如果是这样,我怎样才能使用AddOrUpdate
而不改变这样?通过设置外键来完成所有操作似乎不是一个选项,因为在代码第一次运行时它们不可用。
答案 0 :(得分:1)
AFAIK AddOrUpdate
不支持导航属性。此外,当AddOrUpdate
没有通过输入获取任何属性时,它将使用默认值属性保存它。
在你的煽动中你使用导航属性。
city.Name = "Paris";
city.Country = country;
但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);
应该是这样的
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);
我没有测试过。
答案 1 :(得分:0)
也许你需要这个......
[Key]
public virtual int Id { get; set; }