Buscar este blog

martes, 17 de abril de 2018

Introducción a la Programación Orientada a Objeto (POO)

Mi objetivo es enseñarle los conceptos de programación orientada a objeto, modelo de objeto, clases y responsabilidades.

Si comienzas en la programación orientada a objeto, primero deberías saber un poco de historia.
Los orígenes intelectuales de la programación orientada a objetos nacen con el desarrollo del lenguaje Simula (Dahl y Nygaard 1966), pero surgió como una tecnología de software significativa durante la década de 1980 con los lenguaje Smalltalk y C++.

Smalltalk-80 fue una manifestación pionera de la importancia y la utilidad de un área naciente de la informática. La programación orientada a objetos surgió cuando se desarrolló Smalltalk.

La década de 1990 vio el surgimiento del lenguaje de programación Java orientado a objetos. En 1992 la programación orientada a objetos realmente comienza el auge de la programación orientada a objetos.

Si desean profundizar sobre el tema del comienzo de la Programación Orientada a Objetos (POO) o Object-oriented programming (OOP) pueden leer “The emergence of object-oriented technology: the role of community” por Hugh Robinson y Helen Sharp.

Comencemos a conceptualizar.
Qué significa la programación orientada a objeto?
La programación orientada a objetos es un paradigma de programación. Los objetos manipulan los datos de entrada y salida e interactúan entre ellos. Un paradigma de programación es un modelo de diseño y desarrollo de programas que posee un conjunto de reglas.

El modelo orientado a objetos (OO) es una colección de objetos o clases que permite que un programa pueda examinar y manipular elemento de su entorno. Es modelar un problema existente con entidades independientes que interactúan entre sí.

Estas entidades son llamadas objetos con similitud de un objeto del mundo real. Pero es importante no confundir que todo objeto del entorno informático tiene que ser exactamente un objeto del mundo real. Pueden existir objetos en informática que no existan físicamente en el mundo real.Ejemplo: Una fecha se pude considerar un objeto y no es un objeto del mundo real físicamente.

Qué es un objeto y una clase?

En lenguajes de programación como Java y C# (por citarlos) una clase es la definición de las características concretas de un determinado tipo de objetos.

Los objetos son instancias de una clase. Por ende los objetos de una misma clase poseen las mismas responsabilidades siendo las clases abstracciones que generalizan dominios de objetos.

Qué es una responsabilidad?

Las responsabilidades de un objeto se dividen en dos grupos: atributos y métodos. Hay autores que lo llaman a los atributos: campos o fields, propiedade o variables; a los métodos: rutinas o funciones miembro. Los atributos son valores almacenados por los objetos de una clase mientras que los métodos son secuencias de pasos para determinar un comportamiento.

Imagine una tienda que se dedica a vender alimentos tales como manzanas y arroz. La tienda posee un vendedor. El vendedor debe ser capaz de informar al cliente acerca de precio, color, fecha de vencimiento de un producto.

¿Identifique cuáles son las clases y objetos?

En esta situación podemos decir que nuestro modelo orientado a objeto o nuestro entorno del problema son todos los objetos que intervienen en esta tienda.

Primero Identificar los objetos:
N cantidad de manzanas y arroz
Un vendedor
N cantidad de clientes.

Se preguntarán por qué pongo la variable N? Si analizan el problema nunca mencionan la cantidad de manzanas y arroz que hay por ende asumimos que pueden ser cualquier cantidad.

Hasta este paso ya tenemos los objetos ahora debemos agruparlos en clases.

Los objetos N manzanas pertenecen a la clase Manzana.
Los objetos N arroz pertenecen a la clase Arroz.
Pero a la vez las clases Manzana y Arroz son alimentos por ende pertenecen tambien a la clase Alimentos.
El objeto Vendedor pertence a la clase Vendedor
El objeto Cliente pertence a la clase Cliente.
Y la clase Vendedor y Cliente son personas que aunque el problema no lo diga se debe deducir y se crea la clase Persona.

