IDbSetExtensions.AddOrUpdate和关系

时间:2012-03-19 19:52:49

标签: c# entity-framework

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?

1 个答案:

答案 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();
    }
}