EF 0..1到多个关系更新

War*_*War 5 c# sql-server entity-framework foreign-keys entity-framework-6

我无法理解这一点,线索遍布SO状态我正在做所有正确的事情,但显然我一定错过了一些东西......

鉴于这两个对象defs ...

public class Invoice
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("Block")]
    public int? BlockingCodeId { get; set; }

    public virtual BlockingCode Block { get; set; }

    ...

}

public class BlockingCode
{
    [Key]
    public int Id { get; set; }
    public virtual ICollection<Invoice> Invoices { get; set; }
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后用适当的关系配置上下文...

public class FaureciaContext : EFDataContext
{
    public virtual DbSet<Invoice> Invoices { get; set; }
    public virtual DbSet<BlockingCode> BlockingCodes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Invoice>()
            .HasOptional(e => e.Block)
            .WithMany(e => e.Invoices);
    }
}
Run Code Online (Sandbox Code Playgroud)

我为什么这样做......

// assume this invoice has a BlockingCode relationship
var invoice = db.Invoices.First();
invoice.BlockingCodeId = null;
db.Savechanges();
Run Code Online (Sandbox Code Playgroud)

我得到这个例外......

操作失败:无法更改关系,因为一个或多个外键属性不可为空.当对关系进行更改时,相关的外键属性将设置为空值.如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象.

编辑:

我想我会补充一下,因为这里的答案并没有真正指出我遇到的问题的真正答案......

事实证明,有问题的引用并不是我实际上更新发票类的另一个子属性的问题,因为这样的代码......

invoice.Lines = MergLines(newVersion, dbVersion);
Run Code Online (Sandbox Code Playgroud)

我的合并代码工作正常,但任何敏锐的EF用户都知道你不能简单地"替换这样的子集合",你必须删除旧的并适当添加新的.

小智 1

因此,从我假设的您正在使用的基本 SQL 表结构进行逆向工程......

块表:

块表定义

发票表:

发票表定义

并在 Invoice.BlockingCodeId 和 Block.Id 之间定义外键关系...

FK关系

当让 EF 从物理数据库创建它们时,我得到以下代码优先实体类和上下文:

[Table("Block")]
public partial class Block
{
    public Block()
    {
        Invoices = new HashSet<Invoice>();
    }

    public int Id { get; set; }

    [Required]
    [StringLength(50)]
    public string Description { get; set; }

    public virtual ICollection<Invoice> Invoices { get; set; }
}

[Table("Invoice")]
public partial class Invoice
{
    public int Id { get; set; }

    public int? BlockingCodeId { get; set; }

    [Required]
    [StringLength(50)]
    public string Description { get; set; }

    public virtual Block Block { get; set; }
}

public partial class TestContext : DbContext
{
    public TestContext()
        : base("name=TestContext")
    {
    }

    public virtual DbSet<Block> Blocks { get; set; }
    public virtual DbSet<Invoice> Invoices { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Block>()
            .HasMany(e => e.Invoices)
            .WithOptional(e => e.Block)
            .HasForeignKey(e => e.BlockingCodeId);
    }
}
Run Code Online (Sandbox Code Playgroud)

当实体和上下文按照上面的方式配置时,以下代码执行时不会出现问题,并且我会在 SQL 数据库中看到我所期望的内容:

var context = new TestContext();
var block = new Block { Description = "Block 1" };
var invoices = new List<Invoice>
                    {
                        new Invoice { Description = "Invoice 1" },
                        new Invoice { Description = "Invoice 2" }
                    };

invoices.ForEach(i => block.Invoices.Add(i));
context.Blocks.Add(block);
context.SaveChanges();

block = null;
var invoice = context.Invoices.First();
invoice.Block = null;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

执行后,结果数据状态是...

块表:

块数据

发票表:

发票数据