Raw SQL Query en EF Core

Cuando, en 2016, empecé a trastear con Entity Framework, tuve que elegir entre la versión clásica o la nueva versión «Core». En la documentación te indicaba que, para proyectos nuevos, lo mejor era elegir EF Core, que era lo que se iba a desarrollar a futuro. Pero, ¡ay!, la versión entonces disponible no soportaba vistas y yo las necesitaba como el comer. No me quedó otra que empezar con EF clásico y dejar EF Core para más adelante.

El año pasado, aprovechando que ya teníamos una versión para .Net Standard de EF clásico, modifiqué mis proyectos con EF para pasarlos del tipo .Net Framework al tipo actual .Net Core, en donde se puede tener varios frameworks de destino. Así, los compilé para .Net Framework y .Net Core.

Este otoño, preparando mi salto a .Net Core del año que viene (posiblemente con Blazor), se me ha ocurrido también compilar mis proyectos de EF tanto para la versión clásica como para la nueva EF 7.0, recién salida del horno. En parte también porque en la documentación decía más o menos que los desarrolladores de EF clásico ya no teníamos excusa. Bien, me dije, veamos si es así. La madre del cordero es el mapeo parcial de la base de datos de SAP Business One, que es sólo relacional en parte. Más de 150 entidades (hasta la fecha), entre tablas y vistas.

Lo primero fue revisar qué usaba en EF clásico y cómo se hacía en EF Core, así que monté un prototipo y mapeé un par de tablas y vistas, con sus relaciones. Sin problemas.

Luego llegó el turno de las consultas SQL a pelo y ahí, ¡ah, amigo!, ahí se complicó todo.

En EF clásico teníamos una opción maravillosa que era:

public DbRawSqlQuery<TElement> SqlQuery<TElement>(string sql, params object[] parameters)

Sigue leyendo

Cliente WCF asíncrono

Volviendo con lo del otro día, se me ocurrió ampliar los contratos de servicio para definir métodos asíncronos, de cara a trabajar con .Net Core este invierno. Quería hacerlo sólo en los clientes, para no tocar toda la parte de los servicios, que ya está creada, así que jugué con las compilaciones condicionales:

<ServiceContract([Namespace]:="http://CdA.Cromo.Services", SessionMode:=SessionMode.NotAllowed)>
Public Interface ILotesService

    <OperationContract()>
    <FaultContract(GetType(ServiceFault))>
    Function Modificar(Lote As LoteSAP, InfoConfig As InfoConfiguracion) As Mensaje

#If NET5_0_OR_GREATER Then
    <OperationContract()>
    Function ModificarAsync(Lote As LoteSAP, InfoConfig As InfoConfiguracion) As Task(Of Mensaje)
#End If

End Interface

Sigue leyendo

Vi la luz

El otro día modifiqué un servicio WCF y me tocó pegarme, a continuación, con la aplicación cliente. Siguiendo el manual, en su día utilicé «Agregar referencia de servicio» de Visual Studio. Actualizar luego es siempre un dolor de cabeza. Las clases de datos y las enumeraciones utilizadas por el servicio las comparto vía NuGet y las tiene el cliente. En teoría, le puedes indicar al asistente que utilice esos ensamblados en lugar de generar de nuevo todo, pero al actualizar… raro es que funcione a la primera.

Entonces encontré este viejo artículo y, aún mejor, esta explicación con ejemplos de ese artículo. Cómo crear a mano los proxy de cliente. Vaya cosa simple. Vaya forma de hacer el canelo todos estos años.

Así que paré todo y dediqué dos días a llevarme las interfaces de los contratos de servicio a otro proyecto, crear un tercero con los proxy de cliente, empaquetarlos y distribuirlos por NuGet. Los agregué al cliente, eliminé el código generado por Visual Studio y lo sustituí por las nuevas clases y listo.

De paso, compilé los nuevos proyectos para .Net Core y lo probé con una aplicación Visual Basic. Iba genial, lo que es un alivio porque el Agregar referencia de servicio en proyectos de .Net Core sólo aparece para C#.

Me gusta cuando aprendo algo nuevo de una tecnología que llevo usando años. Por una parte me da rabia (es algo que debería haber sabido antes, pienso), por otra me muestra todo lo que me queda por mejorar en las áreas que controlo.

No se puede acceder a la ventana de Firmas en Outlook 365

Llevo casi dos días perdidos con una tontería. Estamos estos días migrando a Office 365 (ahora Microsoft 365) en la empresa. Dejando de lado el incorporar el histórico de los correos, actualmente bonitos perfiles locales de Thunderbird de obscenidades de gigas, todo marcha bien. Hasta que ayer, tras una instalación con algunos problemas en uno de los portátiles de los comerciales, me encontré con un problema pintoresco en Outlook: la ventana de las firmas no aparecía.