¿Cuáles son sus responsabilidades?

La clase Alimentos, Manzana y Arroz tienen los atributos: precio, color y fecha de vencimiento.
La clase Persona tiene los atributos: RUT, nombre y apellido....
Vendedor y Cliente poseen las misma responabilidades de la clase Persona.
Vendedor también posee un método que es Informar encargado de darle información de los productos de la tienda a los clientes.
Cliente aunque no lo diga el problema para poder recibir información debe tener el método Consultar.

Espero que les hay gustado
Tengan un buen día
Yeiniel Alfonso

jueves, 5 de abril de 2018

EntityFramework + Patrón Repositorio

En tres artículos anteriores explique cómo utilizar ADO.NET y DataSet. En este artículo les voy a explicar cómo utilizar EntityFramework  y el patrón repositorio con dos gestores de bases de datos.

En este artículo no voy a explicar la sintaxis del lenguaje de consulta SQL ni MySQL, ni algunos pasos ya que se encuantra escrito en los tres artículos mencionados.

El código hablará por si solo:

Crearemos la clase conexión.


static class Connection
    {
       internal static string Connected()
       {
           var provider = ConfigurationManager.AppSettings.Get("DataProvider");
           return GetBase(provider);
       }

        internal static string Connected(EnumDataProvider dataProvider)
        {
            return GetBase(dataProvider.ToString());
        }

        private static string GetBase(string provider)
        {
            switch (provider.ToLower())
            {
                case "sql":
                    return "name=Sql";
                case "mysql":
                    return "name=MySql";
                default:
                    return "";
            }
        }
    }

Vamos a crear una clase que mapea un objeto y una tabla de una base de datos.


class MapperEngineering : EntityTypeConfiguration
    {
        public MapperEngineering()
        {
            ToTable("Engineering");

            HasKey(item => item.Id);
            Property(item => item.Id)
                .HasColumnName("Id")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .IsRequired();

            Property(item => item.Name)
                .HasColumnName("Name")
                .HasMaxLength(255)
                .IsUnicode()
                .IsRequired();
        }
    }

Se crea el contexto de la base de datos

class DataBaseContext : DbContext
    {
        public DataBaseContext()
            : base(Connection.Connected()) { }

        public DataBaseContext(EnumDataProvider dataProvider) :
            base(Connection.Connected(dataProvider)) { }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove();
            modelBuilder.Configurations.Add(new MapperEngineering());
            base.OnModelCreating(modelBuilder);
        }
    }

Ahora vamos a crear la interfaz y el patrón repositorio base

public interface IRepositoryGeneric where T : Entity
    {
        #region CRUD
        void Insert(T entidad);

        void Delete(T entidad);

        IEnumerable Find(Expression> expresion);

        T GetById(long id);

        IEnumerable FindAll();

        IEnumerable FindAll(Expression> orderbyExpression);

        void Saves(T entidad);
        #endregion

        #region Paged
        IEnumerable GetPage(bool desc, Expression> orderbyExpression, int currentPage,
            int pageSize, out int totalCount);

        IEnumerable GetPage(bool desc, Expression> orderbyExpression,
            Expression> expression, int currentPage, int pageSize, out int totalCount);
        #endregion

        #region Other

        decimal Sum(Expression> expression);

        bool Exist(Expression> expresion, out IEnumerable items);

        bool Exist(long id, out T item);
        #endregion
    }

