Cómo: Implementar una clase auxiliar JOIN a DataSet en Visual C#.

Para una versión de Microsoft Visual Basic .NET de este artículo, consulte

325688 Cómo: implementar una clase auxiliar JOIN de DataSet en Visual Basic .NET
Nota: este artículo es parte de una serie de artículos sobre DataSetHelper . Puede combinar el código en la clase sobre DataSetHelper que se enumera en este artículo con el código que se proporciona en otros artículos sobre DataSetHelper hacer una sola clase con un conjunto de características más completo.


En este artículo se refiere a los siguientes espacios de nombres de biblioteca de clases de Microsoft.NET Framework:
  • System.Data

EN ESTA TAREA

Resumen

En este artículo paso a paso se describe cómo implementar y cómo utilizar una clase sobre DataSetHelper que incluye código de ejemplo para crear un objeto DataTable entre dos o más definiciones de DataTable relacionadas y copiar registros que están ordenados y filtrados desde los objetos DataTable de origen al destino DataTable.

Para ello, utilice los siguientes métodos públicos:

  • CreateJoinTable
  • InsertJoinInto
  • SelectJoinInto
El método SelectJoinInto llama el CreateJoinTable y los métodos InsertJoinInto . También puede utilizar a un miembros de datos y el método auxiliar privado para almacenar la lista campo analizada.

La clase sobre DataSetHelper incluye una variable de miembro de conjunto de datos . Opcionalmente, puede asignar un conjunto de datos de existente a la variable de miembro de conjunto de datos . Si la variable miembro apunta a un DataSetválido, los objetos DataTable que crea el CreateJoinTable o el método SelectJoinInto se agregan al DataSet. En cualquier caso, la llamada al método devuelve una referencia al objeto DataTable . El método InsertJoinInto requiere un destino existente DataTable y no devuelve nada.

Para obtener más información sobre los objetos DataSet , haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:

313485 INFO: Guía básica de ADO.NET DataSet, DataView y DataViewManager

Requisitos

La lista siguiente describe el hardware recomendado, software, infraestructura de red y service packs que se necesitan:

  • Microsoft Windows XP, Windows 2000 o Windows NT 4.0 Service Pack 6a
  • Microsoft Visual Studio .NET
En este artículo se supone que está familiarizado con los temas siguientes:

  • Sintaxis de Visual C#.
  • Fundamentos ADO.NET y sintaxis

Clase sobre DataSetHelper Shell

El código de esta sección declara la clase de shell para que todos los artículos sobre DataSetHelper agregar métodos y variables miembro.
  1. Inicie Visual Studio. NET.
  2. En el menú archivo, elija nuevo y, a continuación, haga clic en proyecto.
  3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyectoy, a continuación, haga clic en Biblioteca de clases en plantillas.
  4. En el cuadro nombre , escriba sobre DataSetHelper.
  5. Reemplace el código de la clase con el código siguiente:
    public class DataSetHelper{
    public DataSet ds;

    public DataSetHelper(ref DataSet DataSet)
    {
    ds = DataSet;
    }
    public DataSetHelper()
    {
    ds = null;
    }
    }

    Puede utilizar las dos sobrecargas del constructor para crear una instancia de la clase, con o sin una referencia a un conjunto de datosválido. Para una clase que contiene una referencia a un DataSetválido, los objetos DataTable que devuelven los métodos también se agregan automáticamente al conjunto de datos.

Analizador de lista de campos

