EF 4: Model Defined Functions

A lo largo de este post trataré de mostrar como consturir e invocar funciones definidas en el modelo, más conocidas por su nombre en lengua anglosajona como  ‘Model defined functions’. En algunas ocasiones, con el fin de facilitar las consultas sobre un contenedor de trabajo, resulta ideal poder definir una función directamente en nuestro modelo conceptual que sea capaz de realizar este trabajo y hacer mucho más sencillas y claras las consultas ejecutadas en LINQ To Entities.figura1

Con el fin de mostrar un ejemplo, suele ser la via más clara para enseñar el funcionamiento de casi cualquier cosa, partiremos de una entidad que llamaremos Producto y que tendrá la información que puede verse en la siguiente imagen.

Dentro de esta entidad, como podrá observar existe una propiedad llamada FechaLanzamiento a partir de la cual podríamos ver la fecha en la que un producto se ha puesto a la venta. Ahora imagine que muchas de sus consultas filtran el conjunto de resultados en función de lo años que este producto lleva en la calle. Este escenario podría ser válido para crear una función directamente en el modelo y poder hacer uso de ella directamente en nuestras consultas.

 

 

 

 

El primer paso para crear una función del modelo consiste en abrir este con cualquier editor XML, por ahora no podemos hacerlo en el diseñador, tendremos que seguir esperando para estos temas. Una vez abierto el fichero de modelo, edmx, con nuestro editor XML nos dirigiremos a la sección de nuestro espacio C, anotada por el comentario XML <!—CSDL content—>. Dentro de esta sección podremos crear una entrada como la siguiente:

<Function Name=”YearSince” ReturnType=”Edm.Int32″>
          <Parameter Type=”MamazonModel.Producto” Name=”producto”>
          </Parameter>
          <DefiningExpression>
            Year(CurrentDateTime())-Year(producto.FechaLanzamiento)
          </DefiningExpression>
</Function>

 

Con estas sencillas lineas, acabamos de crear nuestra función del modelo, en la que podrá observar como especificar los parámetros de entrada,salida y la definición propia de la función. Como podrá observar tanto los parametros de entrada como los de salida pueden ser tipos escalares, definidos siempre con el espacio de nombres Edm, como entidades o incluso colecciones de entidades, no cubierto en este ejemplo.

 

Una vez definida nuestra función del modelo, tendremos que ver como invocarla, para lo cual tendremos distintas alternativas. La primera consiste en definir un método en una clase personalizada que contenga la firma de estas funciones.Para ello crearemos una clase denominada ModelFunctions y agregaremos a esta la firma de nuestra función.

 

El único requisito a la hora de definir estas funciones está en el uso del atributo EdmFunction, el cual debe de contener el espacio de nombres y el propio nombre de la función ( son case sensitive ). Por supuesto, no es necesario realizar implementación ya que esta función será llevada al motor de base de datos correspondiente para que la resuelva.

Ahora que ya tenemos creada la función solamente nos queda probarla:

 

NOTA: Como curiosidad puede observar la clase SqlFunctions dentro del espacio de nombres System.Data.Objects.SqlClient y como esta tiene definida todas las funciones propias de Sql Server para que podamos hacer uso dentro de nuestras consultas de igual forma que nuestra función anterior.

 

La siguiente forma de ejecutar una función definida en el modelo es como un método propio de nuestro contenedor de trabajo, algo que puede aportarnos una via de localización y mantenimiento algo mejor en algunas ocasiones. Para hacer este trabajo, basta con que creeemos la firma del método anterior dentro de la clase parcial de nuetro contendor como vemos a continuación.

En este caso el cuerpo del método si debe de contener código indicando la proveedor de consultas como realizar la invocación, no se asuste querido lector, este mismo código le valdría para todas sus funciones, solamente debería sustituir el tipo genérico del metodo Execute por el tipo de retorno y el typeof del parámetro de entrada.

 

Espero que esta entrada les sea de interes,

 

saludos

Unai

Microsoft NLayer App – V.07 Compat. VS 2010 RTM

Desde hoy está disponible la versión V.07 de NLayerApp, aunque ya se incluyen diversas features nuevas quizás la más importante es la compatibilidad con Visual Studio 2010 RTM, entorno que seguro la mayoría ya tenéis instalada.

De entre las nuevas features, pueden destacarse las siguientes:

  • Visual Studio 2010 RTM compatibility

  • Silverlight 4.0 Client
    • Alpha version
    • Silverlight projects 100% Blend friendly
    • Proyectos de librería con los links a los elementos del dominio para poder incluir estos como referencias de proyectos, “el truquito”

 

  • IoC
    • Registro por código en vez de en ficheros de configuración.
    • Elementos de Cross cutting como dependency objects

 

  • Refactoring general

 

 

Saludos

Unai

WCF 4 Routing Service: Tablas de enrutado en función del To

En otro post relativamente reciente sobre el servicio de Routing de WCF se explicó como crear un servicio de router con las nuevas API’s incorporadas a WCF 4, System.ServiceModel.Routing. Recientemente, en un proyecto tenía que implementar una pasarela de intermediario que se basara en la dirección del servicio destino para realizar el enrutamiento, lógicamente, la primera aproximación consiste en usar uno de los filtros por defecto de los que disponemos, EndpointAddress ,el cual en teoría hace este trabajo por nosotros. Después de unas pruebas y de comprobar como el funcionamiento no era correto me decidí por revisar correctamente la documentación asociada y pude comprobar como este MessageFilter no incluye el segmento del host dentro de la comparación de las direcciones, es decir, para este filtro,la uri http://plainconceptsLondon/Servicio es exáctamente igual a http://plainconceptsMadrid/Servicio, técnicamente, este problema se podría resolver realizando la configuración del servicio por código  y estableciendo a este filtro la propiedad IncludeHostNameComparasion a true, pero perdía algo que necesitaba, la configuración del servicio en mi archivo de configuración. Llegado a este puntó me decidi por cambiar el tipo de filtro y basarme en una consulta XPath del sobre SOAP para verificar la cabecera To, dirección lógica del servicio, y con esto se solucionó el problema. Si alguno se encuentra con esta necesidad os dejo aquí la consulta XPath que permite realizar este trabajo, espero que algún dia os sea util…..

 

<routing>
  <namespaceTable>
    <add prefix="s" namespace="http://www.w3.org/2003/05/soap-envelope" />
    <add prefix="wsa" namespace="http://www.w3.org/2005/08/addressing" />
  </namespaceTable>
  <filters>
    <filter name="FiltroMadrid" filterType="XPath" filterData="/s:Envelope/s:Header/wsa:To=’net.tcp://plainconceptsMadrid/Servicio’"/>
    <filter name="FiltroLondres" filterType="XPath" filterData="/s:Envelope/s:Header/wsa:To=’net.tcp://plainconceptsLondon/Servicio’"/>
  </filters>
  <filterTables>
    <filterTable name="ROUTE_TABLE">
      <add filterName="FiltroMadrid" endpointName="Madrid" priority="1"/>
      <add filterName="FiltroLondres" endpointName="Londres" priority="1"/>
    </filterTable>
  </filterTables>
</routing>