public class Repository : IDisposable, IRepositoryGeneric where T : Entity
    {
        private readonly DbContext _contexto;
        private readonly DbSet _entities;
        private bool _disposed;

        public Repository(EnumDataProvider dataProvider)
        {
            _contexto = new DataBaseContext(dataProvider);
            _entities = _contexto.Set();
        }

        protected Repository()
        {
            _contexto = new DataBaseContext();
            _entities = _contexto.Set();
        }

        #region CRUD
        public void Insert(T entidad)
        {
            _entities.Add(entidad);
            _contexto.Entry(entidad).State = EntityState.Added;
        }

        public void Delete(T entidad)
        {
            _entities.Remove(entidad);
            _contexto.Entry(entidad).State = EntityState.Deleted;
        }

        public IEnumerable Find(Expression> expresion)
        {
            return _entities.Where(expresion);
        }

        public T GetById(long id)
        {
            return _entities.Find(id);
        }

        public IEnumerable FindAll()
        {
            return _entities;
        }

        public IEnumerable FindAll(Expression> orderbyExpression)
        {
            return _entities.OrderBy(orderbyExpression);
        }

        public void Saves(T entidad)
        {
            var entry = _contexto.Entry(entidad);
            entry.State = EntityState.Modified;
        }
        #endregion

        #region Paged
        public IEnumerable GetPage(bool desc, Expression> orderbyExpression, int currentPage,
            int pageSize, out int totalCount)
        {
            totalCount = _entities.Count();
            if (desc)
            {
                return
                    _entities.OrderByDescending(orderbyExpression)
                        .Skip((currentPage - 1) * pageSize)
                        .Take(pageSize);
            }

            return
                    _entities.OrderBy(orderbyExpression)
                        .Skip((currentPage - 1) * pageSize)
                        .Take(pageSize);
        }

        public IEnumerable GetPage(bool desc, Expression> orderbyExpression,
            Expression> expression, int currentPage, int pageSize, out int totalCount)
        {
            totalCount = _entities.Count(expression);

            if (desc)
            {
                return
                    _entities.Where(expression).OrderByDescending(expression)
                        .Skip((currentPage - 1) * pageSize)
                        .Take(pageSize);
            }

            return
                    _entities.Where(expression).OrderBy(expression)
                        .Skip((currentPage - 1) * pageSize)
                        .Take(pageSize);
        }

        #endregion

        #region Other

        public decimal Sum(Expression> expression)
        {
            return _entities.Sum(expression);
        }

        public bool Exist(Expression> expresion, out IEnumerable items)
        {
            items = Find(expresion);
            return items.Any();
        }
        public bool Exist(long id, out T item)
        {
            item = GetById(id);
            return item != null;
        }
        #endregion

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!_disposed)
                if (disposing)
                    _contexto.Dispose();
            _disposed = true;
        }
    }

 public class RepositoryEngineering: Repository
    {
        public RepositoryEngineering() { }

        public RepositoryEngineering(EnumDataProvider dataProvider) 
            : base(dataProvider) { }
    }

TEST

[TestMethod]
        public void SelectRepository()
        {
            var context = new RepositoryEngineering();
            var n = context.FindAll();

            Assert.AreEqual(n.Count(), 7);
        }

[TestMethod]
        public void InsertRepository()
        {
            var context = new RepositoryEngineering(EnumDataProvider.MySql);
            context.Insert(new Engineering { Name = "Engineering" });
        }
 
Saludos
 

jueves, 29 de marzo de 2018

ADO.NET + Patrón Repositorio + C#

En dos artículos anteriores explique cómo utilizar ADO.NET y DataSet. En este artículo les voy a explicar cómo utilizar ADO.NET y el patrón repositorio con dos gestores de bases de datos de forma genérica.

Se utiliza los lenguaje de consulta SQL, MySQL, lenguaje de programación C# y el entorno de desarrollo integrado Microsoft Visual Studio Community.

Situación o Negocio

Una tabla llamada Ingeniería que posee dos campos un ID auto-numérico incremental y NAME una cadena de texto. Se quiere que la Aplicación se conecte con dos bases de datos SQL y MySQL.

Paso 1

Script – SQL

CREATE SCHEMA DatabaseTest

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

Script – MySql

CREATE SCHEMA `databasetest` ;

CREATE TABLE `databasetest`.`engineering` (
  `Id` BIGINT(20)  NOT NULL AUTO_INCREMENT COMMENT '' ,
  `Name` VARCHAR(255) NOT NULL COMMENT '',
  PRIMARY KEY (`Id`)  COMMENT '',
  UNIQUE INDEX `Name_UNIQUE` (`Name` ASC)  COMMENT '');