Esta sección contiene el código de un analizador de lista de campos. La estructura analizada se utiliza para que la CreateJoinTable y los métodos InsertJoinInto no tienen que analizar la lista de campos. Estos métodos deben reanálisis la lista de campos si se les llama desde el método SelectJoinInto o su propio código. La lista campo analizada y la lista de campos sin analizar se almacenan en variables miembro privadas de la clase sobre DataSetHelper .

  1. Agregue la siguiente definición de clase privada en la clase sobre DataSetHelper que creó en la sección "Sobre DataSetHelper Shell de clase":
    private class FieldInfo{
    public string RelationName;
    public string FieldName;//source table field name
    public string FieldAlias;//destination table field name
    public string Aggregate;
    }

    Nota: esta clase es común a otros artículos sobre DataSetHelper y contiene algunos campos que no se utiliza en este artículo.

  2. Agregue las siguientes variables miembro privadas a la definición de clase inmediatamente después de la declaración de conjunto de datos :
    private System.Collections.ArrayList m_FieldInfo; private string m_FieldList; 
  3. Agregue el siguiente método privado a la definición de clase. Este método es igual que el método que se utiliza en otros artículos sobre DataSetHelper .
    private void ParseFieldList(string FieldList, bool AllowRelation){
    /*
    * This code parses FieldList into FieldInfo objects and then
    * adds them to the m_FieldInfo private member
    *
    * FieldList systax: [relationname.]fieldname[ alias], ...
    */
    if (m_FieldList == FieldList) return;
    m_FieldInfo = new System.Collections.ArrayList();
    m_FieldList = FieldList;
    FieldInfo Field; string[] FieldParts;
    string[] Fields=FieldList.Split(',');
    int i;
    for (i=0; i<=Fields.Length-1; i++)
    {
    Field=new FieldInfo();
    //parse FieldAlias
    FieldParts = Fields[i].Trim().Split(' ');
    switch (FieldParts.Length)
    {
    case 1:
    //to be set at the end of the loop
    break;
    case 2:
    Field.FieldAlias=FieldParts[1];
    break;
    default:
    throw new Exception("Too many spaces in field definition: '" + Fields[i] + "'.");
    }
    //parse FieldName and RelationName
    FieldParts = FieldParts[0].Split('.');
    switch (FieldParts.Length)
    {
    case 1:
    Field.FieldName=FieldParts[0];
    break;
    case 2:
    if (AllowRelation==false)
    throw new Exception("Relation specifiers not permitted in field list: '" + Fields[i] + "'.");
    Field.RelationName = FieldParts[0].Trim();
    Field.FieldName=FieldParts[1].Trim();
    break;
    default:
    throw new Exception("Invalid field definition: " + Fields[i] + "'.");
    }
    if (Field.FieldAlias==null)
    Field.FieldAlias = Field.FieldName;
    m_FieldInfo.Add (Field);
    }
    }

Método CreateJoinTable

Esta sección contiene el código para el método CreateJoinTable .

La siguiente es la convención de llamada para el método CreateJoinTable :
dt = dsHelper.CreateJoinTable("TestTable", ds.Tables["Employees"],    "FirstName FName,LastName LName,DepartmentEmployee.DepartmentName Department");

En este ejemplo de llamada crea una nueva DataTable con un TableName de TestTable y tres campos (FName, LName y departamento). Estos tres campos tienen los mismos datos de tipo como el nombre y los campos LastName de la tabla empleados y el campo DepartmentName de la tabla primaria que se tiene acceso mediante el objeto DepartmentEmployee DataRelation .


Utilice la siguiente sintaxis para especificar campos en la lista de campos:
[relationname.]fieldname[ alias], ...
Tenga en cuenta lo siguiente para esta sintaxis:

  • La ColumnName y las propiedades de tipo de datos son las únicas propiedades que se copian a la tabla de datosde destino.
  • El resultado se copia para campos que contienen una expresión.
  • Puede cambiar el nombre de un campo en la tabla de datos de destino mediante la especificación de un nombre de alias.
  • La lista de campos puede contener un subconjunto de nombres de campos que aparecen en un orden diferente que el orden en la DataTablede origen. Si la lista de campos está en blanco, se produce una excepción.
  • DataRelation se referirán a las tablas primarias. Por ejemplo, si desea crear una tabla que combina los campos de los clientes, los empleados y las tablas pedidos, debe utilizar la tabla pedidos como la tabla de origen y, a continuación, hacer referencia a campos de los clientes y las tablas de empleados por medio de relaciones.
Para llamar al método CreateJoinTable , agregue el método siguiente a la clase sobre DataSetHelper que creó en la sección "Sobre DataSetHelper Shell de clase":
public DataTable CreateJoinTable(string TableName, DataTable SourceTable, string FieldList){
/*
* Creates a table based on fields of another table and related parent tables
*
* FieldList syntax: [relationname.]fieldname[ alias][,[relationname.]fieldname[ alias]]...
*/
if (FieldList==null)
{
throw new ArgumentException("You must specify at least one field in the field list.");
//return CreateTable(TableName, SourceTable);
}
else
{
DataTable dt = new DataTable(TableName);
ParseFieldList(FieldList, true);
foreach(FieldInfo Field in m_FieldInfo)
{
if(Field.RelationName==null)
{
DataColumn dc = SourceTable.Columns[Field.FieldName];
dt.Columns.Add(dc.ColumnName, dc.DataType, dc.Expression);
}
else
{
DataColumn dc = SourceTable.ParentRelations[Field.RelationName].ParentTable.Columns[Field.FieldName];
dt.Columns.Add(dc.ColumnName, dc.DataType, dc.Expression);
}
}
if (ds!=null)
ds.Tables.Add(dt);
return dt;
}
}

