IDbSetExtensions.AddOrUpdate旨在帮助编写无论数据库为空还是填充的代码。但链接对象需要不同的代码。当数据库为空时,对象还没有ID,您可以通过分配导航属性来链接它们。但是,当对象已存在时,导航属性不起作用,您需要直接设置外键。 导航属性在两种情况下都适用于代理,代价是放弃POCO。编辑:实际上,当两个实体都旧时,代理不起作用。
当EF尝试将CountryID设置为0时,此示例在第二个SaveChanges调用中崩溃:
public class Country
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
public class Person
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual int CountryID { get; set; }
public virtual Country Country { get; set; }
}
public class Context : DbContext
{
public DbSet<Person> Person { get; set; }
public DbSet<Country> Country { get; set; }
}
class Program
{
static void Foo()
{
using (var db = new Context())
{
//var c = new Country();
var c = db.Country.Create();
c.Name = "usa";
db.Country.AddOrUpdate(x => x.Name, c);
//var p = new Person();
var p = db.Person.Create();
p.Name = "billg";
p.Country = c;
db.Person.AddOrUpdate(x => x.Name, p);
db.SaveChanges();
}
}
static void Main()
{
Database.SetInitializer<Context>(new DropCreateDatabaseAlways<Context>());
Foo();
Foo();
}
}
如何使用AddOrUpdate?
答案 0 :(得分:9)
IDbSetExtensions.AddOrUpdate旨在帮助编写无论数据库为空还是已填充的代码。
AddOrUpdate
仅用于Seed
代码首次迁移方法。它不应该在普通代码中使用,因为它有很大的开销和一些限制。开销是对数据库和反射的附加查询。限制是它只检查您传递的主要实体,而不检查其关系。每个关系应该通过单独调用AddOrUpdate
:
static void Foo()
{
using (var db = new Context())
{
var c = new Country() {Name = "abc"};
db.Country.AddOrUpdate(x => x.Name, c);
var p = new Person()
{
Name = "me",
CountryID = c.ID,
Country = c
};
db.Person.AddOrUpdate(x => x.Name, p);
db.SaveChanges();
}
}