En este ejemplo se utiliza nuestra vieja técnica de procedimiento almacenado (stored procedure):

stored procedure – SQL

CREATE PROCEDURE InsertEngineering
 @Name varchar(255)
AS
 INSERT Engineering(Name) Values(@Name)
 RETURN @@Identity


stored procedure – MySql

DELIMITER $$
USE `databasetest`$$
CREATE PROCEDURE `InsertEngineering` (in `@Name` varchar(255))
BEGIN
 insert engineering(Id) values(`@Name`);
END
$$ DELIMITER ;

Paso 2 

Crear un proyecto de tipo Class Library 

Por defecto Visual Studio tiene como referencia la librería para Sql pero no siendo el caso con MySql. Pues sencillo, hay que agregar esta referencia. Lo pueden hacer con Nuget.


Paso 3

Crear las cadenas de conexión en el fichero App.config


Se tiene dos cadenas de conexión con las bases de datos y un elemento o llave llamado DataProvider con valor Sql. Si observan tiene el mismo nombre que la cadena de conexión para Sql. Esta llave DataProvider tiene como objetivo establecer por defecto en configuración que conexión se va a ejecutar.

Paso 4

Se crea un enum llamado EnumDataProvider. Tiene como objetivo establecer y chequear el tipo de conexión a realizar en el código.


 public enum EnumDataProvider
    {
        Sql,
        MySql
    }

Paso 5 

Crear la clase CommandCommon que su objetivo es establecer un tipo de comando genérico común para Sql y MySql.


class CommandCommon
    {
        private readonly DbCommand _command;

        public CommandCommon(DbCommand command, DbConnection connection)
        {
            _command = command;
            _command.Connection = connection;
            _command.CommandType = CommandType.StoredProcedure;
        }

        public int ExecuteComand(string procedure, ParameterCommon[] parameters)
        {
            _command.CommandText = procedure;
            ParameterCommon.AddParameter(_command, parameters);

            _command.Connection.Open();
            var rowCount = _command.ExecuteNonQuery();
            _command.Connection.Close();

            return rowCount;
        }

        public int ExecuteComand(string procedure)
        {
            return ExecuteComand(procedure, new ParameterCommon[0]);
        }

        public DataTable Fill(string procedure, ParameterCommon[] parameters)
        {
            _command.CommandText = procedure;
            ParameterCommon.AddParameter(_command, parameters);
            var dataTable = new DataTable();

            _command.Connection.Open();
            var datareader = _command.ExecuteReader();
            dataTable.Load(datareader);
            datareader.Close();
            _command.Connection.Close();

           return dataTable;
        }

        public DataTable Fill(string procedure)
        {
            return Fill(procedure, new ParameterCommon[0]);
        }

        public object ExecuteScalar(string procedure, ParameterCommon[] parameters)
        {
            _command.CommandText = procedure;
            
            ParameterCommon.AddParameter(_command, parameters);

            _command.Connection.Open();
            var value = _command.ExecuteScalar();
            _command.Connection.Close();

            return value; 
        }

        public object ExecuteScalar(string procedure)
        {
            return ExecuteScalar(procedure, new ParameterCommon[0]);
        }
    }

En cada método se le pasa un parámetro con el nombre del procedure que son iguales en las dos bases de datos y un arreglo de parámetros de tipo de datos ParameterCommon

sealed class ParameterCommon
    {
        public string Name { get; set; }
        public object Value { get; set; }

        public static void AddParameter(IDbCommand comand, ParameterCommon[] parameters)
        {
            if (comand.Parameters.Count > 0)
                comand.Parameters.Clear();

            foreach (var parameter in parameters)
            {
                var p = comand.CreateParameter();
                p.ParameterName = parameter.Name;
                p.Value = parameter.Value;
                comand.Parameters.Add(p);
            }
        }
    }

