2013-12-20 49 views
3

我有以下數據庫中列出的數據。將IDataRecord個別記錄分組到一個集合

enter image description here

我有以下是工作簡單的場景數據訪問層的代碼。但對於上述方案,我需要的結果是基於employeeID grouping。對於僱員的所有角色應該來一個下Employee對象。

我們如何通過使用C#的通用委託功能修改以下數據訪問代碼來實現此目的?

注意:我正在尋找一個不使用DataTable的解決方案(因爲DataTable預先加載所有數據並且比IDataRecord方法慢)。

參考文獻

  1. An Elegant C# Data Access Layer using the Template Pattern and Generics
  2. Using C# generics and factory classes to map IDataReader to POCO

數據傳輸對象

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] 
     }; 
    } 
} 

常見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(); 
       } 
      } 
     } 
    } 
} 

具體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(); 
    } 
} 

客戶

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

回答

2

您應該添加新的平板類

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] 
     }; 
    } 
} 

和呼叫(我希望,我把它寫不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()}); 

更新: 如果你不」要引入平板類,可以使用下一種方法:

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(); 
+0

這將工作..但我正在尋找一種方法,而不引入平板類... – Lijo

+1

我更新我的答案。 –

+0

謝謝......它很有希望......如果您可以添加對LINQ的簡要說明,這將更有用。 – Lijo

0

對於這樣的情況發生,你需要將值分配給您的Employee對象的Roles財產。

在factoryMethod中,您需要找到不同的員工創建相同的對象並分配您從查詢中獲得的相應角色。

This可能會幫助您查詢您的表,因此您已得到該表。

+0

我已經alredy發佈了現有的完整代碼 - 包括ExecuteQueryGenericApproach – Lijo

+0

編輯請檢查 –

0

在您的特定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(); 
+0

我不能完全遵循這個..是否需要更改'EmployeeFactory'?我們如何獲取RoleID和RoleName? – Lijo