Buscar este blog

Mostrando entradas con la etiqueta Algoritmo. Mostrar todas las entradas
Mostrando entradas con la etiqueta Algoritmo. Mostrar todas las entradas

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


lunes, 18 de julio de 2016

Algoritmo de conversión de Autómata finito no determinista a un Autómata finito determinista


La conversión de un AFND-vacía o AFND en un AFD se basa en el concepto de Clausura de Kleene o Operador estrella que se describe como A*.

A es un subconjunto de A* que contiene la secuencia vacía y este último es un sistema de las secuencias que se forman con las concatenaciones de cero o más secuencia de A.


La clausura(q), siendo q un estado, es el conjunto de todos los estados que se acceden a partir de q, con un símbolo de entrada.

La transformación de un AFND a AFD se realiza a través de la tabla de transición del autómata finito no determinista, siendo cada entrada un conjunto de estado. Mientras en la tabla de transición del autómata finito determinista, cada entrada del alfabeto es un solo estado. Cada estado del AFD deviene un conjunto de estados del AFND. El estado inicial y el alfabeto del AFND es el mismo para el AFD.

Conversión de AFND-vacía a AFD

A medida que se obtienen los conjuntos del autómata, se calcula la tabla de transición. A medida que se obtienen los conjuntos del autómata, se calcula la tabla de transición.

Iteración 1: Al comenzar con q0 (estado inicial) se obtendría la clausura(q0), es decir, todos los estados alcanzados con transiciones vacía desde este estado. Los estados serían{q1, q2}, a este Conjunto lo llamaremos A.




a
d
Aceptación
A={q0}{q1, q2}





Iteración 2: Se calculan todos los estados alcanzables con la letra a y d desde cada elemento del Conjunto A. Con la letra d desde q6 se llega a q3 y no se alcanza ningún estado. Con a desde q1 se llega a q6 y desde q2 se llega a q7 formando el conjunto {q6, q7} al cual se le aplica la clausura a q6 y q7 siendo los estados alcanzables con transiciones vacía el conjunto {q18, q4, q5}que forman el conjunto B. Como q5 es un estado de aceptación adquiere B la condición de estado final.




a
d
Aceptación
A={q0}{q1, q2}
B={q6, q7}{q18, q4, q5}


B={q6, q7}{q18, q4, q5}




Iteración 3: Se calculan todos los estados alcanzables con la letra a y d desde cada elemento del Conjunto B. Con la letra d desde q6 se llega a q3, desde q18 a q19 formando el conjunto {q3, q19}al cual se aplica la clausura y forman el conjunto {q5, q18, q4}, y la unión de ambos conjuntos da como resultado el conjunto C. Como q5 es un estado aceptación, C se convierte en estado final. Con la letra a no se alcanza ningún estado.




a
d
Aceptación
A={q0}{q1, q2}
B={q6, q7}{q18, q4, q5}


B={q6, q7}{q18, q4, q5}

C={q3, q19}{q5, q18, q4}
C={q3, q19}{q5, q18, q4}




Iteración 4: Se calculan todos los estados alcanzables con la letra a y d desde cada elemento del Conjunto C. Con la letra a no alcanza ningún estado. Con la letra d desde q18 se llega a q19, formando el conjunto {q19} al cual se le aplica la clausura emergiendo el conjunto {q3, q5, q18, q4}. Al unir estos dos conjunto se forma de nuevo el conjunto C.




a
d
Aceptación
A={q0}{q1, q2}
B={q6, q7}{q18, q19, q4, q5}


B={q6, q7}{q18, q4, q5}

C={q3, q19}{q5, q18, q4}
C={q3, q19}{q5, q18, q4}

 C={q19}{q3, q5, q18, q4}


Iteración 5 y final: No existe conjunto nuevo a analizar. Obteniendo la tabla del AFD equivalente.




a
d
Aceptación
A
B


B

C
C

C


Los conjuntos se transforman en estados. A es el estado inicial, B y C son estados aceptados o finales, porque como conjunto contienen a q5 y heredan sus propiedades. Siendo el autómata finito determinista:



Conversión de AFND a AFD

La expresión regular ad|ad* puede obtener un AFND equivalente:



A medida que se obtienen los conjuntos del autómata, se calcula la tabla de transición.

Iteración 1: Al comenzar con q0 (estado inicial) denominado A, se calculan todos los estados alcanzables con la letra a y d. Con la letra a desde q0 se llega a q1 y q2, formando el conjunto {q1, q2} denominado B. Con la letra d no alcanza ningún estado.




a
d
A={q0}
 B={q1, q2}

B




Iteración 2: Se calculan todos los estados alcanzables con la letra a y d del conjunto {q1, q2} Con la letra a no se alcanza ningún estado. Con la letra d desde q1 se llega a q3 y desde q2 se llega a q4, formando el conjunto C{q3, q4}.




a
d
A={q0}
 B={q1, q2}

B

C={q3, q4} 
C




Iteración 3: Se calculan todos los estados alcanzables con la letra a y d desde cada elemento del Conjunto C. Con la letra a no se alcanza ningún estado. Con la letra d desde q3 se llega a q3, formando el conjunto {q3}que pertenece a C.




a
d
A={q0}
 B={q1, q2}

B

C={q3, q4} 
C

C


Iteración 4: No existe conjunto nuevo a analizar.




a
d
Aceptación
A
B


B

C
C

C


Recomendacion: Leer:

Expresiones regulares a partir del autómata finito equivalente: Parte I 

Expresiones regulares a partir del autómata finito equivalente: Parte II 

Algoritmo de conversión de expresión regular a aut...

Referencias Bibliográficas 

1. Pérez Martínez, Abel. ERAFPLN. 2009.
2. PÉREZ, NALLY CAMPO. INTRODUCCIÓN A LA TEORÍA DE CONJUNTOS. [En
línea] http://www.e-socrates.org/mod/resource/view.php?id=4398.
3. REAL ACADEMIA ESPAÑOLA. [En línea] http://buscon.rae.es/draeI/.
4. Brena, Ramón. AUTOMATAS Y LENGUAJES. Monterrey : s.n., 2003.
5. Hopcroft, John E. Introducion to automata theory, languages, and computation.
s.l. : Addison-Wesley, 2001.
6. Lawson, M. V. Finite automata.
http://www.ma.hw.ac.uk/~markl/preprints/Lawson.pdf. [En línea] 
7. RegExlib. [En línea] http://regexlib.com/default.aspx.
8. Javascript Regular Expression Validator. [En línea]
http://tools.netshiftmedia.com/regexlibrary/.
9. RegexPal. [En línea] http://regexpal.com/.
10. metriplica.com, Grupo. ¡Prueba tus Expresiones Regulares!
http://www.metriplica.com/4_4_herramientas.asp. 2008.
11. Regular Expression Tool. [En línea]
http://erik.eae.net/playground/regexp/regexp.html.
12. Regexp Editor. [En línea] http://myregexp.com/.
13. Rad Software Regular Expression Designer 1.4.7528.27091. [En línea]
http://www.radsoftware.com.au/?from=RegexDesigner.
14. Visual REGEXP 3,0. [En línea] http://www.softpedia.com/get/Programming/OtherProgramming-Files/Visual-REGEXP.shtml.
15. Regulazy v1.0.3.0 (Beta). [En línea] http://tools.osherove.com/Default.aspx.
16. Regular Expression Workbench. [En línea] EricGu@Microsoft.Com.
17. Sells, Chris and Weinhardt, Michael. RegexDesigner v1.0.2727. [En línea]
http://www.sellsbrothers.com/tools/.
18. Visual Automata Simulator. [En línea] http://www.cs.usfca.edu/~jbovet/.
19. Acosta, Francisco Ríos. SP-PS1. [En línea] http://www.friosa.com.mx.
20. RegexBuddy3. [En línea] http://www.regexbuddy.com/.
21. The Software Process Dashboard Initiative. [En línea]
http://www.processdash.com/.
22. METODOLOGÍA DE MUESTREO. [En línea]
http://www.hsa.es/id/investigacion/uai/uai_docs/muestreo/muestreo.htm.
23. Modelos Abstractos de Cómputo I. [En línea]
http://www.sc.ehu.es/jiwnagom/MAC1/MAC-archivos/Tema2-parte3.pdf.