我有两张桌子:
Id
,Name
,DepartmentId
Id
,Name
Employee.cs:
public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}
Department.cs:
public int Id {get;set;}
public string Name {get;set;}
ViewModel:EmployeeDepartmentVM:
public Department department {get;set;}
public List<Employee> employees {get;set;}
为了加入这两个表,我编写了这段代码:
SELECT E.* , D.Id as DId , D.Name as DName
from [Employee] as E
LEFT OUTER JOIN [Department] as D
ON E.DepartmentId = D.Id
where D.Id = 1
如何从上述查询中获取EmployeeDepartmentVM类型?
我知道如果我写一个像我的问题的模型将会被解决:
public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}
public int DId {get;set;}
public string Name {get;set;}
但我不想写额外的模型。只需要将查询数据绑定到EmployeeDepartmentVM类型。
答案 0 :(得分:7)
我真的不明白什么是挑战。 EmployeeDepartmentVM
定义意味着您需要按Department
对结果集进行分组。假设结果集是无序的,可以通过简单地维护字典来实现,该字典用于在读取期间定位已经添加的部门的视图模型。
导致类似这样的事情:
static List<EmployeeDepartmentVM> GetEmployeeDepartmentVMList(DbCommand command)
{
var resultById = new Dictionary<int, EmployeeDepartmentVM>();
using (var reader = command.ExecuteReader())
{
var employeeIdCol = reader.GetOrdinal("Id");
var employeeNameCol = reader.GetOrdinal("Name");
var departmentIdCol = reader.GetOrdinal("DId");
var departmentNameCol = reader.GetOrdinal("DName");
while (reader.Read())
{
var departmentId = reader.GetInt32(departmentIdCol);
EmployeeDepartmentVM result;
if (!resultById.TryGetValue(departmentId, out result))
{
result = new EmployeeDepartmentVM
{
department = new Department(),
employees = new List<Employee>()
};
result.department.Id = departmentId;
result.department.Name = reader.GetString(departmentNameCol);
resultById.Add(departmentId, result);
}
var employee = new Employee();
employee.Id = reader.GetInt32(employeeIdCol);
employee.Name = reader.GetString(employeeNameCol);
employee.DepartmentId = departmentId;
result.employees.Add(employee);
}
}
return resultById.Values.ToList();
}
有些事情需要注意。编写的方式,您的SQL查询意味着Department相关字段可以为null(LEFT OUTER JOIN
)。但是,WHERE
子句以及Employee模型(DepartmentId
字段不可为空)意味着它不会发生。如果意图包括没有员工的部门,那么最好将联接更改为RIGHT OUTER
并使用以下内容:
// ...
if (reader.IsDBNull(employeeIdCol)) continue;
var employee = new Employee();
// ...
编辑:为了完整起见,这是另一种方法。它与EF实现类似查询的方式类似,不需要临时字典,但需要输入集由主表的PK排序,因此需要添加
ORDER BY D.Id
在SQL结束时。数据库可以轻松有效地提供此类排序,此解决方案的好处是它允许延迟执行,并且不需要处理整个集合以便开始返回结果。如果您想获得一个列表,这不是必需的,但在其他场景中可能很有用。
static IEnumerable<EmployeeDepartmentVM> GetEmployeeDepartmentVMs(DbCommand command)
{
using (var reader = command.ExecuteReader())
{
var employeeIdCol = reader.GetOrdinal("Id");
var employeeNameCol = reader.GetOrdinal("Name");
var departmentIdCol = reader.GetOrdinal("DId");
var departmentNameCol = reader.GetOrdinal("DName");
for (bool more = reader.Read(); more;)
{
var result = new EmployeeDepartmentVM
{
department = new Department(),
employees = new List<Employee>()
};
result.department.Id = reader.GetInt32(departmentIdCol);
result.department.Name = reader.GetString(departmentNameCol);
do
{
if (reader.IsDBNull(employeeIdCol)) continue;
var employee = new Employee();
employee.Id = reader.GetInt32(employeeIdCol);
employee.Name = reader.GetString(employeeNameCol);
employee.DepartmentId = result.department.Id;
result.employees.Add(employee);
}
while ((more = reader.Read()) && reader.GetInt32(departmentIdCol) == result.department.Id);
Debug.Assert(!more || reader.GetInt32(departmentIdCol) > result.department.Id); // Sanity check
yield return result;
}
}
}
要像第一种方法一样获取列表,只需在通话后添加ToList()
,例如
var result = GetEmployeeDepartmentVMs(command).ToList();