【问题标题】:How to Copy Data From Sql Object to C# Model Property如何将数据从 Sql 对象复制到 C# 模型属性
【发布时间】:2016-09-09 08:42:46
【问题描述】:

我有两张桌子:

  • 员工:IdNameDepartmentId
  • 部门:IdName

Employee.cs:

public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}

部门.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 类型。

【问题讨论】:

  • 可以使用反射来填充属性。 stackoverflow.com/questions/1089123/…
  • LEFT JOIN 时,将右侧表的条件放在 ON 子句中,以实现真正的左连接行为。 (在 WHERE 中,您会得到常规的内部连接结果。)即 ... ON E.DepartmentId = D.Id AND D.Id = 1
  • 为什么你不喜欢使用 EF..?如果您不使用此 ORM,则必须编写更多代码..
  • Karthik:我们的项目不是基于实体框架的。所以我必须使用传统的 ADO.Net。
  • 如果您首先展示您现在如何根据查询结果构建模型会很好。

标签: c# sql sql-server ado.net ado.net-entity-data-model


【解决方案1】:

我真的不明白有什么挑战。 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 查询意味着与部门相关的字段可以为空 (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();

【讨论】:

  • 是的。这个对我有用。一个问题。我可以使用 List 代替 Dictionary 吗?
  • 可以,但是如果不应用部门过滤器会效率低下。分组实现通常使用某种哈希数据结构(如 Dictionary)或排序结果集(如 EF)。字典只是临时的,如您所见,我将其转换为最后的列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 2018-09-13
  • 2013-12-02
  • 1970-01-01
相关资源
最近更新 更多