LINQ to SQL (4ª Parte) – Actualizando la base de datos

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un O/RM(object relational mapper) integrado en la versión 3.5 del framework de .NET, y nos permite modelar fácilmente bases de datos relacionales en clases de .NET. Podemos usar expresiones LINQ tanto para consultar la base de datos como para actualizar, insertar y borrar datos.

Aquí tenéis los links a los tres primeros post:

En el post de hoy veremos cómo usar el modelo de datos que hemos creado, y usarlo para actualizar, insertar y borrar datos. También veremos cómo integrar reglas de negocio y crear lógica de validación personalizada con nuetro modelo de datos.

Modelado de la base de datos NorthWind con LINQ to SQL

En la segundo post de esta serie, vimos cómo crear el modelo de clases con el diseñador de LINQ to SQL que trae VS 2008. Aquí tenéis el modelo que creamos a partir de la base de datos de ejemplo Northwind que usaremos en este post:

Cuando definimos el modelo definimos cinco clases: Product, Category, Customer, Order y OrderDetail. Las propiedades de cada clase mapean las diferentes columnas de las tablas correspondientes en la base de datos. Cada instancia de cada clase es una entidad que representa una fila de cada tabal.

Cuando definimos nuestro modelo de datos, el diseñador LINQ to SQL creó una clase llamada DataContext que proporciona todo lo necesario para poder consultar/actualizar  la base de datos. En nuestro ejemplo, esta clase se llama NorthwindDataContext. Ésta clase tiene unas propiedades que representan cada tabla modelada de la base de datos (en concreto: Products, Categories, Customers, Orders y OrderDetails).

Como vimos en el tercer post de esta serie, podemos usar expresiones LINQ para consultar y obtener datos usando la clase NorthwindDataContext.LINQ to SQL traduce automáticamente estas expresiones LINQ al código SQL apropiado en tiempo de ejecución.

Por ejemplo, la siguiente expresión devuelve un objeto Product buscando el nombre del  producto:

La siguiente consulta nos devuelve todos los productos de la base de datos que no han sido pedidos, y cuyo precio es mayor de 100 dólares:

Estamos usando la asociación "OrderDetails" de cada producto como parte de la consulta sólo para obtener aquellos productos que no se han pedido.

Seguir los cambios y DataContext.SubmitChanges()

Cuando creamos consultas y obtenemos objetos como en los ejemplos anteriores, LINQ to SQL estará pendiente de los cambios o actualizaciones que les hagamos a los objetos. Podemos hacer tantas consultas y cambios como queramos usando la clase DataContext de LINQ to SQL, sabiendo que dichos cambios serán supervisados a la vez:

Nota: El seguimiento de cambios de LINQ to SQL ocurre en el lado del consumidor - y NO en la base de datos. Es decir, no estamos consumiendo ningún recurso de la base de datos mientras lo usemos, tampoco tenemos que cambiar/instalar nada en la base de datos para que esto funcione.

Después de realizar los cambios que queramos a los objetos que hemos obtenido con LINQ to SQL, podemos llamar al método "SubmitChanges()" de nuestro DataContext para guardar los cambios en nuestra base de datos. Con esto, LINQ to SQL, creara y ejecutará las sentencias SQL apropiadas para actualizar la base de datos.

Por ejemplo, el siguiente código actualiza el precio y las unidades en stock del producto "Chai" en la base de datos:

Cuando llamamos al método northwind.SubmitChanges(), LINQ to SQL creará y ejecutará las sentencias "UPDATE" de SQL necesarias para guardar las propiedades modificadas.

Con el siguiente código iteramos sobre los productos menos populares y caros y ponemos la propiedad "ReorderLevel" a cero.

Cuando llamamos al método northwind.SubmitChanges(), LINQ to SQL crea y ejecuta las sentencias UPDATE de SQL necesarias para modificar los productos a los que hemos modificado la propiedad ReorderLevel.

Vemos que si no se ha modificado alguna propiedad de un Product con la asignación anterior, LINQ to SQL no ejecutará ninguna actualización para ese objeto. Por ejemplo - si el precio del producto "Chai" era 2 dolares, y el número de unidades en stock era cuatro, la llamada a SubmitChanges() no actualizara esos valores. Sólo los productos cuyo ReorderLevel no era 0 se actualizarán.

Ejemplos de inserción y borrado

Además de poder actualizar la base de datos, LINQ to SQL también nos permite insertar y eliminar datos. Esto lo conseguimos añadiendo o eliminando objectos de las colecciones disponibles en DataContest, y luego llamar al método SubmitChanges(). LINQ to SQL "monitorizará" esas inserciones y borrados, y generará el código SQL necesario cuando se invoque a SubmitChanges()

Añadiendo un producto

Podemos añadir un producto a la base de datos creando un nuevo objeto "Product", inicializando sus propiedades y añadirlo a la colección "Products" de nuestro DataContext:

Cuando llamemos a SubmitChanges() se añadirá una nueva fila en la tabla de productos.

Borrando productos

De la misma forma que añadimos un nuevo producto a la base de datos añadiendo un objeto Product a la colección Products del DataContext, también podemos borrar productos borrándolos de esa misma colección:

Lo que estamos haciendo es obtener una secuencia de productos "alternados" de la tabla, es decir, no ordenados por ninguna expresión LINQ, y luego esa secuencia se la pasamos al método RemoveAll() de la colección "Products". Cuando llamamos a SubmitChanges() todos esos productos serán borrados de la tabla

Actualizaciones y relaciones

Lo que hace que los O/RM's como LINQ to SQL sean tan flexibles es que también nos permiten modelar las relaciones entre las tablas. Por ejemplo, podemos modelar que cada producto tenga una categoría, que cada pedido tenga un detalle de pedido, asociar cada detalle de pedido con un producto, y tener un conjunto de pedidos en cada cliente. Ya vimos cómo modelar las relaciones en la segunda parte de esta serie de post.

LINQ to SQL nos permite aprovechar estas relaciones tanto para consultar como para actualizar nuestros datos. Por ejemplo, con el siguiente código creamos un nuevo producto y lo asociamos con la categoría "Beverages":

Estamos añadiendo el objeto producto en la colección de categorías de productos. Esto indicará que hay una relación entre dos objetos, y hará que LINQ to SQL mantenga automáticamente las relaciones de clave primaria/ajena entre los dos cuando llamemos a SubmitChanges().

Veamos otro ejemplo para ver cómo LINQ to SQL nos ayuda a mantener limpio el código referente a las relaciones entre las tablas. En el siguiente ejemplo estamos creando un nuevo pedido para un cliente existente. Después de rellenar las propiedades necesarias, podemos crear dos objetos de detalles de pedido y asociarlo a un pedido de un cliente y actualizaremos la base de datos con todos los cambios:

Como vemos, el modelo de programación que hemos usado para hacer todo esto es realmente limpio y orientado a objetos.

Transacciones

Una transacción es un servicio de la base de datos que garantiza que un conjunto de acciones individuales van a suceder de forma atómica - es decir, o se pueden completar todas o si hay alguna que falle, todas las demas se descartarán, y el estado de la base de datos será el mismo que ántes de comenzar la transacción.

Cuando llamemos a SubmitChanges(), las actualizaciones se mapean en una única transacción. Es decir, la base de datos no tendrá nunca un estado inconsistente si hacemos muchos cambios - tanto si se hacen las actualizaciones como si no.

Si no hay ninguna transacción en curso, el objeto DataContext empezará una transacción de la base de datos para guardar las actualizaciones que hagamos con SubmitChanges(). Pero LINQ to SQL también nos permite definir explícitamente y usar nuestro propio sistema de transacciones (introducido en la versión 2.0 de .NET). Esto hace más fácil aún integrar código LINQ to SQL con el código de acceso a datos que ya tengamos. También nos permite encolar recursos que no son propios de la base de datos en la misma transacción - por ejemplo: podemos enviar un mensage MSMQ, actualizar el sistema de archivos (usando el nuevo soporte transaccional de sistemas de archivos), etc - y enlazar todas estas tareas en una sola transacción a la hora de actualizar la base de datos

Validación y lógica de negocio

Una de las cosas más importantes que los desarrolladores tienen que hacer cuando trabajan con datos es incorporar validación  y reglas de negocio. LINQ to SQL tiene varias formas para hacer que los desarrolladores puedan hacer eso de forma fácil y clara.

LINQ to SQL nos permite añadir esta validación lógica una vez. De forma que no tendremos que repetir esa lógica en varios sitios, con lo que conseguimos un modelo de datos más mantenible y más claro.

Soporte de validación de esquemas

Cuando definimos el modelo de clases de datos con el diseñador de LINQ to SQL de VS 2008, se añadirán algunas reglas de validación obtenidas del esquema de las tablas de la base de datos.

Los tipos de datos de las propiedades de las clases del modelo de datos coincidirán con el esquema de la base de datos. Con esto tendremos errores de compilación si intentamos asignar un booleano a un valor decimal, o si convertirmos tipos numéricos incorrectamente.

Si una columna en la base de datos está marcada como nullable, la propiedad correspondiente que crea el diseñador de LINQ to SQL será un tipo nullable. Las columnas marcadas como no nullables lanzarán excepciones si no les asignamos ningun valor. LINQ to SQL también se asegurará que de que los valores identidad/unicos se asignan correctamente.

Obviamente podemos usar el diseñador LINQ to SQL para sobreescribir los valores por defecto del esquema si queremos - pero por defecto, las tendremos automáticamente sin tener que hacer nada. LINQ to SQL también comprueba los valores de los parámetros de las consultas SQL, de manera que no tendremos que preocuparnos por los ataques de inyección de SQL.