Método InsertJoinInto

Esta sección contiene código para el método InsertJoinInto . El método InsertJoinInto copia los registros que están ordenados y filtran de la tabla de origen y tablas relacionadas en la tabla de destino. Cuando se llama a la propiedad ParseFieldList , puede analizar las listas que se han analizado anteriormente, si estas listas están disponibles. Si la lista de campos está en blanco, se produce una excepción.


La siguiente es la convención de llamada para el método InsertJoinInto :
dsHelper.InsertJoinInto(ds.Tables["TestTable"], ds.Tables["Employees"],     "FirstName FName,LastName LName,DepartmentEmployee.DepartmentName Department", 
"EmployeeID<5", "BirthDate");

En el ejemplo de llamada copia registros de empleados DataTable (y el campo DepartmentName de una DataTablerelacionada) a TestTable DataTable, que se filtra en "EmployeeID < 5" y se ordena por fecha de nacimiento.

Nota: el filtro y las expresiones de ordenación se aplican sólo a la tabla de origen y no a las tablas relacionadas.

Para llamar al método InsertJoinInto , agregue el método siguiente a la clase sobre DataSetHelper que creó en la sección "Sobre DataSetHelper Shell de clase":
public void InsertJoinInto(DataTable DestTable, DataTable SourceTable,     string FieldList, string RowFilter, string Sort)
{
/*
* Copies the selected rows and columns from SourceTable and inserts them into DestTable
* FieldList has same format as CreatejoinTable
*/
if (FieldList==null)
{
throw new ArgumentException("You must specify at least one field in the field list.");
//InsertInto(DestTable, SourceTable, RowFilter, Sort);
}
else
{
ParseFieldList(FieldList, true);
DataRow[] Rows = SourceTable.Select(RowFilter, Sort);
foreach(DataRow SourceRow in Rows)
{
DataRow DestRow = DestTable.NewRow();
foreach(FieldInfo Field in m_FieldInfo)
{
if(Field.RelationName==null)
{
DestRow[Field.FieldName] = SourceRow[Field.FieldName];
}
else
{
DataRow ParentRow = SourceRow.GetParentRow(Field.RelationName);
DestRow[Field.FieldName] = ParentRow[Field.FieldName];
}
}
DestTable.Rows.Add(DestRow);
}
}
}

Método SelectJoinInto

Esta sección contiene el código para el método SelectJoinInto . Este método es una combinación de la CreateJoinTable y los métodos InsertJoinInto . El método SelectJoinInto crea una nueva DataTable basado en DataTable objetos y copias de los registros existentes que están ordenados y filtrados en la nueva tabla de datos.


La siguiente es la convención de llamada para el método SelectJoinInto :
dt = dsHelper.SelectInto("TestTable", ds.Tables["Employees"],     "FirstName FName,LastName LName,DepartmentEmployee.DepartmentName Department", "EmployeeID<5", "BirthDate");

Esta llamada de ejemplo crea un DataTable con el nombre TestTable con tres campos. Estos tres campos se basan en el nombre y los campos LastName de la DataTable de empleados y el campo DepartmentName de la DataTable que se hace referencia a través de la DepartmentEmployee DataRelation. A continuación, este ejemplo copia los registros de la DataTable de empleados a TestTable DataTable, que se filtra en "EmployeeID < 5" y se ordena por fecha de nacimiento.

Nota: el filtro y las expresiones de ordenación se aplican sólo a la tabla de origen y no a las tablas relacionadas.

Para llamar al método SelectJoinInto , agregue el método siguiente a la clase sobre DataSetHelper que creó en la sección "Sobre DataSetHelper Shell de clase":
public DataTable SelectJoinInto(string TableName, DataTable SourceTable, string FieldList, string RowFilter, string Sort){
/*
* Selects sorted, filtered values from one DataTable to another.
* Allows you to specify relationname.fieldname in the FieldList to include fields from
* a parent table. The Sort and Filter only apply to the base table and not to related tables.
*/
DataTable dt = CreateJoinTable(TableName, SourceTable, FieldList);
InsertJoinInto(dt, SourceTable, FieldList, RowFilter, Sort);
return dt;
}

