我有2个班级,作为一对多的关系。这种关系的结构如下:
public partial class Department
{
public Department()
{
this.Employees = new HashSet<Employee>();
}
public int DepartmentId { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public partial class Employee
{
public int EmployeeId { get; set; }
public int DepartmentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public virtual Department Department { get; set; }
}
当我创建一个新的Employee对象并为其分配一个现有的部门时,EF会在我的数据库中创建一个新的Employee对象以及一个新的部门记录,但这不是我想要的。我希望创建员工记录,但要引用现有的部门对象。这是我的商业代码:
IEmployeeBiz employeeBiz = new EmployeeBiz();
IDepartmentBiz departmentBiz = new DepartmentBiz();
Department department = new Department();
department.Name = "Testing";
departmentBiz.Add(department); // add to db
Employee employee = new Employee();
employee.FirstName = "James";
employee.LastName = "Bond";
employee.Department = department; // add existing department to new employee
employeeBiz.Add(employee); // add to db
如您所见,我将Department对象分配给employee.Department,此创建的DAL代码如下,我正在使用通用DAL:
public virtual void Add(T[] items)
{
using (var context = new DbConnect())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Added;
}
context.SaveChanges();
}
}
我知道我可以通过在我的员工对象上分配departmentId来解决这个问题,但我希望我的代码可以在我将子Department对象分配给父Employee对象的地方工作。
我怎样才能以我想要的方式工作?
答案 0 :(得分:0)
“部门”有一个“员工”集合,“员工”有“部门”属性。这是一个递归设计,不知道,如果EF可以处理这个。这看起来像是一个设计错误。
顺便说一句:使用GraphDiff在EF中非常优雅。这是一个没有详细记录,但非常有效的EF扩展用于更新整个图形。 https://www.nuget.org/packages/RefactorThis.GraphDiff/
答案 1 :(得分:0)
您的一对多关系配置不正确。您的员工需要为其所属的部门指定外键
class Employee
{
public int EmployeeId {get; set;}
// every employee belongs to exactly one Department
public int DepartmentId {get; set;}
public virtual Department Department {get; set;}
... // other properties, not meaningful for this question
}
如果您想介绍员工以及新部门,您可以按照以下方式执行此操作:
var addedEmployee = myDbcontext.Employees.Add(new Employe()
{
FirstName = ...;
...
Department = new Department()
{
Name = "My beautiful launderette",
},
});
如果您想将新员工引入现有部门,您必须先获取此部门,或者只是分配DepartmentId
int departmentId = ...
var addedEmployee = myDbcontext.Employees.Add(new Employe()
{
FirstName = ...;
...
DepartmentId = departmentId,
});
如果您以不同方式获取现有部门,那么您应该拥有可以使用的ID:
Department existingDepartment = ..
var addedEmployee = myDbcontext.Employees.Add(new Employe()
{
FirstName = ...;
...
DepartmentId = existingDepartmenr.DepartmentId,
});
或者,但不可取,因为您不会轻易看到您是使用现有部门还是创建新部门:
Department someDepartment = ..
var addedEmployee = myDbcontext.Employees.Add(new Employe()
{
FirstName = ...;
...
Department = someDepartment,
});
实体框架将使用someDepartment.DepartmentId检测someDepartment是否已存在。那么为什么不自己使用呢?它只会保护您和未来的读者不会意外地创建新的部门。
最后:在Department的构造函数中创建Hashset是没用的。使用它时会立即丢弃:
// fetch some departments:
var result = myDbContext.Departments
.Where(department => department.Name = ...)
.ToList();
这里将创建一个带有空哈希集的部门,它将立即被从数据库中提取的虚拟ICollection所取代
// Introduce a Department with several employees:
var introducedDepartment = myDbContext.Departments.Add(new Department()
{
Name = ...
Employees = new List<Employee>()
{
new Employee() {Name = ... etc},
new Employee() {Name = ... etc},
new Employee() {Name = ... etc},
},
});
这里创建了一个具有HashSet的部门。此哈希集会立即被丢弃,并替换为新的员工列表。
那么为什么要构造HashSet呢?