Soporte para validación personalizada de propiedades

La validación de datos a través de esquemas es muy útil, pero no suele ser suficiente en escenarios reales.

Imaginemos que en la base de datos Northwind tenemos una propiedad "Phone" en la clase "Customer" que está definida en la base de datos como nvarchar. Usando LINQ to SQL podemos escribir el siguiente código para actualizarlo con un número de teléfono válido:

El problema que nos encontraríamos, sería que el siguiente código sigue siendo válido desde el punto de vista de un esquema SQL (ya que sigue siendo una cadena, no un número de teléfono válido).

Para no permitir que no se puedan meter números de teléfono erróneos en nuestra base de datos, podemos añadir una regla de validación personalizada a la clase Customer de nuestro modelo de datos. Es realmente fácil, todo lo que necesitamos hacer es añadir una nueva clase parcial a nuestro proyecto que defina el siguiente método:

Este código usa dos caracteristicas de LINQ to SQL:

  1. Todas las clases que genera el diseñador LINQ to SQL son "parciales" - es decir, podemos añadir métodos adicionales, propiedades, y eventos (en archivos separados). Así podemos extender nuestro modelo de clases creada por el diseñador de LINQ to SQL con reglas de validación y métodos auxiliares que definamos. No es necesario ninguna configuración.
  2. LINQ to SQL expone una serie de puntos de extensión en el modelo de datos que podemos usar para añadir validación lógica. Muchos de estos puntos de extensión usan la nueva característica llamada "métodos parciales" que viene con VB y C# en VS 2008 Beta2. Wes Dyer el equipo de C# ha escrito un post explicando cómo va esto de los métodos parciales.

En nuestro ejemplo de validación, estamos usando el método parcial OnPhoneChangin que se ejecuta cada vez que se cambia el valor de la propiedad "Phone" de un objeto "Customer". Podemos usar este método para validar la entrada de datos (en este caso estamos usan una expresión regular). Si todo va bien, LINQ to SQL asumirá que el valor es válido. Si hay algún problema con el valor, podemos lanzar una excepción en el método de validación - que hará que la asignación no se haga.

Soporte para validación personalizada de objetos entidad.

En el punto anterior hemos visto cómo añadir validación a una propiedad individual de nuestro modelo de datos. Sin embargo, algunas veces, necesitamos/queremos validar validar multiples propiedades de un objeto.

Veamos un ejemplo, tenemos un objeto Order y queremos poner las propiedades "OrderDate" y "RequiredDate":

Este código es legal desde el punto de vista de SQL - aunque no tenga ningún sentido la propiedad de fecha de entrega, que era para ayer.

LINQ to SQL en Beta2 nos permite añadir reglas de validación a nivel de entidad para corregir este tipo de errores. Podemos añadir una clase parcial para nuestra entidad "Order" e implementar el método parcial OnValidate() que se invocará ántes de que se guarden los datos en la base de datos. De esta forma, podemos acceder y validar todas las propiedades de nuestro modelo de datos:

De esta forma podemos validar cualquiera de las propiedades de la entidad (incluso obtener acceso de sólo lectura a los objetos asociados), y lanzar una excepción si el valor es incorrecto. Cualquier excepción lanzada desde el método OnValidate() abortará cualquier cambio que queramos hacer en la base de datos, y deshacer todos los cambios hechos en la transacción actual.

Validación en los métodos de inserción/actualización/borrado.

A menudo necesitamos añadir validación específica en los métodos de inserción, actualización o borrado. LINQ to SQL nos lo permite añadiendo una clase parcial que extienda a la clase DataContext e implementar métodos parciales para personalizar la lógica de inserción, actualización y borrado de las entidades de nuestro modelo de datos. Estos métodos serán llamados automáticamente cuando invoquemos a SubmitChanges().

Podemos añadir la validación lógica que estimemos oportuna con estos métodos - y si todo va bien, LINQ to SQL continará guardando los datos en la base de datos (llamando al método de DataContext "ExecuteDynamicXYZ").

Podemos añadir métodos que se invocarán automáticamente cuando se vayan a crear/actualizar/borrar datos. Por ejemplo, supongamos que queremos crear un nuevo pedido y asociarlo con un cliente existente:

Cuando llamamos a northwind.SubmitChanges(), LINQ to SQL determinará que es necesario guardar el nuevo objeto Order, y ejecutará nuestro método parcial "InsertOrder".

Avanzado: Viendo la lista de cambios de la transacción

Hay veces que no nos interesa añadir validación lógica a elementos individuales, sino que queremos ser capaces de ver toda la lista de cambios que están ocurriendo en una transacción.

Desde la Beta2 de .NET 3.5, LINQ to SQL nos permite acceder a la lista de cambios a través del método DataContext.GetChangeList(). Nos devolverá un objeto ChangeList que expone una serie de colecciones de adiciones, borrados y modificaciones que se han hecho.

