简体   繁体   English

将IDataRecord个别记录分组到集合

[英]Grouping IDataRecord individual records to a collection

I have data as listed below in database. 我在数据库中有如下列出的数据。

在此输入图像描述

I have following data access layer code that is working for simple scenarios.. But for the above scenario, I need result based on employeeID grouping .. All roles for an employee should come under one Employee object. 我有以下数据访问层代码,适用于简单的场景..但对于上面的场景,我需要基于employeeID grouping结果。 employeeID grouping所有角色都应该在一个Employee对象下。

How can we achieve this by modifying the following data access code using the generic delegate features of C# ? 我们如何通过使用C#的通用委托功能修改以下数据访问代码来实现这一目标?

Note: I am looking for a solution that does not use DataTable (since DataTable loads all data upfront and is slower than the IDataRecord approach). 注意:我正在寻找一种不使用DataTable的解决方案(因为DataTable预先加载所有数据并且比IDataRecord方法慢)。

REFERENCES 参考

  1. An Elegant C# Data Access Layer using the Template Pattern and Generics 使用模板模式和泛型的优雅C#数据访问层
  2. Using C# generics and factory classes to map IDataReader to POCO 使用C#泛型和工厂类将IDataReader映射到POCO

Data Transfer Object 数据传输对象

public class Role
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }
}


public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public List<Role> Roles { get; set; }

    //IDataRecord Provides access to the column values within each row for a DataReader
    //IDataRecord is implemented by .NET Framework data providers that access relational databases.

    //Factory Method
    public static Employee EmployeeFactory(IDataRecord record)
    {
        return new Employee
        {
            EmployeeID = (int)record[0],
            EmployeeName = (string)record[1]
        };
    }
}

Common DAL 常见的DAL

public class MyCommonDAL
{
    public static IEnumerable<T> ExecuteQueryGenericApproach<T>(string commandText, List<SqlParameter> commandParameters, Func<IDataRecord, T> factoryMethod)
    {
        string connectionString = @"Server=TRVMVSDDVXXXX;Database=AS400_Source;User Id=XXXXXXXX;Password=XXXXXXX";

        //Action, Func and Predicate are pre-defined Generic delegates.
        //So as delegate they can point to functions with specified signature.

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = connection;
                command.CommandType = CommandType.Text;
                command.CommandText = commandText;
                command.CommandTimeout = 0;
                command.Parameters.AddRange(commandParameters.ToArray());

                connection.Open();
                using (var rdr = command.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        yield return factoryMethod(rdr);
                    }
                    rdr.Close();
                }
            }
        }
    }
}

Specific DAL 特定DAL

public class MyEmployeeDAL
{
    public List<Employee> GetEmployees(string excludedEmployee)
    {


        List<SqlParameter> commandParameters = new List<SqlParameter>()
                                                {
                                                    new SqlParameter {ParameterName = "@ExcludedEmployee", 
                                                                      Value = excludedEmployee, 
                                                                      SqlDbType = SqlDbType.VarChar}
                                                };


        string commandText = @"SELECT E.EmployeeID,E.EmployeeName,R.RoleID,R.RoleName FROM dbo.EmployeeRole ER
                                INNER JOIN dbo.Employee E  ON E.EmployeeID= ER.EmployeeID
                                INNER JOIN dbo.[Role] R ON R.RoleID= Er.RoleID 
                                WHERE EmployeeName <> @ExcludedEmployee";

        IEnumerable<Employee> employees = MyCommonDAL.ExecuteQueryGenericApproach<Employee>(commandText, commandParameters, Employee.EmployeeFactory);
        return employees.ToList();
    }
}

Client 客户

    static void Main(string[] args)
    {
        MyEmployeeDAL logDAL = new MyEmployeeDAL();
        List<Employee> logSeverities = logDAL.GetEmployees("test");
    }

You should add new flat class 你应该添加新的平面类

public class RoleAndEmployee
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }

    public static Employee EmployeeFactory(IDataRecord record)
    {
        return new RoleAndEmployee
        {
            EmployeeID = (int)record[0],
            EmployeeName = (string)record[1],
            RoleID = (int)record[2],
            RoleName = (string)record[3]
        };
    }
}

and call (i hope, i write it correct without IDE): 并打电话(我希望,没有IDE我写得正确):

IEnumerable<Employee> employees = MyCommonDAL.ExecuteQueryGenericApproach<RoleAndEmployee>(commandText, commandParameters, RoleAndEmployee.EmployeeFactory)
    .GroupBy(c=>new {c.EmployeeId, c.EmployeeName}, c=>new{c.RoleId, c.RoleName})
    .Select(k=>new Employee{EmployeeId=k.Key.EmployeeId, EmployeeName= k.Key.EmployeeName, Roles = k.ToList()});

Update: If you don't want introduce flat class, you can use next approach: 更新:如果您不想引入平面类,可以使用下一种方法:

public static Employee EmployeeFactory(IDataRecord record)
{
    var employee = new Employee
    {
        EmployeeID = (int)record[0],
        EmployeeName = (string)record[1],
        Roles = new List<Role>()
    };
    employee.Roles.Add(new Role{RoleID = (int)record[2], roleName=(string)record[3]});
    return employee;
}

IEnumerable<Employee> employees = MyCommonDAL.ExecuteQueryGenericApproach
    <Employee>(commandText, commandParameters, Employee.EmployeeFactory)
        .GroupBy(
            x => new { x.EmployeeID, x.EmployeeName},
            (key, group) => 
                new Employee
                    {
                        EmployeeId=key.EmployeeID, 
                        EmployeeName=key.EmployeeName,
                        Roles = group.SelectMany(v => v.Roles).ToList()
                    }).ToList();

For so to happen you need to assign values to Roles property of your Employee objects. 为此,您需要将值分配给Employee对象的Roles属性。

In factoryMethod you need to find distinct employees create object of the same and assign corresponding roles that you get from your query. 在factoryMethod中,您需要找到不同的员工创建相同的对象,并分配从查询中获得的相应角色。

This may help you query your table that you have got as a result. 可以帮助您查询您的表格。

After executing logDAL.GetEmployees("test") in your specific DAL, just group them. 在特定DAL中执行logDAL.GetEmployees("test")后,只需对它们进行分组。

IEnumerable<Employee> employees = MyCommonDAL.ExecuteQueryGenericApproach
        <Employee>(commandText, commandParameters, Employee.EmployeeFactory);
employees = employees.GroupBy(
                x => new
                    {
                        x.EmployeeID, 
                        x.EmployeeName
                    },
                (key, groupedEmployees) => 
                    new Employee
                        {
                            EmployeeId=key.EmployeeID, 
                            EmployeeName=key.EmployeeName,
                            Roles = groupedEmployees.SelectMany(v => v.Roles)
                        });
return employees.ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM