Buscar este blog

viernes, 5 de enero de 2018

ADO.NET + DataSet + C#

En el artículo DataSet + C# se explica como trabajar con DataSet. En este voy a explicar como realizar lo mismo pero con líneas de código.

Se utiliza para este ejemplo el lenguaje de consulta SQL, el lenguaje de programación C# y el IDE Microsoft Visual Studio Community.

Situación o Negocio

Para no complicar el ejemplo se utiliza dos tablas con pocos campos.

En una universidad los estudiantes estudian una carrera de ingeniería. De los estudiantes se saben su DNI y Nombre. De la carrera de ingeniería el nombre.

La relación de estas tablas es de 1:N (Uno a varios). Un estudiante solo estudia una carrera de ingeniería y una carrera de ingeniería posee varios estudiantes.

Script – Sql


CREATE TABLE engineering
(
 [Id] BIGINT IDENTITY (1, 1) NOT NULL, 
    [Name] VARCHAR(255) NOT NULL,
 PRIMARY KEY CLUSTERED ([Id] ASC),
    UNIQUE NONCLUSTERED ([Name] ASC)
)

CREATE TABLE student
(
 [Id] BIGINT IDENTITY (1, 1) NOT NULL, 
 [DNI] VARCHAR(255) NOT NULL,    
 [Name] VARCHAR(255) NOT NULL,
 [IdEngineering] BIGINT NOT NULL, 
 PRIMARY KEY CLUSTERED ([Id] ASC),
 UNIQUE NONCLUSTERED ([DNI] ASC),
 CONSTRAINT [FK] FOREIGN KEY ([IdEngineering]) 
  REFERENCES [dbo].[engineering] ([Id]) 
  ON DELETE CASCADE 
  ON UPDATE CASCADE 
)


Paso 1
  • Abrir Visual Studio
  • Crear un proyecto de tipo Class Library. (FILE ->  new -> Proyect)
  •  Ctrl + Shift + A 
  • Crear el fichero de Sql (mdf) 

Paso 2
  • Crear el fichero app.config y escribir la cadena de conexión con la base de datos


  • Crear la clase Connection

class Connection
    {
        public static SqlConnection SqlConnectionProvider
        {
            get
            {
                var cnx =
                    ConfigurationManager.ConnectionStrings[
                        "ClassDataSetBlog.Properties.Settings.DatabaseDataSetConnectionString"].ConnectionString;
                return new SqlConnection(cnx);
            }
        }
    }


Paso 3

Se crea las clases que mapean con las tablas de la base de datos (engineering y student).

    public class Engineering
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }

    public class Student
    {
        public long Id { get; set; }

        public string Dni { get; set; }

        public string Name { get; set; }

        public long IdEngineering { get; set; }
    }


Paso 4

Crear las clase Adapter de cada tabla y mapearlo con las clases del Paso 3.

Se utiliza las clases SqlDataAdapter y SqlCommand.

El SqlCommand tiene la propiedad CommandText que recibe una query de Sql o cuando se inicializa el comando puede recibir en su constructor una query

Ejemplo:


    _adapter.DeleteCommand = new SqlCommand("DELETE FROM engineering WHERE Id = " + item.Id, connection);


En este caso se va a guardar las query en un fichero de recursos. Ctrl + Shift + A


Este recurso nos sirve como un diccionario de códigos SQL


Crear la clase AdapterEngineering y AdapterStudent

    public class AdapterEngineering
    {
        private readonly SqlDataAdapter _adapter;

        public AdapterEngineering()
        {
            _adapter = new SqlDataAdapter();
        }

        public int Insert(Engineering item)
        {
            var connection = Connection.SqlConnectionProvider;
            
            _adapter.InsertCommand = new SqlCommand(ResourceQueryEngineering.Insert, connection);
            var parameter = new SqlParameter(ResourceQueryEngineering.Parameter_Name, item.Name);
            _adapter.InsertCommand.Parameters.Add(parameter);

            connection.Open();
            var value = _adapter.InsertCommand.ExecuteNonQuery();
            connection.Close();

            return value;
        }

        public int Update(Engineering item)
        {
            var connection = Connection.SqlConnectionProvider;

            _adapter.UpdateCommand = new SqlCommand(ResourceQueryEngineering.Update, connection);
            SqlParameter[] parameters =
            {
                 new SqlParameter(ResourceQueryEngineering.Parameter_Name, item.Name),
                 new SqlParameter(ResourceQueryEngineering.Parameter_Id, item.Id)
            };
            _adapter.InsertCommand.Parameters.AddRange(parameters);

            connection.Open();
            var value = _adapter.UpdateCommand.ExecuteNonQuery();
            connection.Close();

            return value;
        }

        public int Delete(Engineering item)
        {
            var connection = Connection.SqlConnectionProvider;

            _adapter.DeleteCommand = new SqlCommand(ResourceQueryEngineering.Delete, connection);
            var parameter = new SqlParameter(ResourceQueryEngineering.Parameter_Id, item.Id);
            _adapter.DeleteCommand.Parameters.Add(parameter);

            connection.Open();
            var value = _adapter.DeleteCommand.ExecuteNonQuery();
            connection.Close();

            return value;
        }

        public List Fill()
        {
            var connection = Connection.SqlConnectionProvider;

            var datatable = new DataTable();
            _adapter.SelectCommand = new SqlCommand(ResourceQueryEngineering.Select, connection);
            _adapter.Fill(datatable);

            return datatable.Rows.Count == 0 ? new List() :
                (from DataRow variable in datatable.Rows
                 select new Engineering
                 {
                     Id = (long)variable[0],
                     Name = (string)variable[1]
                 }).ToList();
        }

        public List QueryEngineeringCountStudent()
        {
            var connection = Connection.SqlConnectionProvider;

            var datatable = new DataTable();
            _adapter.SelectCommand = new SqlCommand(ResourceQueryEngineering.SelectEngineeringCountStudent, connection);
            _adapter.Fill(datatable);

            return datatable.Rows.Count == 0 ? new List() :
                (from DataRow variable in datatable.Rows
                 select new EngineeringCountStudentDto
                 {
                     EngineeringName = (string)variable[0],
                     Count = (int)variable[1]
                 }).ToList();
        } 
    }

Paso 6
 
Se tiene el diseño, las consultas y las funciones básicas de los CRUD de las tablas para gestionar la información de la base de datos. Ahora pasaremos a testear estas acciones con las pruebas unitarias.

  •  Ctrl + Shift + A 



[TestMethod]
        public void TestEgineering()
        {
            var adapter = new AdapterEngineering();
                        
            for (int i = 0; i < 10; i++)
                adapter.Insert(new Engineering{
                    Name = "Engineering " + i
                });

            var list = adapter.Fill();
            int delete = adapter.Delete(list[0]);


            Assert.AreEqual(1, delete);
        }
    

Conclusiones 

Se realiza paso por paso un pequeño ejemplo de cómo utilizar nuestro viejo DataSet y se realiza pruebas unitarias.

Espero que les haya gustado y recuerden que mi objetivo es publicar varias formas de comunicación de una Aplicación con un gestor de base de datos. Próximamente les pondré como aplicar el patrón repositorio.

ADO.NET + Patrón Repositorio + C#


Se despide
Ing. YAM