El botón que no funciona. En realidad, no funcionaba ningún botón de ese panel.


Sigue leyendo

SAP Business One B1WS: editar oferta de ventas II

Hace poco tuve que modificar unos documentos de márketing (ofertas y pedidos de ventas) vía B1WS/Di Server. Hasta el momento, sólo había creado documentos de SAP y supuse que la edición seguiría el mismo proceso que con los UDO, con los que tengo bastante más manejo. Básicamente, el proceso con un UDO es:

  • Obtengo el objeto sin modificar vía B1WS.
  • Modifico los campos de la cabecera con los datos nuevos.
  • Con el array de líneas, agrego las nuevas, elimino las que hay que borrar y modifico los campos de las que hay que modificar.
  • Le vuelvo a enviar todo a SAP.

Con las líneas, que es lo que me importa aquí, el proceso es como éste, siendo Origen el objeto con los cambios que envía la capa de lógica de negocio y Destino, el objeto sin modificar recuperado de SAP. Como pueden observar, hay una propiedad en las filas origen que me indica qué debo hacer con ellas:

Sigue leyendo

Microsoft da la espalda a VB.Net

El 11 de marzo se publicó una entrada en el blog de Visual Basic de Microsoft, la primera entrada desde noviembre de 2018 en un blog que había estado bastante surtido hasta octubre de 2017. El título de la entrada es Visual Basic support planned for .NET 5.0. Es una entrada sin firma (aparece .NET Team como autor, mientras que las anteriores, salvo pocas excepciones, iban firmadas por sus autores) y viene a ser la sentencia de muerte de Visual Basic por parte de Microsoft. La entrada dice que van a hacer Visual Basic compatible con .NET 5.0 (la siguiente versión de la rama de .NET Core que va ahora por la 3.1). Ésa es la zanahoria que nos dan, después de meses (por no decir años) de sentirnos ninguneados y olvidados frente a C#.

El palo viene luego: Going forward, we do not plan to evolve Visual Basic as a language. No van a seguir desarrollando Visual Basic. No van a incluir las futuras mejoras de .NET Core. No es que me sorprenda. Llevábamos bastante tiempo con Visual Basic desaparecido del mapa y no tenemos la suerte de que haya un pequeño grupo de desarrollo que pueda ir a lo suyo, como pasa con F#. Tampoco es novedad que Microsoft deje en la estacada a sus clientes. Pasó con VisualFox Pro, por ejemplo. O con Windows Phone. O con las aplicaciones de tienda de Windows 8. Otrora una de las joyas de la corona de Microsoft, hoy Visual Basic es considerado aburrido, viejo y obsoleto por el equipo de desarrollo de .NET y el mensaje es claro: migrad a C#, dinosaurios.

Leí la noticia con resignación. Ya bastante me cuesta tener que dar explicaciones por usar Visual Basic cada vez que lo menciono. Hasta mis compañeros de departamento se han pasado a C# en el último proyecto. El día que tenga que pasarme a C# para ganarme los garbanzos, pues lo haré. O a lo que sea. Programar es mi trabajo. No tiene por qué ser mi afición.

Sin embargo, ayer leí también la contestación de Anthony D. Green, 5 entradas donde se explaya a gusto que ustedes pueden leer aquí: la primera, la segunda, la tercera, la cuarta y la quinta, y que agradezco de corazón. Me ha recordado que Visual Basic es un lenguaje de código abierto desde 2014 que irá donde su comunidad decida que vaya. Me ha explicado algo que debía ser totalmente evidente, que desarrolladores ajenos a un lenguaje de programación no deberían condicionar el futuro de ese lenguaje; que no tengo por qué dar explicaciones ni disculparme por usar las herramientas que uso y porque me guste el lenguaje de programación que me gusta. Cuenta anécdotas y experiencias vividas en su tiempo trabajando en Microsoft y termina con una carta abierta a Nadella.

La lectura ha cambiado mi resignación por cabreo y rebeldía. Quiero seguir programando en VB.Net. Quiero que mi trabajo siga siendo una afición. Quiero disfrutar mucho más de su sintaxis, de imprimirme el código y leerlo en voz alta y del placer de programar, en definitiva. Y si tengo que dejarlo, quizás pueda aprovechar y quitarme esa espinita clavada que es mi otro amor, Pascal, y aprender de una vez Delphi.

SAP Business One B1WS: editar oferta de ventas

Una breve entrada sobre SAP Business One:

Intento editar una oferta de ventas vía B1WS. Al obtener la misma mediante el consabido método de GetByParams, me da error al procesar el xml. Un error de conversión de algún campo de fecha/hora. Empezamos bien.

