public class DataTableJoiner
{
#region Variables
private LibDataTable left;
private List<Joiner> _joiners = new List<Joiner>();
#endregion
#region Constructor
public DataTableJoiner(LibDataTable left)
{
Left = left;
}
#endregion
#region Property
public LibDataTable Left
{
get { return left; }
set { left = value; }
}
public List<Joiner> Joiners
{
get { return _joiners; }
set { _joiners = value; }
}
#endregion
#region Public Method
public LibDataTable Execute()
{
foreach (Joiner joiner in _joiners)
{
switch (joiner.JoinType)
{
case JoinType.Left:
LeftJoin(joiner);
break;
case JoinType.Inner:
InnerJoin(joiner);
break;
case JoinType.Full:
FullJoin(joiner);
break;
}
}
return left;
}
public LibDataTable Join()
{
return Execute();
}
#endregion
#region Private Metod
/// <summary>
/// 内连接,实现SQL中的inner join
/// </summary>
/// <returns></returns>
private void InnerJoin(Joiner joiner)
{
LibDataTable result = MergeColumns(joiner.Right);
foreach (DataRow leftRow in Left.Rows)
{
DataRow[] rightRows = joiner.Right.Select(joiner.On(leftRow));
foreach (DataRow rightRow in rightRows)
{
DataRow mergedRow = result.NewRow();
CopyRow(leftRow, mergedRow);
CopyRow(rightRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
}
left = result;
}
/// <summary>
/// 左连接,实现SQL中的inner join
/// </summary>
/// <returns></returns>
private void LeftJoin(Joiner joiner)
{
LibDataTable result = MergeColumns(joiner.Right);
foreach (DataRow leftRow in Left.Rows)
{
DataRow[] rightRows = joiner.Right.Select(joiner.On(leftRow));
if (rightRows.Length == 0)
{
DataRow mergedRow = result.NewRow();
CopyRow(leftRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
else
{
foreach (DataRow rightRow in rightRows)
{
DataRow mergedRow = result.NewRow();
CopyRow(leftRow, mergedRow);
CopyRow(rightRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
}
}
left = result;
}
/// <summary>
/// 全连接,实现SQL中的inner join
/// </summary>
/// <returns></returns>
private void FullJoin(Joiner joiner)
{
try
{
LibDataTable result = MergeColumns(joiner.Right);
List<DataRow> mergedRows = new List<DataRow>();
foreach (DataRow leftRow in Left.Rows)
{
DataRow[] rightRows = joiner.Right.Select(joiner.On(leftRow));
if (rightRows.Length == 0)
{
DataRow mergedRow = result.NewRow();
CopyRow(leftRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
else
{
foreach (DataRow rightRow in rightRows)
{
DataRow mergedRow = result.NewRow();
CopyRow(leftRow, mergedRow);
CopyRow(rightRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
mergedRows.AddRange(rightRows);
}
}
foreach (DataRow rigtRow in joiner.Right.Rows)
{
if (mergedRows.Contains(rigtRow)) continue;
DataRow mergedRow = result.NewRow();
CopyRow(rigtRow, mergedRow);
result.Rows.Add(mergedRow);
result.AcceptChanges();
}
left = result;
}
catch (Exception ex)
{
throw new Exception(String.Format("Talbe:{0},Message:{1}", joiner.Right.TableName, ex.Message), ex);
}
}
private static void CopyRow(DataRow sourceRow, DataRow targetRow)
{
foreach (DataColumn column in targetRow.Table.Columns)
{
if (sourceRow.Table.Columns.IndexOf(column.ColumnName) < 0) continue;
targetRow[column.ColumnName] = sourceRow[column.ColumnName];
}
}
/// <summary>
/// 创建具有left和join指定列的LibDataTable
/// </summary>
/// <returns></returns>
private LibDataTable MergeColumns(LibDataTable right)
{
LibDataTable result = new LibDataTable(left.TableName);
foreach (DataColumn column in Left.Columns)
{
DataColumn col = new DataColumn(column.ColumnName, column.DataType);
if (IsNumType(column))
{
col.DefaultValue = 0;
}
result.Columns.Add(col);
}
foreach (DataColumn column in right.Columns)
{
if (result.Columns[column.ColumnName] != null) continue;
DataColumn col = new DataColumn(column.ColumnName, column.DataType);
if (IsNumType(column))
{
col.DefaultValue = 0;
}
result.Columns.Add(col);
}
return result;
}
private static bool IsNumType(DataColumn column)
{
return column.DataType == typeof(Int32)
|| column.DataType == typeof(Decimal)
|| column.DataType == typeof(Int16)
|| column.DataType == typeof(Int64)
|| column.DataType == typeof(Single)
|| column.DataType == typeof(Double)
|| column.DataType == typeof(Byte)
;
}
#endregion
#region Public Static Method
public static LibDataTable LeftJoin(Joiner.JoinDelegate joinDelegate, LibDataTable left, params LibDataTable[] joinTBs)
{
return Join(JoinType.Left, joinDelegate, left, joinTBs);
}
public static LibDataTable InnerJoin(Joiner.JoinDelegate joinDelegate, LibDataTable left, params LibDataTable[] joinTBs)
{
return Join(JoinType.Inner, joinDelegate, left, joinTBs);
}
public static LibDataTable FullJoin(Joiner.JoinDelegate joinDelegate, LibDataTable left, params LibDataTable[] joinTBs)
{
return Join(JoinType.Full, joinDelegate, left, joinTBs);
}
public static LibDataTable Join(JoinType joinType, Joiner.JoinDelegate joinDelegate, LibDataTable left, params LibDataTable[] joinTBs)
{
DataTableJoiner tableJoiner = new DataTableJoiner(left);
foreach (LibDataTable rightTb in joinTBs)
{
tableJoiner.Joiners.Add(new Joiner(joinType, rightTb, joinDelegate));
}
return tableJoiner.Execute();
}
#endregion
}
public class Joiner
{
/// <summary>
///
/// </summary>
/// <param name="leftRow"></param>
/// <example>
/// <code>
/// Joiner.JoinDelegate joinDelegate = delegate(DataRow leftRow) {return String.Format("Opara={0}",leftRow["Opara"]); };
/// </code>
/// </example>
/// <returns></returns>
public delegate string JoinDelegate(DataRow leftRow);
private LibDataTable _right;
private JoinType _joinType;
private JoinDelegate _on;
public Joiner(JoinType joinType, LibDataTable right, JoinDelegate on)
{
On = on;
Right = right;
JoinType = joinType;
}
public JoinDelegate On
{
get { return _on; }
set { _on = value; }
}
public LibDataTable Right
{
get { return _right; }
set { _right = value; }
}
public JoinType JoinType
{
get { return _joinType; }
set { _joinType = value; }
}
}
public enum JoinType
{
Left,
Inner,
Full
}
eg:
public LibDataTable mergeDataTable(LibDataTable left, LibDataTable right, string checkColumn)
{
LibDataTable result = DataTableJoiner.FullJoin(delegate(DataRow leftRow) { return String.Format(checkColumn + "='{0}'", leftRow[checkColumn]); }, left, right);
return result;
}