Una aproximación que podemos hacer en algunos escenarios es crear una clase parcial de la clase DataContext y sobreescribir su método SubmitChange(). Podemos obtener la lista de ChangeList() para las operaciones de actualizaciones y crear cualquier validación que queramos:

Este ejemplo es un caso de uso avanzado - pero es interesante saber que siempre podremos extender y aprovecharnos de esta forma de las nuevas características de LINQ to SQL.

Administrando cambios simultáneos con concurrencia optimista.

Una de las cosas en las que tenemos que pensar los desarrolladores en entornos multi-usuarios es cómo administrar las actualizaciones de los mismos datos en la base de datos. Por ejemplo, imaginemos que tenemos dos usuarios que obtienen un objeto product, y uno de ellos cambia el ReorderLevel a 0 mientras que el otro lo pone a 1. Si ambos usuarios guardan esos cambios en la base de datos, el desarrollador tiene que decidir cómo tratar ese conflicto.

Una solución es dejar que sea el último que lo guarda - es decir, que el valor que el primer usuario guardó se perderá sin que éste se de cuenta. Esta es una solución muy pobre (e incorrecta).

Otra solución que permite LINQ to SQL es usar el modelo de concurrencia optimista, es decir, LINQ to SQL detectará automáticamente si el valor original de la base de datos ha sido actualizado por alguien ántes que se guarden los nuevos datos. LINQ to SQL nos da una lista de conflictos de valores cambiados al desarrollador y nos permite tanto hacer lo que queramos como avisar al usuario de la aplicación para que nos indique el propio usuario lo que quiere hacer.

Ya veremos en más detalle este tema en un próximo post.

Uso de procedimientos almacenados o lógica SQL personalizada para insertar, actualizar y borrar.

Una de las preguntas que tienen los desarrolladores (en especial los DBAs), que suelen escribir procedimientos almacenados con SQL personalizadas, cuando ven LINQ to SQL por primeravez es: "¿pero cómo podemos tener control absoluto del SQL que se está ejecutando?".

Las buenas noticias son que LINQ to SQL tiene un modelo muy flexible que nos permite sobreescribir el SQL que se está ejecutando, y llamar a los procedimientos almacenados que desarrollemos para añadir, actualizar o borrar datos.

Lo realmente increible es que podemos empezar definiendo nuestro modelo de datos y dejar que LINQ to SQL administre las inserciones, actualizaciones y borrados. Una vez hecho esto, podemos personalizar el modelo de datos para que use nuestros propios procedimientos almacenados o nuestras sentencias SQL - sin tener que cambiar nada de la lógica de aplicación que estamos usando para nuestro modelo de datos, ni cambiar nada de las validaciones ni de la lógica de negocio. Esto nos da una gran flexibilidad a la hora de construir nuestra aplicación.

Dejaremos para otro post cómo personalizar los modelos de datos con procedimientos almacenados o sentencias SQL.

Resumen.

Este post presenta un buen resumen sobre cómo podemos usar LINQ to SQL para actualizar nuestra base de datos e integrar de una forma clara validación de datos y lógica de negocio. Creo que encontraréis que LINQ to SQL incrementa mucho la prouctividad a la hora de trabajar con datos, y nos permite escribir código orientado a objeto claro en el acceso a datos.

En próximos post veremos el nuevo control <asp:linqdatasource> de la versión 3.5 de .NET, y hablaremos sobre lo fácil que es crear interfaces de usuario en ASP.NET que se aprovechen de los modelos de datos de LINQ to SQL. También veremos algunos conceptos de programación más especificos de LINQ to SQL sobre concurrencia optimista, carga perezosa, herencia de mapeado de tablas, uso de procedimientos almacenados y sentencias SQL personalizadas, y mucho más.

Espero que sirva.

Scott.

Traducido por: Juan María Laó Ramos. Microsoft Student Partner.

toH tlhIngan Hol DajatlhlaH ‘e’ DaneH’a’?