Probar la aplicación

  1. Guarde y, a continuación, compile la clase sobre DataSetHelper que creó en las secciones anteriores.
  2. Siga estos pasos para crear una nueva aplicación de Windows de Visual C#:
    1. Inicie Visual Studio. NET.
    2. En el menú archivo, elija nuevo y, a continuación, haga clic en proyecto.
    3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyectoy, a continuación, haga clic en Aplicación para Windows en plantillas.
  3. En el Explorador de soluciones, haga clic derecho en la solución y, a continuación, haga clic en Agregar proyecto existente. Agregue el proyecto sobre DataSetHelper.
  4. En el menú proyecto , haga clic en Agregar referencia.
  5. En el cuadro de diálogo Agregar referencia , haga clic en la ficha proyectos y, a continuación, agregue una referencia al proyecto sobre DataSetHelper a la aplicación de formularios Windows Forms.
  6. En el Diseñador de formulario, arrastre tres controles Button y un control DataGrid desde el cuadro de herramientas hasta el formulario. Nombre los botones btnCreateJoin, btnInsertJoinIntoy btnSelectJoinInto. Mantenga el nombre predeterminado para el control DataGrid (dataGrid1).
  7. En el código del formulario, agregue la siguiente instrucción Using a la parte superior de la ventana de código:
    using System.Data;
  8. Agregue las siguientes declaraciones de variable en la definición del formulario:
    DataSet ds; DataSetHelper.DataSetHelper dsHelper;
  9. Agregue el código siguiente al evento Form_Load :
    ds = new DataSet();dsHelper = new DataSetHelper.DataSetHelper(ref ds);
    //Create source tables
    DataTable dt = new DataTable("Employees");
    dt.Columns.Add("EmployeeID",Type.GetType("System.Int32") );
    dt.Columns.Add("FirstName", Type.GetType("System.String"));
    dt.Columns.Add("LastName", Type.GetType("System.String"));
    dt.Columns.Add("BirthDate", Type.GetType("System.DateTime"));
    dt.Columns.Add("JobTitle", Type.GetType("System.String"));
    dt.Columns.Add("DepartmentID", Type.GetType("System.Int32"));
    dt.Rows.Add(new object[] {1, "Tommy", "Hill", new DateTime(1970, 12, 31), "Manager", 42});
    dt.Rows.Add(new object[] {2, "Brooke", "Sheals", new DateTime(1977, 12, 31), "Manager", 23});
    dt.Rows.Add(new object[] {3, "Bill", "Blast", new DateTime(1982, 5, 6), "Sales Clerk", 42});
    dt.Rows.Add(new object[] {1, "Kevin", "Kline", new DateTime(1978, 5, 13), "Sales Clerk", 42});
    dt.Rows.Add(new object[] {1, "Martha", "Seward", new DateTime(1976, 7, 4), "Sales Clerk", 23});
    dt.Rows.Add(new object[] {1, "Dora", "Smith", new DateTime(1985, 10, 22), "Trainee", 42});
    dt.Rows.Add(new object[] {1, "Elvis", "Pressman", new DateTime(1972, 11, 5), "Manager", 15});
    dt.Rows.Add(new object[] {1, "Johnny", "Cache", new DateTime(1984, 1, 23), "Sales Clerk", 15});
    dt.Rows.Add(new object[] {1, "Jean", "Hill", new DateTime(1979, 4, 14), "Sales Clerk", 42});
    dt.Rows.Add(new object[] {1, "Anna", "Smith", new DateTime(1985, 6, 26), "Trainee", 15});
    ds.Tables.Add(dt);

    dt = new DataTable("Departments");
    dt.Columns.Add("DepartmentID", Type.GetType("System.Int32"));
    dt.Columns.Add("DepartmentName", Type.GetType("System.String"));
    dt.Rows.Add(new object[] {15, "Men's Clothing"});
    dt.Rows.Add(new object[] {23, "Women's Clothing"});
    dt.Rows.Add(new object[] {42, "Children's Clothing"});
    ds.Tables.Add(dt);

    ds.Relations.Add("DepartmentEmployee", ds.Tables["Departments"].Columns["DepartmentID"],
    ds.Tables["Employees"].Columns["DepartmentID"]);

  10. Agregue el código siguiente al evento btnCreateJoin_Click :
    dsHelper.CreateJoinTable("EmpDept",ds.Tables["Employees"],     "FirstName FName,LastName LName,BirthDate,DepartmentEmployee.DepartmentName Department");
    dataGrid1.SetDataBinding(ds, "EmpDept");

  11. Agregue el código siguiente al evento btnInsertJoinInto_Click :
    dsHelper.InsertJoinInto(ds.Tables["EmpDept"], ds.Tables["Employees"],     "FirstName FName,LastName LName,BirthDate,DepartmentEmployee.DepartmentName Department",
    "JobTitle='Sales Clerk'", "DepartmentID");
    dataGrid1.SetDataBinding(ds, "EmpDept");

  12. Agregue el código siguiente al evento btnSelectJoinInto_Click :
    dsHelper.SelectJoinInto("EmpDept2", ds.Tables["Employees"],    "FirstName,LastName,BirthDate BDate,DepartmentEmployee.DepartmentName Department", 
    "JobTitle='Manager'", "DepartmentID");
    dataGrid1.SetDataBinding(ds, "EmpDept2");

  13. Ejecute la aplicación y, a continuación, haga clic en cada uno de los botones. Observe que el control DataGrid se rellena con las tablas y los datos desde el código.

    Nota: puede hacer sólo clic en el btnCreateJoin y los botones btnSelectJoinInto una vez. Si hace clic en cualquiera de estos botones más de una vez, recibirá un mensaje de error que intenta agregar la misma tabla dos veces. Además, debe hacer clic btnCreateJoin antes de hacer clic en btnInsertJoinInto; de lo contrario, el destino DataTable no se crea. Si hace clic en el botón btnInsertJoinInto varias veces, llenará el DataGrid con registros duplicados.

