none
ACCESO A SQL SERVER COMO SERVICIO RRS feed

  • Pregunta

  • Hola. Soy nuevo en el desarrollo de aplicaciones con tecnología .net. El caso de la aplicación en cuestión es el siguiente:

    • La aplicación ha de estar leyendo continuamente una gran cantidad de información de unos autómatas y volcándolos a la base de datos.
    • Este flujo también ha de poderse dar en sentido inverso, desde la aplicación almacenar en los distintos autómatas.
    • La aplicación ha de poder consultar dicha información y acceder también a la base de datos para modificar/guardar otros parámetros.

    Para obtener un buen rendimiento ¿Cuál sería el camino?.

    Muchas gracias

    • Editado jpabloace domingo, 28 de diciembre de 2014 6:53
    domingo, 28 de diciembre de 2014 6:47

Respuestas

  • Mi sugerencia sería hacer una aplicación multi-hilo, donde se utilice uno (o varios) hilos para leer información de los autómatas, y uno (o varios) hilos para enviar información hacia los autómatas, además del hilo que gestione la interfaz de usuario.

    Desde el punto de vista de la base de datos, no debería haber mucho problema. Simplemente hay que saber que la conexión no es thread-safe, por lo que cada hilo debe abrir una conexión separada a la base de datos (en lugar de que todos los hilos compartan la misma conexión). Aparte de eso, el propio motor de la base de datos ya utiliza internamente varios hilos separados para atender las peticíones recibidas simultaneamente, por lo que no debería haber problema en este sentido.

    Habría que ver de cuántas operaciones por segundo estamos hablando cuando decimos "leyendo continuamente una gran cantidad de información", pero en principio incluso un PC "corrientito" puede soportar fácilmente veinte o treinta mil transacciones por segundo en un SQL Server local bien configurado, siempre que estén bien diseñadas para que no se bloqueen unas a otras.

    • Marcado como respuesta jpabloace domingo, 4 de enero de 2015 16:03
    domingo, 28 de diciembre de 2014 8:13
  • No, si era una aplicación con C# y WPF y no lanzaste aposta varios hilos, entonces no es un problema de bloqueos. Puede ser un problema de velocidad de escritura sobre el log de transacciones, o un problema debido a la forma de procesar las transacciones por parte de EF, o tal vez el coste añadido de construir varios índices sobre la tabla si es que los tenía.

    También puede ser debido a que lo probaste desde dentro de Visual Studio; si lanzas directamente el ejecutable compilado, corre mucho más que si lo ejecutas con el debugger.

    Por ejemplo, creé esta tabla de prueba:

    create table Prueba (
        campo1 int primary key nonclustered,
        campo2 varchar(50),
        campo3 varchar(50),
        campo4 varchar(50),
        campo5 varchar(50)
    )

    Y luego inserté registros con este código:

    using (SqlConnection cn = new SqlConnection("Server=.;DataBase=tempdb;trusted_connection=true"))
                {
                    cn.Open();
                    SqlCommand cmd = new SqlCommand("insert prueba values (@c1, @c2, @c3, @c4, @c5)", cn);
                    SqlParameter p1 = cmd.Parameters.Add("@c1", SqlDbType.Int);
                    SqlParameter p2 = cmd.Parameters.Add("@c2", SqlDbType.VarChar, 50);
                    SqlParameter p3 = cmd.Parameters.Add("@c3", SqlDbType.VarChar, 50);
                    SqlParameter p4 = cmd.Parameters.Add("@c4", SqlDbType.VarChar, 50);
                    SqlParameter p5 = cmd.Parameters.Add("@c5", SqlDbType.VarChar, 50);
                    for (int i = 0; i < 10000; i++)
                    {
                        p1.Value = i;
                        p2.Value = "Valor 2 " + i;
                        p3.Value = "Valor 3 " + i;
                        p4.Value = "Valor 4 " + i;
                        p5.Value = "Valor 5 " + i;
                        cmd.ExecuteNonQuery();
                    }
                }

    En un "laptop" corrientito, tardó 1,7 segundos en ejecutar las diez mil inserciones, rodando tanto el cliente como el servidor en la misma máquina y utilizando un único hilo. Si hubiéramos lanzado un par de hilos y combinando lecturas y escrituras, casi seguro que en este equipo (bastante anticuado y no muy rápido) llegaríamos fácilmente a las veinte mil operaciones por segundo.
    • Marcado como respuesta jpabloace lunes, 29 de diciembre de 2014 7:39
    domingo, 28 de diciembre de 2014 9:06
  • Como complemento a la respuesta de Alberto, he hecho unas pruebas de rendimiento de inserción, con Entity Framework, EntityLite y ADO.NET directo. He hecho pruebas de insertar un número de registros, por un lado uno a uno, y por otro lado todos de golpe en una sola transacción.

    Estos son los resultados para 5000 registros:

    InsertMultipleItemsEntityFramework
    8501
    InsertMultipleItemsEntityLite
    671
    InsertMultipleItemsRawAdoNet
    747
    InsertSingleItemEntityFramework
    7051
    InsertSingleItemEntityLite
    2633
    InsertSingleItemRawAdoNet
    2396

    Y estos para 1000 registros:

    InsertMultipleItemsEntityFramework
    573
    InsertMultipleItemsEntityLite
    119
    InsertMultipleItemsRawAdoNet
    144
    InsertSingleItemEntityFramework
    1509
    InsertSingleItemEntityLite
    449
    InsertSingleItemRawAdoNet
    421

    El más lento es EntityFramework en todos los casos y con gran difierencia. ADO.NET directo, debería ganar en todos los casos, pero la diferencia de rendimiento es tan pequeña con EntityLite que a veces los resultados dan ganador a EntityLite.

    Por otra parte he descubierto un comportamiento extraño en Entity Framework, con un número de cientos y cerca de mil, es más rápido insertar todos los registros de golpe en una sola transacción, pero a partir de cierto número el rendimiento se degrada, esto puede que sea debido a la gestión que hace EF de las entidades dentro del contexto.

    Por otra parte, con ADO.NET directo y EntityLite, el rendimiento es siempre mayor cuando insertas los registros todos de golpe en una transacción.

    Este es el código fuente usado en la prueba de rendimiento:

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data.Entity;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InsertPerformance
    {
        class Program
        {
            static void Main(string[] args)
            {
                const int itemCount = 1000;
                Database.SetInitializer<InsertPerformance.EntityFramework.ItemContext>(null);
                
                MultipleTest(itemCount, InsertMultipleItemsEntityFramework);
                MultipleTest(itemCount, InsertMultipleItemsEntityLite);
                MultipleTest(itemCount, InsertMultipleItemsRawAdoNet);
    
                SingleTest(itemCount, InsertSingleItemEntityFramework);
                SingleTest(itemCount, InsertSingleItemEntityLite);
                SingleTest(itemCount, InsertSingleItemRawAdoNet);
            }
    
    
            static void InsertMultipleItemsEntityFramework(int itemCount)
            {
                using (var context = new EntityFramework.ItemContext())
                {
                    for(int i = 1; i < itemCount; i++)
                    {
                        context.Items.Add(new EntityFramework.Item
                        {
                            Field1 = "Field 1." + i.ToString(),
                            Field2 = "Field 2." + i.ToString(),
                            Field3 = "Field 3." + i.ToString(),
                            Field4 = "Field 4." + i.ToString()
                        });
                    }
                    context.SaveChanges();
                }
            }
    
            static void InsertMultipleItemsEntityLite(int itemCount)
            {
                using (var ds = new Entities.ItemsDataService())
                {
                    ds.BeginTransaction();
                    for (int i = 1; i < itemCount; i++)
                    {
                        var item = new Entities.Item
                        {
                            Field1 = "Field 1." + i.ToString(),
                            Field2 = "Field 2." + i.ToString(),
                            Field3 = "Field 3." + i.ToString(),
                            Field4 = "Field 4." + i.ToString()
                        };
                        ds.ItemRepository.Insert(item);
                    }
                    ds.Commit();
                }
            }
    
            static SqlCommand CreateInsertCommand(SqlConnection cn, SqlTransaction tx)
            {
                var cmd = new SqlCommand("INSERT INTO Items(Field1, Field2, Field3, Field4) VALUES (@Field1, @Field2, @Field3, @Field4); SELECT SCOPE_IDENTITY();", cn);
                cmd.Parameters.Add("@Field1", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field2", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field3", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field4", System.Data.SqlDbType.NVarChar, 50);
                cmd.Transaction = tx;
                return cmd;
            }
    
            static void InsertMultipleItemsRawAdoNet(int itemCount)
            {
                using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
                {
                    cn.Open();
                    using (var tx = cn.BeginTransaction())
                    using (var cmd = CreateInsertCommand(cn, tx))
                    {
                        for (int i = 0; i < itemCount; i++)
                        {
                            cmd.Parameters["@Field1"].Value = "Field 1." + i.ToString();
                            cmd.Parameters["@Field2"].Value = "Field 2." + i.ToString();
                            cmd.Parameters["@Field3"].Value = "Field 3." + i.ToString();
                            cmd.Parameters["@Field4"].Value = "Field 4." + i.ToString();
                            int id = Convert.ToInt32( cmd.ExecuteNonQuery());
                        }
                    }
                }
            }
    
            static void InsertSingleItemRawAdoNet(int i)
            {
                using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
                {
                    cn.Open();
                    using (var cmd = CreateInsertCommand(cn, null))
                    {
                        cmd.Parameters["@Field1"].Value = "Field 1." + i.ToString();
                        cmd.Parameters["@Field2"].Value = "Field 2." + i.ToString();
                        cmd.Parameters["@Field3"].Value = "Field 3." + i.ToString();
                        cmd.Parameters["@Field4"].Value = "Field 4." + i.ToString();
                        int id = Convert.ToInt32(cmd.ExecuteNonQuery());
                    }
                }
            }
    
            static void InsertSingleItemEntityLite(int i)
            {
                using (var ds = new Entities.ItemsDataService())
                {
                    var item = new Entities.Item
                    {
                        Field1 = "Field 1." + i.ToString(),
                        Field2 = "Field 2." + i.ToString(),
                        Field3 = "Field 3." + i.ToString(),
                        Field4 = "Field 4." + i.ToString()
                    };
                    ds.ItemRepository.Insert(item);
                }
            }
    
            static void InsertSingleItemEntityFramework(int itemIndex)
            {
                using (var context = new EntityFramework.ItemContext())
                {
                    context.Items.Add(new EntityFramework.Item
                    {
                        Field1 = "Field 1." + itemIndex.ToString(),
                        Field2 = "Field 2." + itemIndex.ToString(),
                        Field3 = "Field 3." + itemIndex.ToString(),
                        Field4 = "Field 4." + itemIndex.ToString()
                    });
                    context.SaveChanges();
                }
            }
    
            static void MultipleTest(int itemCount, Action<int> testAction)
            {
                
                Console.WriteLine(testAction.Method.Name);
                testAction(2); // warm up
                TruncateTable();
                var watch = Stopwatch.StartNew();
                testAction(itemCount);
                watch.Stop();
                Console.WriteLine((int) watch.Elapsed.TotalMilliseconds);
            }
    
            static void SingleTest(int itemCount, Action<int> testAction)
            {
                TruncateTable();
                Console.WriteLine(testAction.Method.Name);
                var watch = Stopwatch.StartNew();
                for (int i = 0; i < itemCount; i++)
                {
                    testAction(i);
                }
                watch.Stop();
                Console.WriteLine((int)watch.Elapsed.TotalMilliseconds);
            }
    
            static SqlConnection CreateOpenConnection()
            {
                var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString);
                cn.Open();
                return cn;
            }
    
            static void TruncateTable()
            {
                using (var cn = CreateOpenConnection())
                using (var cmd = new SqlCommand("TRUNCATE TABLE Items", cn))
                {
                    cmd.ExecuteNonQuery();
                }
            }
        }
    }

    Y esta es la tabla:

    CREATE TABLE [dbo].[Items](
    	[ItemId] [int] IDENTITY(1,1) NOT NULL,
    	[Field1] [nvarchar](50) NULL,
    	[Field2] [nvarchar](50) NULL,
    	[Field3] [nvarchar](50) NULL,
    	[Field4] [nvarchar](50) NULL,
    PRIMARY KEY CLUSTERED 
    (
    	[ItemId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO



    Jesús López


    EntityLite a lightweight, database first, micro orm


    • Editado Jesús López lunes, 29 de diciembre de 2014 18:33 x
    • Marcado como respuesta jpabloace domingo, 4 de enero de 2015 16:02
    lunes, 29 de diciembre de 2014 18:32
  • Muchas gracias. El número de transacciones dependerá del número de autómatas conectados al cliente (en principio la aplicación a desarrollar es genérica). Yo había probado con un sql server en localhost y con una aplicación en C# con WPF y entity framework me había tardado como 3 segundos en añadir 1000 registros de 5 campos a una tabla. A lo mejor es por lo que dices del bloqueo.

    ¿Algún sitio que explique lo de evitar los bloqueos en las consultas?. 

    Muchas gracias.

    • Marcado como respuesta jpabloace domingo, 28 de diciembre de 2014 8:31
    • Desmarcado como respuesta jpabloace domingo, 28 de diciembre de 2014 8:32
    • Marcado como respuesta jpabloace lunes, 29 de diciembre de 2014 7:39
    domingo, 28 de diciembre de 2014 8:31

Todas las respuestas

  • Mi sugerencia sería hacer una aplicación multi-hilo, donde se utilice uno (o varios) hilos para leer información de los autómatas, y uno (o varios) hilos para enviar información hacia los autómatas, además del hilo que gestione la interfaz de usuario.

    Desde el punto de vista de la base de datos, no debería haber mucho problema. Simplemente hay que saber que la conexión no es thread-safe, por lo que cada hilo debe abrir una conexión separada a la base de datos (en lugar de que todos los hilos compartan la misma conexión). Aparte de eso, el propio motor de la base de datos ya utiliza internamente varios hilos separados para atender las peticíones recibidas simultaneamente, por lo que no debería haber problema en este sentido.

    Habría que ver de cuántas operaciones por segundo estamos hablando cuando decimos "leyendo continuamente una gran cantidad de información", pero en principio incluso un PC "corrientito" puede soportar fácilmente veinte o treinta mil transacciones por segundo en un SQL Server local bien configurado, siempre que estén bien diseñadas para que no se bloqueen unas a otras.

    • Marcado como respuesta jpabloace domingo, 4 de enero de 2015 16:03
    domingo, 28 de diciembre de 2014 8:13
  • Muchas gracias. El número de transacciones dependerá del número de autómatas conectados al cliente (en principio la aplicación a desarrollar es genérica). Yo había probado con un sql server en localhost y con una aplicación en C# con WPF y entity framework me había tardado como 3 segundos en añadir 1000 registros de 5 campos a una tabla. A lo mejor es por lo que dices del bloqueo.

    ¿Algún sitio que explique lo de evitar los bloqueos en las consultas?. 

    Muchas gracias.

    • Marcado como respuesta jpabloace domingo, 28 de diciembre de 2014 8:31
    • Desmarcado como respuesta jpabloace domingo, 28 de diciembre de 2014 8:32
    • Marcado como respuesta jpabloace lunes, 29 de diciembre de 2014 7:39
    domingo, 28 de diciembre de 2014 8:31
  • No, si era una aplicación con C# y WPF y no lanzaste aposta varios hilos, entonces no es un problema de bloqueos. Puede ser un problema de velocidad de escritura sobre el log de transacciones, o un problema debido a la forma de procesar las transacciones por parte de EF, o tal vez el coste añadido de construir varios índices sobre la tabla si es que los tenía.

    También puede ser debido a que lo probaste desde dentro de Visual Studio; si lanzas directamente el ejecutable compilado, corre mucho más que si lo ejecutas con el debugger.

    Por ejemplo, creé esta tabla de prueba:

    create table Prueba (
        campo1 int primary key nonclustered,
        campo2 varchar(50),
        campo3 varchar(50),
        campo4 varchar(50),
        campo5 varchar(50)
    )

    Y luego inserté registros con este código:

    using (SqlConnection cn = new SqlConnection("Server=.;DataBase=tempdb;trusted_connection=true"))
                {
                    cn.Open();
                    SqlCommand cmd = new SqlCommand("insert prueba values (@c1, @c2, @c3, @c4, @c5)", cn);
                    SqlParameter p1 = cmd.Parameters.Add("@c1", SqlDbType.Int);
                    SqlParameter p2 = cmd.Parameters.Add("@c2", SqlDbType.VarChar, 50);
                    SqlParameter p3 = cmd.Parameters.Add("@c3", SqlDbType.VarChar, 50);
                    SqlParameter p4 = cmd.Parameters.Add("@c4", SqlDbType.VarChar, 50);
                    SqlParameter p5 = cmd.Parameters.Add("@c5", SqlDbType.VarChar, 50);
                    for (int i = 0; i < 10000; i++)
                    {
                        p1.Value = i;
                        p2.Value = "Valor 2 " + i;
                        p3.Value = "Valor 3 " + i;
                        p4.Value = "Valor 4 " + i;
                        p5.Value = "Valor 5 " + i;
                        cmd.ExecuteNonQuery();
                    }
                }

    En un "laptop" corrientito, tardó 1,7 segundos en ejecutar las diez mil inserciones, rodando tanto el cliente como el servidor en la misma máquina y utilizando un único hilo. Si hubiéramos lanzado un par de hilos y combinando lecturas y escrituras, casi seguro que en este equipo (bastante anticuado y no muy rápido) llegaríamos fácilmente a las veinte mil operaciones por segundo.
    • Marcado como respuesta jpabloace lunes, 29 de diciembre de 2014 7:39
    domingo, 28 de diciembre de 2014 9:06
  • Como complemento a la respuesta de Alberto, he hecho unas pruebas de rendimiento de inserción, con Entity Framework, EntityLite y ADO.NET directo. He hecho pruebas de insertar un número de registros, por un lado uno a uno, y por otro lado todos de golpe en una sola transacción.

    Estos son los resultados para 5000 registros:

    InsertMultipleItemsEntityFramework
    8501
    InsertMultipleItemsEntityLite
    671
    InsertMultipleItemsRawAdoNet
    747
    InsertSingleItemEntityFramework
    7051
    InsertSingleItemEntityLite
    2633
    InsertSingleItemRawAdoNet
    2396

    Y estos para 1000 registros:

    InsertMultipleItemsEntityFramework
    573
    InsertMultipleItemsEntityLite
    119
    InsertMultipleItemsRawAdoNet
    144
    InsertSingleItemEntityFramework
    1509
    InsertSingleItemEntityLite
    449
    InsertSingleItemRawAdoNet
    421

    El más lento es EntityFramework en todos los casos y con gran difierencia. ADO.NET directo, debería ganar en todos los casos, pero la diferencia de rendimiento es tan pequeña con EntityLite que a veces los resultados dan ganador a EntityLite.

    Por otra parte he descubierto un comportamiento extraño en Entity Framework, con un número de cientos y cerca de mil, es más rápido insertar todos los registros de golpe en una sola transacción, pero a partir de cierto número el rendimiento se degrada, esto puede que sea debido a la gestión que hace EF de las entidades dentro del contexto.

    Por otra parte, con ADO.NET directo y EntityLite, el rendimiento es siempre mayor cuando insertas los registros todos de golpe en una transacción.

    Este es el código fuente usado en la prueba de rendimiento:

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data.Entity;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InsertPerformance
    {
        class Program
        {
            static void Main(string[] args)
            {
                const int itemCount = 1000;
                Database.SetInitializer<InsertPerformance.EntityFramework.ItemContext>(null);
                
                MultipleTest(itemCount, InsertMultipleItemsEntityFramework);
                MultipleTest(itemCount, InsertMultipleItemsEntityLite);
                MultipleTest(itemCount, InsertMultipleItemsRawAdoNet);
    
                SingleTest(itemCount, InsertSingleItemEntityFramework);
                SingleTest(itemCount, InsertSingleItemEntityLite);
                SingleTest(itemCount, InsertSingleItemRawAdoNet);
            }
    
    
            static void InsertMultipleItemsEntityFramework(int itemCount)
            {
                using (var context = new EntityFramework.ItemContext())
                {
                    for(int i = 1; i < itemCount; i++)
                    {
                        context.Items.Add(new EntityFramework.Item
                        {
                            Field1 = "Field 1." + i.ToString(),
                            Field2 = "Field 2." + i.ToString(),
                            Field3 = "Field 3." + i.ToString(),
                            Field4 = "Field 4." + i.ToString()
                        });
                    }
                    context.SaveChanges();
                }
            }
    
            static void InsertMultipleItemsEntityLite(int itemCount)
            {
                using (var ds = new Entities.ItemsDataService())
                {
                    ds.BeginTransaction();
                    for (int i = 1; i < itemCount; i++)
                    {
                        var item = new Entities.Item
                        {
                            Field1 = "Field 1." + i.ToString(),
                            Field2 = "Field 2." + i.ToString(),
                            Field3 = "Field 3." + i.ToString(),
                            Field4 = "Field 4." + i.ToString()
                        };
                        ds.ItemRepository.Insert(item);
                    }
                    ds.Commit();
                }
            }
    
            static SqlCommand CreateInsertCommand(SqlConnection cn, SqlTransaction tx)
            {
                var cmd = new SqlCommand("INSERT INTO Items(Field1, Field2, Field3, Field4) VALUES (@Field1, @Field2, @Field3, @Field4); SELECT SCOPE_IDENTITY();", cn);
                cmd.Parameters.Add("@Field1", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field2", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field3", System.Data.SqlDbType.NVarChar, 50);
                cmd.Parameters.Add("@Field4", System.Data.SqlDbType.NVarChar, 50);
                cmd.Transaction = tx;
                return cmd;
            }
    
            static void InsertMultipleItemsRawAdoNet(int itemCount)
            {
                using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
                {
                    cn.Open();
                    using (var tx = cn.BeginTransaction())
                    using (var cmd = CreateInsertCommand(cn, tx))
                    {
                        for (int i = 0; i < itemCount; i++)
                        {
                            cmd.Parameters["@Field1"].Value = "Field 1." + i.ToString();
                            cmd.Parameters["@Field2"].Value = "Field 2." + i.ToString();
                            cmd.Parameters["@Field3"].Value = "Field 3." + i.ToString();
                            cmd.Parameters["@Field4"].Value = "Field 4." + i.ToString();
                            int id = Convert.ToInt32( cmd.ExecuteNonQuery());
                        }
                    }
                }
            }
    
            static void InsertSingleItemRawAdoNet(int i)
            {
                using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString))
                {
                    cn.Open();
                    using (var cmd = CreateInsertCommand(cn, null))
                    {
                        cmd.Parameters["@Field1"].Value = "Field 1." + i.ToString();
                        cmd.Parameters["@Field2"].Value = "Field 2." + i.ToString();
                        cmd.Parameters["@Field3"].Value = "Field 3." + i.ToString();
                        cmd.Parameters["@Field4"].Value = "Field 4." + i.ToString();
                        int id = Convert.ToInt32(cmd.ExecuteNonQuery());
                    }
                }
            }
    
            static void InsertSingleItemEntityLite(int i)
            {
                using (var ds = new Entities.ItemsDataService())
                {
                    var item = new Entities.Item
                    {
                        Field1 = "Field 1." + i.ToString(),
                        Field2 = "Field 2." + i.ToString(),
                        Field3 = "Field 3." + i.ToString(),
                        Field4 = "Field 4." + i.ToString()
                    };
                    ds.ItemRepository.Insert(item);
                }
            }
    
            static void InsertSingleItemEntityFramework(int itemIndex)
            {
                using (var context = new EntityFramework.ItemContext())
                {
                    context.Items.Add(new EntityFramework.Item
                    {
                        Field1 = "Field 1." + itemIndex.ToString(),
                        Field2 = "Field 2." + itemIndex.ToString(),
                        Field3 = "Field 3." + itemIndex.ToString(),
                        Field4 = "Field 4." + itemIndex.ToString()
                    });
                    context.SaveChanges();
                }
            }
    
            static void MultipleTest(int itemCount, Action<int> testAction)
            {
                
                Console.WriteLine(testAction.Method.Name);
                testAction(2); // warm up
                TruncateTable();
                var watch = Stopwatch.StartNew();
                testAction(itemCount);
                watch.Stop();
                Console.WriteLine((int) watch.Elapsed.TotalMilliseconds);
            }
    
            static void SingleTest(int itemCount, Action<int> testAction)
            {
                TruncateTable();
                Console.WriteLine(testAction.Method.Name);
                var watch = Stopwatch.StartNew();
                for (int i = 0; i < itemCount; i++)
                {
                    testAction(i);
                }
                watch.Stop();
                Console.WriteLine((int)watch.Elapsed.TotalMilliseconds);
            }
    
            static SqlConnection CreateOpenConnection()
            {
                var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Test"].ConnectionString);
                cn.Open();
                return cn;
            }
    
            static void TruncateTable()
            {
                using (var cn = CreateOpenConnection())
                using (var cmd = new SqlCommand("TRUNCATE TABLE Items", cn))
                {
                    cmd.ExecuteNonQuery();
                }
            }
        }
    }

    Y esta es la tabla:

    CREATE TABLE [dbo].[Items](
    	[ItemId] [int] IDENTITY(1,1) NOT NULL,
    	[Field1] [nvarchar](50) NULL,
    	[Field2] [nvarchar](50) NULL,
    	[Field3] [nvarchar](50) NULL,
    	[Field4] [nvarchar](50) NULL,
    PRIMARY KEY CLUSTERED 
    (
    	[ItemId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO



    Jesús López


    EntityLite a lightweight, database first, micro orm


    • Editado Jesús López lunes, 29 de diciembre de 2014 18:33 x
    • Marcado como respuesta jpabloace domingo, 4 de enero de 2015 16:02
    lunes, 29 de diciembre de 2014 18:32
  • Gracias. Pensaba implementarlo con Entity Framework, pero después de tu respuesta tendré que valolarlo nuevamente. Muchas gracias
    domingo, 4 de enero de 2015 16:06