我们正在采用代码优先的方法,并且在与一对多关系方面遇到麻烦。
我已将示例缩减为一些简单的类:
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();
但是,如果我们想要更新员工,我们就会遇到麻烦。
// Get Employee by Id
Employee employee = Repository.Employees.Single(p => p.Id ==<some id>);
employee.name = "My new name";
context.SaveChanges();
问题1:
如果我们使用
与上面的代码一样,我们注意到在调试时可以从Employee获得Dep对象。当我们浏览对象时,Dep被正确加载。
但是如果我们从Employee-class中删除virtual,就像这样:
,然后Dep始终为null。奇怪!
为什么会这样?是不是虚拟只是为了决定相关数据是否应该延迟加载?
问题2
由于我们仍然想要使用虚拟,所以麻烦从保存更新的Employee开始。它始终失败,并显示需要Dep的消息。员工已经有了Dep,我不想搞砸它。我只想更改员工的姓名。没有别的......
为什么在保存员工时会丢失Dep关系?
我可以在使用虚拟时使其工作,如果我确保Dep也是由
手动加载的或
但这真的很有必要吗?在这种情况下,我真的不关心Dep关系。我为什么要加载Dep-data?
答案 0 :(得分:1)
问题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; }
}
}
答案 1 :(得分:0)
问题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();