Entity Framework - 一对多关系有问题

Entity Framework - Trouble with one-to-many relationship

我们正在采用代码优先的方法,但在处理一对多关系时遇到了问题。

我已将示例简化为一些简单的 classes:

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

    [Required]
    public string name { get; set; }

    [Required]
    public virtual Dep dep { get; set; }

}

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

    [Required]
    public string name { get; set; }

    public virtual ICollection<Employee> Employees { get; set; }
}

像这样添加新值效果很好:

Dep dep = new Dep { name = "My Departement" };
Employee employee = new Employee { name = "My name" };
dep.Employees.Add(employee);

context.Deps.Add(dep);
context.SaveChanges();

但是,如果我们想更新一个 Employee,我们 运行 就会遇到麻烦。

// Get Employee by Id
Employee employee = Repository.Employees.Single(p => p.Id ==<some id>);
employee.name = "My new name";
context.SaveChanges();

问题一:

如果我们使用

在上面的代码中,我们注意到 Dep 对象在调试时可以从 Employee 获得。当我们浏览对象时,Dep 加载正常。

但是如果我们像这样从 Employee-class 中删除虚拟:

,则 Dep 始终为空。奇怪!

为什么会这样? virtual 不就是决定相关数据是否懒加载吗?

问题2

既然我们无论如何都想使用虚拟,那么麻烦就从保存更新的 Employee 开始。它总是失败并显示需要 Dep 的消息。 Employee 已经有一个 Dep,我不想惹它。我只想更改员工的姓名。没有别的...

为什么保存Employee时会丢失Dep关系?

我可以在使用虚拟时让它工作,如果我确保 Dep 也由

手动加载
  1. 添加一些代码以读取 Dep 对象中的一些值

  1. 调试和浏览 Dep 对象

但这一切真的有必要吗?在这种情况下,我真的不关心 Dep 关系。为什么我必须加载 Dep 数据?

问题1:virtual启用延迟加载,简单来说就是当你从数据库中检索记录时,它的相关实体也会被带入。 https://msdn.microsoft.com/en-us/data/jj574232.aspx

问题 2:

你能试试这个吗:

Employee employee = Repository.Employees.Include("Dep").Single(p => p.Id ==<some id>);
var entry = context.Entry(employee);
entry.Property(e => e.name ).IsModified = true;
// other changed properties
db.SaveChanges();

问题 2:

这是因为您使用了 [Required] 属性。在这种情况下,您要求框架(不仅是 EF)处理所需的约束。

如果您只想在 EF 级别应用约束,您应该使用流畅的 API:

public class testEF : DbContext {
    public IDbSet<Employee> Employees { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Configurations.Add(new EmployeeEFConfiguration());
    }
}

public class EmployeeEFConfiguration : EntityTypeConfiguration<Employee> {
    public EmployeeEFConfiguration() {
        HasRequired(x => x.Dep).WithMany(y => y.Employees);
    }
}

我刚刚做了测试。以前的代码运行。如果我使用 RequiredAttribute,我和你有同样的例外。

完整样本:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Linq;

namespace testEf6 {
    class Program {
        static void Main(string[] args) {
            using (testEF ctx = new testEF()) {
                C2 c2 = new C2 {
                    Name = "old name",
                    C1 = new C1 { }
                };

                ctx.C2s.Add(c2);
                ctx.SaveChanges();
            }

            using (testEF ctx = new testEF()) {
                C2 c2 = ctx.C2s.First();
                c2.Name = "new name";
                ctx.SaveChanges(); // exception here with the attribute ========
            }
        }
    }

    public class testEF : DbContext {
        public IDbSet<C2> C2s { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder) {
            //modelBuilder.Configurations.Add(new C2EFConfiguration());
        }
    }

    public class C2EFConfiguration : EntityTypeConfiguration<C2> {
        public C2EFConfiguration() {
            HasRequired(x => x.C1).WithMany(y => y.C2s);
        }
    }

    public class C1 {
        public int Id { get; set; }
        public virtual ICollection<C2> C2s { get; set; }
    }

    public class C2 {
        public int Id { get; set; }
        public String Name { get; set; }
        [Required] 
        public virtual C1 C1 { get; set; }

    }
}