Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# IDbSetExtensions.AddOrUpdate和关系_C#_Entity Framework - Fatal编程技术网

C# IDbSetExtensions.AddOrUpdate和关系

C# IDbSetExtensions.AddOrUpdate和关系,c#,entity-framework,C#,Entity Framework,IDbSetExtensions.AddOrUpdate旨在帮助编写在数据库为空或已填充的情况下都能正常工作的代码。但是链接对象需要不同的代码。当数据库为空时,对象还没有ID,您可以通过指定导航属性来链接它们。但是,当对象已经存在时,导航属性不起作用,您需要直接设置外键。导航属性在这两种情况下都适用于代理,但代价是没收POCO。编辑:实际上,当两个实体都是旧的时,代理不起作用 当EF尝试将CountryID设置为0时,此示例在第二次SaveChanges调用中崩溃: public class C

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();
    }
}
公共类国家
{
公共虚拟整数ID{get;set;}
公共虚拟字符串名称{get;set;}
}
公共阶层人士
{
公共虚拟整数ID{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟int CountryID{get;set;}
公共虚拟国家{get;set;}
}
公共类上下文:DbContext
{
公共DbSet Person{get;set;}
公共数据库集国家{get;set;}
}
班级计划
{
静态void Foo()
{
使用(var db=new Context())
{
//var c=新国家();
var c=db.Country.Create();
c、 Name=“美国”;
db.Country.AddOrUpdate(x=>x.Name,c);
//var p=新人();
var p=db.Person.Create();
p、 Name=“billg”;
p、 国家=c;
db.Person.AddOrUpdate(x=>x.Name,p);
db.SaveChanges();
}
}
静态void Main()
{
SetInitializer(新的DropCreateDatabaseAlways());
Foo();
Foo();
}
}
如何使用AddOrUpdate

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

我强烈建议你阅读它,我缩短了我的代码粘贴在这里。我的应用程序仅在dbmigtorinsconfiguration.Seed覆盖中使用AddOrUpdate。您的示例有效,但我对同时指定Country和CountryID感到不安。您是否建议始终同时指定这两个选项?我的应用程序使用复合键,只分配导航属性更容易、更清晰、更不容易出错。@BrunoMartinez AddOrUpdate不会设置导航属性(和数据库)所依赖的外键值-即使该实体已被“添加或更新”或直接查询(EF应该能够修复关系)。实际上,您只需设置FK,除非稍后需要在种子中导航关系。此外,如果要将关系用作
identifierExpression
的一部分,则必须使用FK Id,因为它必须是基元或枚举值,并且属性映射到列-不能使用其他实体。RE:“只分配导航属性更容易、更清晰、更不容易出错。”我建议为您的实体添加一些扩展方法到
AddRelatedEntity(RelatedEntity){..}
,或者只使用本机
DbSet
方法基本上编写您自己的
AddOrUpdate()
。令人沮丧的是,此API表面没有遵循与其他DbContext/DbSet操作相同的约定\_(ツ)_/¯