Entity Framework - 一对多关系有问题
Entity Framework - Trouble with one-to-many relationship
我们正在采用代码优先的方法,但在处理一对多关系时遇到了问题。
- 一个部门 (Dep) 有一个员工列表。
- 每个员工都属于一个部门。 (必填)
- 我想更新员工姓名。 (不接触 Dep)
我已将示例简化为一些简单的 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();
问题一:
如果我们使用
- public virtual Dep dep { get;放; }
在上面的代码中,我们注意到 Dep 对象在调试时可以从 Employee 获得。当我们浏览对象时,Dep 加载正常。
但是如果我们像这样从 Employee-class 中删除虚拟:
- public Dep dep { get;放; }
,则 Dep 始终为空。奇怪!
为什么会这样? virtual 不就是决定相关数据是否懒加载吗?
问题2
既然我们无论如何都想使用虚拟,那么麻烦就从保存更新的 Employee 开始。它总是失败并显示需要 Dep 的消息。 Employee 已经有一个 Dep,我不想惹它。我只想更改员工的姓名。没有别的...
为什么保存Employee时会丢失Dep关系?
我可以在使用虚拟时让它工作,如果我确保 Dep 也由
手动加载
- 添加一些代码以读取 Dep 对象中的一些值
或
- 调试和浏览 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; }
}
}
我们正在采用代码优先的方法,但在处理一对多关系时遇到了问题。
- 一个部门 (Dep) 有一个员工列表。
- 每个员工都属于一个部门。 (必填)
- 我想更新员工姓名。 (不接触 Dep)
我已将示例简化为一些简单的 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();
问题一:
如果我们使用
- public virtual Dep dep { get;放; }
在上面的代码中,我们注意到 Dep 对象在调试时可以从 Employee 获得。当我们浏览对象时,Dep 加载正常。
但是如果我们像这样从 Employee-class 中删除虚拟:
- public Dep dep { get;放; }
,则 Dep 始终为空。奇怪!
为什么会这样? virtual 不就是决定相关数据是否懒加载吗?
问题2
既然我们无论如何都想使用虚拟,那么麻烦就从保存更新的 Employee 开始。它总是失败并显示需要 Dep 的消息。 Employee 已经有一个 Dep,我不想惹它。我只想更改员工的姓名。没有别的...
为什么保存Employee时会丢失Dep关系?
我可以在使用虚拟时让它工作,如果我确保 Dep 也由
手动加载- 添加一些代码以读取 Dep 对象中的一些值
或
- 调试和浏览 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; }
}
}