如何将数据从Sql对象复制到C#模型属性

Bim*_*Das 10 c# sql sql-server ado.net ado.net-entity-data-model

我有两张桌子:

  • 员工:Id,Name,DepartmentId
  • 部门:Id,Name

Employee.cs:

public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}
Run Code Online (Sandbox Code Playgroud)

Department.cs:

public int Id {get;set;}
public string Name {get;set;}
Run Code Online (Sandbox Code Playgroud)

ViewModel:EmployeeDepartmentVM:

public Department department {get;set;}
public List<Employee> employees {get;set;}
Run Code Online (Sandbox Code Playgroud)

要加入这两个表我写了这段代码:

    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
Run Code Online (Sandbox Code Playgroud)

如何从上面的查询中获取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;}
Run Code Online (Sandbox Code Playgroud)

但我不想写额外的模型.只需要将查询数据绑定到EmployeeDepartmentVM类型.

Iva*_*oev 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();
}
Run Code Online (Sandbox Code Playgroud)

有些事情需要注意.编写的方式,您的SQL查询意味着Department相关字段可以为null(LEFT OUTER JOIN).但是,该WHERE子句以及Employee模型(DepartmentId字段不可为空)意味着它不会发生.如果意图包括没有员工的部门,那么最好将连接更改为RIGHT OUTER并使用如下内容:

// ...
if (reader.IsDBNull(employeeIdCol)) continue;
var employee = new Employee();
// ...  
Run Code Online (Sandbox Code Playgroud)

编辑:为了完整性,这是另一种方法.它与EF实现类似查询的方式类似,不需要临时字典,但需要输入集由主表的PK排序,因此需要添加

ORDER BY D.Id
Run Code Online (Sandbox Code Playgroud)

在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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要获得第一种方法中的列表,只需ToList()在通话后添加,例如

var result = GetEmployeeDepartmentVMs(command).ToList();
Run Code Online (Sandbox Code Playgroud)