Herramientas de usuario

Herramientas del sitio


fw:othersnet:dlinq

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
fw:othersnet:dlinq [2009/03/22 17:39]
alfred
fw:othersnet:dlinq [2020/05/09 09:25] (actual)
Línea 1: Línea 1:
 ====== DLINQ ====== ====== DLINQ ======
 +O //Linq to SQL//. \\ \\ 
 +
 +===== El modelo de datos =====
 +El modelo de base de datos se muestra de forma visual en Visual Studio 2008 a partir de un archivo .dbml, puede ser editado mediante la Toolbox o arrastrando los elementos desde el administrador de servidores. \\ \\ 
 +
 +
 +
 +
 +
 +
 +==== La clase DataContext ====
 +Al modelar la DB en el .dbml y guardar se crea una clase DataContext y clases relacionadas a las entidades y relaciones que hemos indicado. La clase DataContext es que representará la DB con propiedades correspondientes a las tablas y métodos a los procedimientos almacenados. \\ 
 +
 +Por ejemplo, imaginemos que mapeamos una DB con productos y categorías en el siguiente DataContext:​
 +<code csharp>
 +NorthwindDataContext db = new NorthwindDataContext();​
 +</​code>​
 +Podríamos hacer la siguiente consulta:
 +<code csharp>
 +var products = from p in db.Products
 + where p.Category.CategoryName == "​Beverage"​
 + select p;
 +</​code>​
 +
 +=== Updates ===
 +O la siguiente actualización:​
 +<code csharp>
 +NorthwindDataContext db = new NorthwindDataContext ();
 +Product product = db.Products.Single (p => p.ProductName == "Toy 1");
 +product.UnitPrice = 99;
 +product.UnitsInStock = 5;
 +db.submitChanges();​
 +</​code>​
 +
 +=== Inserts ===
 + 
 +O agregar algún producto:
 +<code csharp>
 +Product prod = new Product ();
 +prod.ProductName = "​Toy";​
 +db.Products.InsertOnSubmit (prod);
 +db.SubmitChanges()
 +</​code>​
 +<​del>''​db.Products.Add (prod);''</​del>​ <- Esto se podía hacer en anteriores versiones.
 +
 +=== Deletes ===
 +O borrarlo:
 +<code csharp>
 +var toyProducts = from p in db.Products
 + where p.ProductName.Contains("​Toy"​)
 + select p;
 +db.Products.RemoveAll (toyProducts);​
 +db.submitChanges();​
 +</​code>​
 +
 +=== Procedimientos almacenados ===
 +<code csharp>
 +var products = db.GetProductsByCategory (5);
 +</​code>​
 +
 +=== Paginación ===
 +
 +Coger productos de forma paginada:
 +<code csharp>
 +var products = (from p in db.Products
 + where p.Category.CategoryName.StartsWith("​C"​)
 + select p).Skip(200).Take(10);​
 +</​code>​
 +
 +
 +
 +==== Clases Entidad ====
 +
 +Las "​Clases Entidad"​ (Entity Classes) mapean tablas y sus instancias son denominadas "​entidades",​ las filas de la tabla. Las propiedades serían las columnas de dicha tabla. Podremos cambiar los nombres de dichas clases o de sus propiedades desde el mismo editor.
 +
 +Las propiedades de las clases entidad tienen una propiedad denominada "Delay Loaded"​ cuando está a true hace que no se utilice esta propiedad hasta que no vaya a usarse (por ejemplo para que no nos vengan imágenes grandes cada vez que hacermos una consulta).
 +
 +Si en el diseñador arrastramos procedimientos almacenados estos pasarán a ser métodos del DataContext. Si lo arrastramos sobre la entidad Product, esta devolverá un IEnumerable<​Product>​.
 +
 +Si utilizasemos procedimientos almacenados para hacer Delete/​Insert/​Update sobre alguna tabla podemos indicarlo en las propiedades Delete, Insert o Update de una clase entidad.
 +
 +
 +===== Paginación =====
 +
 +La paginación la hacemos utilizando el ''​Skip''​ y el ''​Take'',​ además, como la consulta no se realiza hasta que no se la llama podríamos hacer algo así:
 +<code csharp>
 +void BindProducts (int startRow) {
 + NorthwindDataContext db = new NorthwindDatacontext();​
 + var products = from p in db.Products
 + where p.OrderDetails.Count > 2
 + select new
 + {
 + Id = p.ProductID,​
 + Name = p.ProductName,​
 + NumOrders = p.OrderDetails.Count,​
 + Revenue = p.OrderDetails.Sum (o => o.UnitPrice * o.Quantity)
 + };
 + GridView1.DataSource = products.Skip(startRow).Take(10);​
 + gridView1.DataBind();​
 +}
 +</​code>​
  
 ===== Validación ===== ===== Validación =====
 +
 +Para realizar validaciones sólo tendremos que crear una clase parcial y agregar un método parcial denominado On<​campo>​Changing:​
 +<code csharp>
 +public partial class Customer {
 + partial void OnPhoneChanging(string value) {
 + Regex phoneNumber = new Regex (@"​^[2-9]\d{2}"​);​
 + if (phoneNumber.IsMatch (value) == false) {
 + throw new Exception("​Not a valid phone number"​);​
 + }
 + }
 +}
 +</​code>​
 +Ahora **no** se podrá hacer algo así:
 +<code csharp>
 +Customer myCustomer = northwind.Customers.Single(c => c.CompanyName == "​Beverages"​);​
 +myCustomer.Phone = "​asfkjasklfjaslkf";​
 +northwind.SubmitChanges();​
 +</​code>​
  
 Podemos agregar reglas de validación a nivel de entidad, es decir, no sólo para las propiedades sino para la tabla en sí, y poder validar así datos que estén relacionados. Podemos agregar reglas de validación a nivel de entidad, es decir, no sólo para las propiedades sino para la tabla en sí, y poder validar así datos que estén relacionados.