Ideas de mejora

  • La ColumnName y las propiedades de tipo de datos son las únicas propiedades que se copian a la tabla de datosde destino. Puede extender el método CreateTable para copiar propiedades adicionales, como la propiedad MaxLength , o puede crear nuevas columnas de clave.
  • La propiedad Expression no se copia; en su lugar, se copia el resultado. Por lo tanto, no es necesario agregar campos a los que hace referencia la expresión a la tabla de destino. Además, la columna de destino puede aparecer antes en la lista de resultados que cualquiera de las columnas que esta columna depende de lo contrario. Puede modificar el método CreateTable para copiar la expresión (la columna InsertInto omite columnas con una expresión), aunque esto está sujeto a las limitaciones que se mencionan en el presente apartado.
  • Puede combinar la funcionalidad de los métodos SelectJoinInto , el InsertJoinIntoy el CreateJoinTableen el CreateTable, el InsertIntoy los métodos SelectInto . Para obtener información adicional acerca de la CreateTable, el InsertIntoy los métodos SelectInto , haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:

    326009 Cómo: implementar una clase auxiliar DataSet SELECT INTO en Visual C#.
    Si no desea combinar estos métodos, pero si tiene dos conjuntos de métodos en una clase única, puede habilitar el CreateJoinTable y los métodos InsertJoinInto para controlar una lista de campo vacío quitando las instrucciones Throw y quitando el comentario de las llamadas a la CreateTable y los métodos InsertInto en las siguientes líneas de código:
        if (FieldList==null)    {
    throw new ArgumentException("You must specify at least one field in the field list.");
    //return CreateTable(TableName, SourceTable);
    }

    - y -
        if (FieldList==null)    {
    throw new ArgumentException("You must specify at least one field in the field list.");
    //InsertInto(DestTable, SourceTable, RowFilter, Sort);
    }

Solución de problemas

  • El nombre de campo y las partes de alias de la lista de campos deben cumplir con las convenciones de nomenclatura DataColumn . El analizador también restringe los nombres, en que el nombre no debe contener un punto (.), comas (,) o un espacio ().
  • Si hace clic en un botón más de una vez, la misma tabla se agrega dos veces al conjunto de datos, lo que da como resultado una excepción. Para evitar este problema, puede agregar código a la aplicación de prueba para comprobar si ya existe una tabla de datos del mismo nombre. Como alternativa, puede crear la clase sobre DataSetHelper sin una referencia a un conjunto de datos y, a continuación, enlazar la propiedad DataGrid.DataSource directamente a la variable dt en lugar de mediante la llamada al método SetDataBinding .
  • Si la tabla de origen utiliza tipos de datos personalizados (es decir, una clase), debe agregar código al método InsertJoinInto para realizar una copia profunda de los datos. De lo contrario, se copia sólo una referencia.
Propiedades

Id. de artículo: 326080 - Última revisión: 17 ene. 2017 - Revisión: 1

Comentarios