43 pensamientos en “LINQ to SQL (4ª Parte) – Actualizando la base de datos

  1. Pingback: LINQ to SQL (5ª Parte - Enlazar controles de interfaz de usuario con el ASP:LinqDatSource « Thinking in .NET

  2. Miguel Ángel

    Hola, el post me parece estupendo.
    Ocurre que cuando implementamos reglas de validación a nivel de columna o entidad a la hora de invocar al método SubmitChanges() en nuestro código los cambios no se realizan en la base de datos, es decir, actúan las reglas de validación, son correctas, pero no se modifica la base de datos ¿por qué?.

  3. Vio

    Ese problema me suena de algo, y es que tenía el método SubmitChanges() dentro de un try catch. Comprueba que no se esté lanzado alguna excepción en el submitChanges().

  4. eDu

    Hola! muy bueno el post, estamos inmersos en un proyecto para la universidad y nos está ayudando mucho. Mi problema es que no puedo invocar al método Add() para añadir líneas a la base de datos, me dice que no tengo definido ese método (ni el Remove())

    ¿Alguna idea?

    Gracias

  5. Vio

    Hola eDu:

    Están un poco desactualizado el post. En la versión que se ha publicado debes usar el método insertOnSubmit() en vez de Add() y DeleteOnSubmit() en vez de Remove().
    y luego llamar a submitChanges.

    Espero que sirva

  6. eDu

    Muchas gracias Vio.

    resulta que lo estaba haciendo como tu dices porque me imaginaba que era “más nuevo”, pero me daba errores por las ForeingKeys en las relaciones de las tablas, vamos, que lo más fácil era lo que no veía.

    Gracias de todos modos y un saludo

  7. Jose

    Cuando intento generar la clase parcial Customer con el metodo parcial OnPhoneChanging no me reconoce el metodo y me sale el siguiente mensaje de error:

    Error 1 ‘Customer’ does not contain a definition for ‘OnPhoneChanging’ and no extension method ‘OnPhoneChanging’ accepting a first argument of type ‘Customer’ could be found (are you missing a using directive or an assembly reference?) LinqToSqlDefault.aspx.cs 41 20 d:…LinqToSql

    Que puede ser?

  8. Vio

    Parece que no estás creando de manera adecuada el método de extensión OnPhoneChanging.

    namespace MisExtensiones
    {
    public static class ExtensionesDeCustomer
    {
    public static string OnPhoneChanging(this Customer arr, string msg)
    {
    return “El Customer dice: “+ msg;
    }
    }
    }

    Comprueba que lo estás haciendo de manera correcta. En una clase estática y un método estático.

    Espero que sirva

  9. Jose

    Hola Vio, gracias por responder. He actualizado mi ReglasValidaciones.cs con el código que muestras en el POST 7 del siguiente modo:

    using System;
    using System.Text.RegularExpressions;

    public partial class Customer
    {
    partial void OnPhoneChanging(this string value)
    {
    Regex phoneNumber = new Regex(@”^[2-9]d{2}-d{3}-d{4}$”);

    if (!phoneNumber.IsMatch(value))
    { throw new ArgumentException(“Not a valid phone number!”); }
    }
    }

    public partial class Order
    {
    partial void OnValidate()
    {
    if (RequiredDate < OrderDate)
    { throw new Exception(“Deviler date is before order date”); }
    }
    }

    El archivo esta situado en la raiz de la solucion al igual que el Default.aspx.cs que es donde estoy implementando los metodos con fines de prueba solamente. En la llamada en uno de los metodos que uso en Default.aspx.cs lo hago tal y cual mencionas en tu APP de ejemplo:

    Customer myCustomer = db.Customers.Single(c => c.CompanyName == “B’s Beverages”);
    string phone = “uygvjhvhjvvjvj”;
    myCustomer.Phone = phone;

    myCustomer.OnPhoneChanging(phone);

    El error sigue siendo el mismo:

    Error 1 ‘Customer’ does not contain a definition for ‘OnPhoneChanging’ and no extension method ‘OnPhoneChanging’ accepting a first argument of type ‘Customer’ could be found (are you missing a using directive or an assembly reference?) d:JRocaOtrosNETPruebasLinqToSqlDefault.aspx.cs 44 20 d:…LinqToSql

    No sera otra cosa???, me estoy guiando tal cual sigue el sgte post y eso es lo unico que me esta causando problemas, de ahi en adelante, todo de maravillas…por cierto a excepcion de ese detalle, estoy MUY satisfecho con esta serie de posts, gracias y congratulaciones…

  10. Vio

    El problema del método de extensión es que lo tienes que definir como estático en una clase estática. Completamente aparte de la clase Customer. Lo tienes declarado como partial, y debe ser estático. En este post:
    http://speakingin.net/2007/03/28/nueva-caracteristica-de-%E2%80%9Corcas%E2%80%9D-metodos-de-extension/
    Tienes cómo se hace. Declaras una clase estática, por ejemplo: MetodosExtension y dentro defines el método de extensión que debe ser estático.

    Espero que te sirva.

  11. Benito Sepulveda

    He estado haciendo pruebas con la heramienta, pero cunado se genera el codigo LINQ-SQL observo que no genera los metodos insert,delete,update que me permiten hacer modificaciones a las tablas de sql-server, solo en unas tablas y en otras si lo genera, no veo la razon aparente para que me haga eso. he estado invetigando con lo que tengo a mi alcace y no encentro la solucion. ya me ha quitado en sueño este problema……

  12. Vio

    Si no te he entendido mal, creo que piensas que linq to sql te va a generar los procedimientos almacenados para insert, delet y update. Esto no es así. Te genera unos métodos para ello que están en la clase DataContext.
    También está la opcion de decirle que use los procedimientos alamacenados que tu le digas para hacer esas operaciones.
    Héchale un vistazo a los post anteriores de la serie y dime si te ha resuleto la duda.
    Un saludo.

  13. Benito Sepulveda

    Gracias, por tu pronta respuesta, mi problema lo veo de la sig. forma. Ya tengo funcionando la aplicacion que actualiza el catalago de grupos. La forma en que actualizo, inserto en la tabla haciendo uso de LINQ-SQL si funciona. La plantilla para el catalago de subgrupos es exactamente igual, pero con la variante que no me actualiza o inserta datos cuando invoco db.SubmitChanges(), revise el codigo que genera LINQ, y la diferencia que encontre entre los metodos generados de ambas tablas, es que para la de subgrupos, no genera los metodos para hacer la actualizacion. de ahi mi duda, que hay de diferente entre ambas tablas., te voy ha anexar el codigo generado, para que veas la diferencia que encontre, posiblemente no me he sabido explicar. Te aclaro estoy haciendo mi primeros pinimos con estas herramientas.

  14. Vio

    Hola Benito:
    Veo que el problema puede estar en cómo insertas los Subgrupos. Puedes probar a hacerlo como se comenta en la penúltima imagen de este post.
    Debes obtener un Grupo (llamemosle g), crear el subgrupo (llamemosle sg) e insertarlo de la siguiente manera:

    g.Subgrupos.Add(sg);
    SubmitChanges();

    Espero que te sirva.

  15. Benito Sepulveda

    Gracias de nuevo, por atender mi duda, bien despues de otra noche larga y bella. haciendo uso del metodo de prueba y error, di con la solucion a mi problema. Lo unico que tuve que hacer para que me generara los metodos insert,delete y update, fue indicarle un campo llave desde el diagarama de contexto. Una vez echo lo anterior reviso el codigo generado, y como arte de magia hay se encontraban los metodos que me hacian falta, para poder hacer las actualizaciones basicas en una tabla. Porque razón es asi?, aun no tengo la respuesta, pero en cunato la encuentre se los hago saber…..

    DE ANTEMANO TE GARADESCO TU INTERES EN DARME UNA EXPLICACION DEL PROBLEMA QUE SE PRESENTO, GRACIAS…

    Saludos!!!

  16. Andres Tabares

    Hola, la parte donde explicas como eliminar no me sale ami, to utilizo Visual Stuio 2008 y el metodo RemoveAll no lo encuentro por ninguna parte, solo me aparece el metodo, DeleteOnSubmit pero ese me saca un error cuando intento eliminar.

    Te agradecería cual info que me puedas regalar, saludos desde Medellín-Colombia

  17. Vio

    Hola Andres:

    Efectivamente el método RemoveAll se renombró y pasó a llamarse DeleteOnSubmit. Si te da un error ese método debes ver qué excepción te salta, seguramente ahí verás cuales son los datos que no puedes elminiar.
    Después de que consiguas eso, sólo te queda llamar al SubmitChanges para que los cambios surtan efecto.

    Espero que sirva.

  18. el Man

    muy buen aporte, pero me pregunto, se pueden pasar parametros?

    por ejemplo el tipico cmd.Parameters.addvaluewith(“@Campo”, tipoobjeto)

    gracias

  19. Javix

    Gracias hermanooo!!!!!!!!!!!!!! me salvaste la vida… excelente explicación. Un abrazo.

    Javix

  20. Felipe

    Hola!

    Tengo una tabla prestamos donde almaceno la informacion general del prestamo y una tabla Abonos donde esta cada cuota del prestamo (Se puede relacion con pedido y detalle pedido).
    Lo que pasa es que cuando intento ingresar un abono, me sale la siguiente Excepcion:

    System.InvalidCastException was caught
    Message=”La conversión especificada no es válida.”
    Source=”System.Data.Linq”
    StackTrace:
    en System.Data.Linq.IdentityManager.StandardIdentityManager.SingleKeyManager`2.TryCreateKeyFromValues(Object[] values, V& v).

    Estoy insertandolo usando la sintaxis prestamo.Abonos.add().

    Que peude ser el problema?

    Gracias

  21. ABEL

    Excelente y de fácil comprensión e implementación.
    Me esta funcionando bien todo tanto con On_ColumnName_Changing con OnValidate, sin embargo en el primer caso que la validación se realiza al momento de dar Enter ó Tabulador, no encuentro como regresar a la celda esta el dato inválido para corregirlo inmediatamente y no confundir al operador. podrás dar alguna idea al respecto.

    1. ABEL

      Cuando selecciono Datagridview al insertar origenes de datos en una WIndowsForm las clases parciales ne funcionan adecuadamente disparando los eventos On”NombreColumna”Changing donde tengo el código de validación, sin embargo cuando Selecciono “Detalles” no se disparan los eventos de tal manera que no me opera el código de validación; aunque el evento OnValidate() de la Clase acutlizada si me funciona bien; cual puede ser la razón???

      saludos.

  22. Alex

    Hola. Me he leído tu tutorial de arriba a abajo. Tus explicaciones me parecen muy buenas, y he comprendido fácilmente la mecánica de trabajo con linq.

    Pero tengo un problema que no he conseguido solucionar. Busque por múltiples paginas de internet y no lo doy solucionado.

    A la hora de hacer una inserción en una tabla con una sola relación es muy facil. Mi problema es que tengo una tabla de clientes, donde hay varios campos que son clave ajena de otra tabla llamada conjuntos. Es decir, en la tabla clientes, hay 3 campos(ingresos,estado civil,profesion) que están definidos en otra tabla llamada conjuntos.

    Como puedo hacer para hacer la inserción teniendo en cuenta los 3 campos a la vez??

    Gracias de antemano

  23. juan carlos

    ola quisiera aprender a desarrollar una base de datos Pero como puedo empezar a trabajr ya tengo instalado el visual studio 2005 y tambien acces 2007 pueden darme una explicacion como empezar a hacer la base de datos.
    aun que sea una sencilla para empezar gracias!!! se los agradesCO..

  24. Pingback: ASP.NET MVC Framework (Primera parte) « Thinking in .NET

  25. Tomás

    Muy bueno todo el blog, artículos muy intersantes. Tan sólo una cosa, el diseño, deberias ampliar el ancho para que las imágenes se viesen completas

  26. mayorga

    El tutorial me parece muy bueno y facil de entender.

    quisiera hacerles una cunsulta y es la siguiente
    estoy haciendo un programa usando linq en c# en la actualidad en un formulario registro una cerie de datos y la persona logeada es la que aparece como la persona que registra x datos pero me muestra el id y lo que necesito que me muestre es el nombre de esa parsona
    les agradeceria su ayuda

  27. emazzu

    Buenas noches, muy bueno tus artículos.

    Me estoy rompiendo la cabeza hace un tiempo para migrar una aplicación VB6. La tecnología la tengo definida, pero hay un tema que no se me ocurre nada.

    El Entity Framwork es muy lindo y comodo. Pero yo actualmente cuando con un modelo de datos que no esta definido, se modifica bastante, con lo cual tener el modelo no me sirve mucho.

    Lo que yo pretendo y para aprovechar todo el trabajo que tengo hecho de muchos años.

    Cada opción de mi menú, esta asociado a 1 vista y 4 store procedures, la vista para visualizar la info ya relacionada y los 4 store para realizar un CRUD.

    La aplicación, es dinámoca, es decir si 50 opciones del menú, son opciones estandard, las mismas saben con que vista de SQL server y sus 4 store procedure deben trabajar, Luego un form, dibuja la pantalla y sabe que store debe llamar para cada operación, el pasaje de parametros también es dinámico.

    Como podría yo migrar esto, utilizando las nuevas tecnologías pero manteniendo esta modelo que es muy eficiente y fácil de mantener.

    Por otro lado tengo mucho lógica de negocio del lado de server en los store. y como trabajo con el petroleo, la logica es compleja…

    Lo ideal seria si en run time, yo podría actualizar mi data model sin tener que abrir la aplicación, agregar tablas nuevas y volver a compilar.

    Por otro lado lo ideal seria si yo pudiera usar una clase, pero que el nombre de la clase lo tomo de una variable de texto, o si existiera una variable de tipo clase.

    Es un poco complejo lo que estoy preguntando, pero si se te ocurre algo, te lo agradezco.

    Gracias
    Eduardo

    1. Juanma

      Hola Eduardo:
      He estado trabajando en el sector del petróleo mucho tiempo y te puedo decir que la mejor solución que encontramos ha sido tener procedimientos almacenados (SPROC) para cada operación CRUD y sólo CRUD, es decir, nada de lógica de negocio en esos SPROC. La lógica que necesitábamos la teníamos en objetos de la capa de negocio que se encargaban de todo eso.
      La lógica de hacer Ventas Directas o Ventas en Ruta y la declaración a Aduanas por ejemplo, vimos que meterlo en un SPROC era demasiado complejo y no ganábamos nada, ya que el mantenimiento de esa lógica en la Base de datos se hacía muy compleja y difícil de testear.
      Si el modelo es muy dinámico te recomendaría la aproximación de Entity Framework Code-First , cosa que no estaba aún cuando estaba en el sector del petróleo y sin duda habría usado.
      La verdad es que actualizar el modelo sin tener que modificar código fuente, se me antoja demasiado complejo y costoso de implementar como para que sea rentable luego a la hora del mantenimiento.
      Yo no tiraría por ahí sinceramente.
      Resumiendo, mi recomendación es que te hagas la capa de acceso a datos simple (principio KISS) tan sólo con las operaciones CRUD, pero operaciones crud que sólo insertan, eliminan y modifican, nada más, eligiría EF, y en una capa de negocio montaría toda la lógica, ya que, si no me equivoco, seguro que en los sproc tienes cosas del estilo: Si hay que declarar a aduanas el aditivo del producto tiene que ir en partes por millon, si el destino del producto está a mas de 50 Km, la cisterna debe tener ADR y cosas así. Y no suele ser buena idea tener este tipo de cosas en la base de datos por que es más costoso de mantener y probar.

      Tuvimos que migrar un sistema que era como el que tu comentas y la opción más rentable que vimos fué esa. Pero ahora con el Entity Framework, hubiese sido más fácil aún.
      Espero que te sirva.

    2. Juanma

      También te recomiendo la lectura pausada y comprensiva del libro que Microsoft ha publicado sobre arquitectura N-Capas DDD para .NET 4.0, en http://msdn.microsoft.com/es-es/architecture/aa699358
      Esta guía me habría ayudado mucho en el sistema que hice para el sector del petroleo. Al final resultó ser un sistema que encajaba con lo expuesto en el libro, pero de haberlo tenido ántes, habría salido mucho mejor y rápido.
      Espero que te sirva.

  28. Salva

    Hola he leido este tutorial y esta muy bien, te doy la enhorabuena porque he aprendido mucho.. Xo tengo una duda y no encuentro nada por ningun sitio…

    No me inserta al hacer en insertOnSubmit.. O sea si inserta en el datacontext porque mientras no cierro la aplicación puedo ver los datos xo una vez cierro la aplicación voy a la bd y veo que los datos no han persistido. Que puede seer????

    Espero tu respuesta.
    Graciaas.

    1. Juanma Autor

      Hola Salva.
      Por lo que comentas parece que no estas llamando al SubmitChanges para persistir los datos.
      Espero que te sirva.

  29. Salva

    Gracias por tu atencion Juanma.

    Si que llamo al submitChanges() justo despues de la llamada al insertonsubmit pero ni con esas..
    Utilizo vs2008 express aunq no creo q eso sea no?? Ya no se q pensar…

    Un saludo.

  30. Salva

    Hola Juanma gracias por contestar.

    Si que utilizo el submitchanges() x eso me extraña que no me funcione. Utilizo visual studio 2008 express sera por esto… Ya nose que puede ser..

    Un saludo.

    1. Juanma Autor

      Hola Salva:
      Por lo que me cuentas, parece que no estás guardando los datos en la misma base de datos. Comprueba que en la base de datos que se te genera en el directorio /Bin al compilar sí se están guardando, sin embargo, en la que tendrás en tu proyecto no está. No se si me he explicado bien…

      1. Salva

        Juanma gracias tioo tenias razón en la bd de debug si que se estan guardando los datos. Lo que no entiendo es si cuando empiezo un proyecto añado una bd, que tengo que hacer luego, abrir la copia de la bd que se genera en debug para ver si se realizan bien los cambios? Porque al añadir un archivo externo no se situa en esa carpeta, sino en la carpeta exterior nose si me explico..

        Otra consulta, porque se duplica la bd??

        Gracias otra vez, un saludo.

        1. Juanma Autor

          De nada Salva.
          Pues es que es asi como funcionan las cosas :). ¿Razones? Por ejemplo, para que todo sea igual cada vez que le damos a F5 y no encontremos problemas de que lo que antes era de una forma, ahora no lo es.
          Yo para el entorno en el que te estas moviendo, si mi bola de cristal no me falla, es un entorno “simple”, lo hago a manita. Si necesito datos siempre iguales, los introduzco la primera vez y copio la base de datos de debug a la principal. Pero para algo mas elaborado dentro de ese escenario simple es poner en la cadena de conexión la ruta absoluta del disco duro.
          En entornos con SQL Server Express, SQL Server, Azure etc … lo mas normal es tener dos bases de datos una para debug y otra para producción …
          Cada maestrillo tiene su librillo y ese librillo se escribe haciendo:
          While(true)
          {
          forma.Hacer();
          if(TengoGanasYTiempo())
          {
          forma= BuscoOtraForma();
          }
          if(TengoGanasYTiempo())
          {
          forma.Mejorar();
          }
          }

          Me alegra haber sido de ayuda.

  31. danis

    Un poco desactualizado.

    Para insertar registros en vez de add()

    db.tabla.InsertOnSubmit(registro);
    //despues guardar los cambios
    db.SubmitChanges();

    1. Juanma Autor

      Efectivamente danis, este post y el tutorial es del año 2007, algo desactualizado.
      Lo actualizaré en cuanto pueda.
      Gracias por tu comentario 🙂

  32. Miguel

    Hola tengo una pregunta, en asp.net. si agrega varios .dbml solo me aparece uno. De tal manera que si agrego linqDataSource solo un archivo .dbml miro los otros no.

    Agradeceria sus comentarios.

Los comentarios están cerrados.