Paso 6

Crear la clase CommandContext con el objetivo de establecer qué tipo de conexión se va a realizar. Dentro de CommandContext se tiene la propiedad abstracta y genérica DbContext el cual recibe qué tipo de conexión se va a realizar y así establecer la comunicación con la base de datos predeterminada. Hasta ahora se tiene una comunicación genérica con la base de datos de tal forma que esta desacoplada. Es fácil adicionar o quitar un gestor de base de datos sin tener que realizar cambios en toda la Aplicación.

class CommandContext
    {
        public CommandCommon DbContext { get; private set; }

        public CommandContext()
        {
            var provider = ConfigurationManager.AppSettings.Get("DataProvider");
            
            EnumDataProvider enumProvider;
            Enum.TryParse(provider, out enumProvider);

            if (Enum.TryParse(provider, out enumProvider))
                GetValue(enumProvider);
        }

        public CommandContext(EnumDataProvider enumProvider)
        {
            GetValue(enumProvider);
        }

        private void GetValue(EnumDataProvider enumProvider)
        {
            var cnx = ConfigurationManager.ConnectionStrings[enumProvider.ToString()].ConnectionString;
            DbConnection connection = null;
            DbCommand command = null;

            switch (enumProvider)
            {
                case  EnumDataProvider.Sql:
                    connection = new SqlConnection(cnx);
                    command = new SqlCommand();
                    break;
                case EnumDataProvider.MySql:
                    connection = new MySqlConnection(cnx);
                    command = new MySqlCommand();
                    break;
            }
            
            DbContext = new CommandCommon(command, connection);
        }
    }

Paso 7

Se mapea el DataTable con un objeto


public static class MapperEngineering
    {
        public static IEnumerable Convert(DataTable datatable)
        {
            return datatable.Rows.Count == 0 ? new List() :
              (from DataRow variable in datatable.Rows
               select new Engineering
               {
                   Id = (long) variable["Id"],
                   Name = (string) variable["Name"]

               } );
        }
    }

Paso 8
Se crea el patrón repositorio.

interface IRepository where T:Entity
    {
        #region CRUD
        void Insert(T entidad);

        void Delete(T entidad);

        void Update(T entidad);

        IEnumerable FindAll();

        #endregion
    }

 interface IRepositoryEngineering: 
        IRepository
    {
         
    }

public sealed class RepositoryEngineering :  IRepositoryEngineering
    {
        private readonly CommandContext _context;

        public RepositoryEngineering()
        {
            _context = new CommandContext();
        }

        public RepositoryEngineering(EnumDataProvider provider)
        {
            _context = new CommandContext(provider);
        }

        public void Insert(Engineering entidad)
        {
            _context.DbContext.ExecuteComand("InsertEngineering",
                new []
                {
                    new ParameterCommon { Name = "@Name", Value = entidad.Name }
                });
        }

        public void Delete(Engineering entidad)
        {
            _context.DbContext.ExecuteComand("InsertEngineering", 
                new[]
                {
                    new ParameterCommon { Name = "@Id", Value = entidad.Id }
                });
        }

        public void Update(Engineering entidad)
        {
            _context.DbContext.ExecuteComand("InsertEngineering",
                new[]
                {
                    new ParameterCommon { Name = "@Name", Value = entidad.Name },
                    new ParameterCommon { Name = "@Id", Value = entidad.Id }
                });
        }

        public IEnumerable FindAll()
        {
            return MapperEngineering.Convert(_context.DbContext.Fill("SelectAllEngineering"));
        }
    }

TEST

[TestMethod]
        public void SelectRepository()
        {
            var context = new RepositoryEngineering();
            var n = context.FindAll();

            Assert.AreEqual(n.Count(), 7);
        }

[TestMethod]
        public void InsertRepository()
        {
            var context = new RepositoryEngineering(EnumDataProvider.MySql);
            context.Insert(new Engineering { Name = "Engineering" });
        }

EntityFramework + Patrón Repositorio


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