Ataco directamente el DiServer para conseguir la oferta en bruto, en texto plano, y busco los campos fecha/hora a ver cuál es el causante. Verán, SAP B1 guarda el tiempo como entero corto, en forma HHMM: 935, 1250, 1800… que son devueltos por correctamente formateados como 9:35:00, etc. Pero hay un campo de la oferta de ventas (y del resto de documentos de márketing), UpdateTS, que guarda HHMMSS: 125015. Y me encuentro con que el DiServer lo devuelve formateado, bajo el nombre de UpdateTime de la forma 1250:15:00. Ferpecto:

El maldito


Imagino que al que hizo la función que formatea los campos de hora para los servicios del DiServer le dirían que todos iban en forma HHMM o que los campos UpdateTS de los documentos de márketing son posteriores a dicha función y nadie se acordó de cambiarla/comprobarla.

Como el campo es irrelevante en la actualización (no necesito su valor y es algo que rellena el propio SAP), la solución es simple: editar manualmente el wsdl generado, buscar el campo de marras y cambiar el tipo de time a string.

Imagino que para la 9.3 lo habrán corregido, pero en la 9.2 parche 10, así están las cosas.

2020-04-14: pues no, no lo han actualizado. Entre el parche 10 de la 9.2 y el parche 13 de la 9.3 me he encontrado con un montón de cambios en la estructura de los documentos de márketing expuestos por Di Api/Di Server, pero el maldito UpdateTime sigue dando guerra.

EF: usando campos no mapeados en consultas

Tengo un vicio confesable (creo) en programación: las enumeraciones. Siempre que puedo, las uso. Cuando, aprovechando unas semanas de verano con poca carga de trabajo, intenté mapear parte de la base de datos de SAP Business One con Entity Framework (lo que tuvo su complicación, que no es lo que se dice muy relacional), me pregunté si podía utilizar enumeraciones para los campos de estado de documentos, que tan pronto pueden ser O/C como P/R/L/C o cualquier otra forma super-intuitiva.

No me refiero sólo a tener una propiedad de sólo lectura no mapeada para obtener un valor comprensible con los datos ya cargados, o sea, esto:

    <Column("Status")>
    Public Property EstadoSAP As String
    <NotMapped>
    Public ReadOnly Property EstadoEnumerado As EWORSAPStatus
        Get
            Return Convierteme(Me.EstadoSAP)
        End Get
    End Property

Sigue leyendo

ASP MVC: autenticación por formularios

Este año pasado he dado mis primeros pasitos con ASP MVC, siendo también mi primera incursión en programación web. Lo primero que a lo que tuve que enfrentarme (tras pasar por varios tutoriales y leerme un par de libros) fue la gestión del usuario. La aplicación MVC compartía componentes con otras (WCF y Windows Forms) y la gestión del usuario y sus permisos se hacía ya con una implementación de IPrincipal. Una búsqueda por Internet me llevó a que debía usar para esto la vieja autenticación por formularios.

Para ello, primero debía crear mi nuevo proyecto MVC sin autenticación. Creé, a continuación, otro con autenticación para coger todo lo que pudiera del código y ahorrarme trabajo: casi todo el diseño e la vista de login, la vista parcial de _LoginPartial, su implementación en la cabecera… Todo lo que me pudiera suponer un ahorro de trabajo.

Sigue leyendo

Dos semanas con W10 Mobile

Así, sin darme cuenta, ya llevo dos semanas con W10 Mobile. El resultado ha sido interesante y agradable, hasta el punto que, de momento, no veo razones para volverme a Windows Phone 8.1. Bueno, siendo sincero, haberlas haylas, pero las razones para quedarme en W10 lo equilibran.

A saber:

  • La batería me dura lo mismo o más. Había leído muchos comentarios avisando de lo contrario y esto ha sido toda una sorpresa. En modo nocturno me gasta menos que WP8, así que llego a los dos días completos entre cargas o más con un uso ligero y día y medio con un uso normal (normal para mí, esto es, algo de mensajería, mucha recepción de correos, algo de navegación vía wi-fi y echar algún vicio).
  • Sin quejas sobre la cámara, otro tema habitual. No era capaz de sacar una foto que no apareciera movida antes y sigo sin ser capaz de hacerlo ahora.
  • Facebook Messenger es una patata, pesado en abrir, voraz de recursos si se queda abierto y sin posibilidad de notificaciones en la pantalla de bloqueo.
  • Me estoy pegando con Cortana y con el teclado más que antes. No sé si es por el reseteo del teléfono o porque es inferior a WP8, la verdad.
  • Y esto probando el modo de cuatro columnas, que para la pantalla de un Lumia 640XL es una muy buena opción.

Y otras cositas de aquí y de allá. Seguimos con las quejas de la falta de aplicaciones, pero, la verdad, salvo que necesitemos algo en las notificaciones o información extra en la Tile, sigo pensando que es mejor tirar de web. Y el futuro parece ahora que no pasa por las tiendas de aplicaciones y las app limitadas y que podemos usar sólo cuando el dueño quiera, sino en los bots (tampoco lo veo, la verdad).