Línea 50: Línea 169:
 } }
 </​code>​ </​code>​
 +
 +
  
 ==== ExecuteQuery ==== ==== ExecuteQuery ====
Línea 58: Línea 179:
     return ExecuteQuery<​Product>​(@"​select * from products where CategoryID = {0}", categoryID);​     return ExecuteQuery<​Product>​(@"​select * from products where CategoryID = {0}", categoryID);​
   }   }
 +}
 +</​code>​
 +Cuando tenemos datos personalizados,​ es decir una clase como la siguiente:
 +<code csharp>
 +public class ProductSummary {
 +  public int ProductID { get; set; }
 +  public string ProductName { get; set; }
 +  public Decimal? UnitPrice { get; set; }
 +}
 +</​code>​
 +El retorno debería ser algo así:
 +<code csharp>
 +public IEnumerable<​ProductSummary>​ GetProductSummariesByCategory (int id) {
 +  return ExecuteQuery<​ProductSummary>​(@"​select ProductID, ProductName,​ UnitPrice from products where CategoryID = {0}", categoryID);​
 } }
 </​code>​ </​code>​
  
-===== Aplicaciones utilizando DLINQ ===== +==== ExecuteCommand ​==== 
- +Es el método que tendremos que utilizar para realizar acciones de borrado, inserción o actualización. \\  
- +Por ejemplo, para sobreescribir el borrado de la clase Product haríamos:​ 
 +<code csharp>​ 
 +public partial class NOrthwindDatacontext { 
 +  partial void DeleteProduct (Product instance) { 
 +    ExecuteCommand ("​delete from Products where ProductId = {0}", instance.ProductID);​ 
 +  } 
 +
 +</​code>​ 
 +Esto se utilizaría de la siguiente forma: 
 +<code csharp>​ 
 +NorthwindDataContext db = new NorthwindDataContext (); 
 +Product product = db.Products.Single(p=>​p.ProductName ​== "My product"​);​ 
 +db.Products.Remove (product); 
 +db.SubmitChanges (); 
 +</​code>​
  
 +===== Procedimientos almacenados =====
 +Podemos mapear los procedimientos almacenados como métodos en la clase DataContexts arrastrandolos al diseñador. Si el método devolviese una secuencia de un elemento de una tabla, por ejemplo registros de Product, lo que haríamos sería arrastrarlo sobre la tabla. \\ \\ 
 +Ahora podemos asignar el resultado de un procedimiento al DataSource de una tabla:
 +<code csharp>
 +GridView.DataSource = Northwind.CustOrderHist ("​Alfred"​);​
 +GridView.DataBind();​
 +</​code>​
 +Si el procedimiento pudiese devolver tanto campos de una tabla como de otra distinta tendremos que configurar el método para que devuelva una instancia de ''​IMultipleResult''​. \\ \\ 
 +Si quisieramos utilizar un procedimiento almacenado para hacer un Insert, Delete o Update de una tabla sólo tenemos que ir, en el diseñador, a dicha tabla y sobre el método deseado (en las propiedades) indicar que se hará de forma personalizada indicando entonces el procedimiento almacenado deseado.
  
 +===== Aplicaciones utilizando DLINQ =====
  
  
Línea 76: Línea 234:
 El control ''<​asp:​LinqDataSource>''​ enlaza modelos de datos LINQ. Utilizandolo no tenemos que definir métodos de consulta, inserción, actualización o borrado, sino que añadiendolo y definiendo las entidades con las que queremos que trabaje podremos enlazar cualquier control ASP.NET para que trabaje con él. Para ello, una vez tenemos el modelo y el entorno diseñados sólo tenemos que indicar en la propiedad DataSource del control que deseemos enlazar el modelo que queramos utilizar. El control ''<​asp:​LinqDataSource>''​ enlaza modelos de datos LINQ. Utilizandolo no tenemos que definir métodos de consulta, inserción, actualización o borrado, sino que añadiendolo y definiendo las entidades con las que queremos que trabaje podremos enlazar cualquier control ASP.NET para que trabaje con él. Para ello, una vez tenemos el modelo y el entorno diseñados sólo tenemos que indicar en la propiedad DataSource del control que deseemos enlazar el modelo que queramos utilizar.
  
-=== Asignándolo a un GridView ===+=== Asignándolo a un GridView ​de ASP.NET ​===
   - Definir el modelo.   - Definir el modelo.
   - Crear el GridView.   - Crear el GridView.
Línea 82: Línea 240:
   - Escoger un modelo Linq (el diseñador nos mostrará los objetos DataContext que existan en nuestro proyecto).   - Escoger un modelo Linq (el diseñador nos mostrará los objetos DataContext que existan en nuestro proyecto).
   - Seleccionar tabla y campos que recogerá. En opciones avanzadas podemos también indicar si está habilitado para realizar operaciones de inserción, edición o eliminación.   - Seleccionar tabla y campos que recogerá. En opciones avanzadas podemos también indicar si está habilitado para realizar operaciones de inserción, edición o eliminación.
-  - Ahora, en las opciones del GridView, podemos escoger si habilitamos la paginación,​ el ordenado, el bororado...+  - Ahora, en las opciones del GridView, podemos escoger si habilitamos la paginación,​ el ordenado, el borrado...
 Esto generará un código con las columnas que se incluyen en el grid como ''<​asp:​BoundField>'',​ y mediante sus propiedades podremos acceder al texto de cabecera y demás... Si alguna no quisieramos mostrarla la borraríamos desde el código o desde el mismo editor. \\ \\  Esto generará un código con las columnas que se incluyen en el grid como ''<​asp:​BoundField>'',​ y mediante sus propiedades podremos acceder al texto de cabecera y demás... Si alguna no quisieramos mostrarla la borraríamos desde el código o desde el mismo editor. \\ \\ 
 Podemos **cambiar el campo de una tabla**, por ejemplo uno que tenga identificadores por el nombre del registro correspondiente,​ cambiando el ''<​asp:​BoundField>''​ por un ''<​asp:​TemplateField>''​. Tipo lo siguiente: Podemos **cambiar el campo de una tabla**, por ejemplo uno que tenga identificadores por el nombre del registro correspondiente,​ cambiando el ''<​asp:​BoundField>''​ por un ''<​asp:​TemplateField>''​. Tipo lo siguiente:
Línea 139: Línea 297:
 <code xml> <code xml>
 <​span><​asp:​Literal ID="​Literal1"​ runat="​server"></​asp:​Literal></​span>​ <​span><​asp:​Literal ID="​Literal1"​ runat="​server"></​asp:​Literal></​span>​
 +</​code>​
 +=== Evento Selecting ===
 +Podemos implementar el evento "​Selecting"​ del objeto ''​LinqDataSource''​ esto nos servirá para poder escribir el código que queramos y obtener los datos; todo lo que tenemos que hacer es asignar la propiedad ''​Result''​ al objeto ''​LinqDataSourceSelectEventArgs''​. ​
 +<code csharp>
 +protected void ProductDataSource_Selecting (object sender, LinqDataSourceSelectEventArgs e) {
 +  NorthwindDataContext northwind = new NorthwindDataContext ();
 +  string[] countries = new string[] {"​UK",​ "​France",​ "​Germany"​};​
 +  var products = from p in northwind.Products
 +    where countries.Contains(p.Supplier.Country)
 +    select p;
 +  e.Result = products;
 +}
 </​code>​ </​code>​
  
-===== Notas =====+Por ejemplo, podemos modificar el evento ''​Selecting''​ para montar un GridView que muestre un subconjunto de información de Product. ​
  
 +<code csharp>
 +protected void ProductDataSource_Selecting (object sender, LinqDataSoruceSelectEventArgs e) {
 +  NorthwindDataContext northwind = new NorthwindDataContext ();
 +  var products = from p in northwind.Products
 +    where p.Category.CategoryName.StartsWith("​C"​)
 +    select new {
 +      p.ProductID,​ p.ProductName,​ p.UnitPrice,​
 +      NumOrders = p.OrderDetails.Count,​
 +      Revenue = p.OrderDetails.Sum (o=>​o.Quantity * o.UnitPrice)
 +    };
 +  e.Result = products;
 +}
 +</​code>​
 +
 +Lo malo es que no funcionará la edición. Esto es debido a que estamos haciendo una montaje personalizado en el método Selecting, y el LINQDataSource no tiene forma de saber cómo actualizar la entidad. Si queremos añadir soporte para la edición podríamos crear un control ObjectDataSource (al que le agregaríamos un método ''​Update''​ personalizado para contorlarlos),​ o hacer que el usuario navegue a una nueva página para hacer la actualización - y mostrar un ''​DetailsView''​ o ''​FormView''​ enlazado a la entidad Producto para la edición (y no intentar hacerlo en el grid).
 +
 +
 +
 +
 +
 +===== Notas =====
 +  * Cuando estás creando un fichero .dbml a partir de unas tablas sin claves primarias definidas, si quieres que se generen listas de las clases agregadas tendrás que indicar tú las claves primarias a mano.
 +  * No es aconsejable poner directamente el código de las clases parciales en el archivo derivado del .dbml, más vale ponerlo en archivos a parte.
 +  * Cuando queremos que el ''​DataContext''​ se conecte en tiempo de ejecución a otra cadena de conexión no es aconsejable editar el fichero ''​.designer.cs''​ (donde se genera el código) ya que este cambiará al editar el .dbml. Lo mejor es agregar una clase parcial y escribir el constructor por defecto, entonces este ya no se generará y en los otros controles se utilizará el creado. También sería correcto cambiar la propiedad ''​ApplicationSettings''​ de la conexión del dbml poniendola a false.
 +<code csharp>
 +partial class databaseDataContext
 +{
 +  public databaseDataContext()
 +    : base(codegest.Configuration.getConnectionString().ConnectionString,​ mappingSource)
 +    {
 +    }
 +}
 +</​code>​
 +  * Podemos cambiar el namespace de donde se generará el DataContext a partir de la propiedad ''​Context namespace''​ del .dbml y el namespace de donde se generarán las clases de las tablas generadas con la propiedad ''​Entity Namespace''​.
 +  * Al trabajar con SQL Servers "​antiguos",​ al actualizar texto este se intenta comparar con el que había anteriormente y acaba por lanzar una excepción debido a que no lo permiten. La solución es indicar ''​UpdateCheck = UpdateCheck.Never''​.
fw/othersnet/dlinq.1237743575.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)