De EF clásico a EF Core II — Configurar las entidades

Decía el otro día que me había puesto a ampliar mi mapeo de SAP Business One en Entity Framework clásico para hacerlo también en Entity Framework Core 7 y .Net 6.0.

Tuve que empezar creando unos métodos de extensión para tener la misma funcionalidad que en EF clásico.

Luego, dividí la clase del DbContext en tres archivos:

  1. Uno para la declaración de los DbSet.
  2. Otro con constructores y configuración para EF clásico.
  3. Y el tercero, para los constructores y configuración para EF Core.

El paso que me quedaba era revisar las clases de configuración de las entidades.

Sigue leyendo

De EF clásico a EF Core I — El Context

Tengo un mapeo de parte de la base de datos de SAP Business One en Entity Framework desde hace unos años que ya pasa de las 150 entidades. Hace no mucho modifiqué el tipo de proyecto de Visual Studio, del clásico de .Net Framework al nuevo estilo usado en .Net Core. El motivo era que este nuevo tipo permitía compilar con facilidad para distintas versiones de .Net. Este otoño, aprovechando esto, me planteé añadir .Net 6.0 y el nuevo EF Core 7 como plataformas de destino.

Ya comenté ayer los problemas que me encontré en las primeras pruebas. Solventados (o trampeados) éstos, pasé al plato principal.

Sigue leyendo

Microsoft y el mundo

De un tiempo a esta parte, me da la impresión de que los desarrolladores de Visual Studio (y .Net en general) tienen una visión del mundo bastante peculiar que se deja fuera a muchos de sus clientes. Algo que no veía en los tiempos de .Net Framework y la década del 2000 y primera mitad del 2010. La última vez que he pensado esto ha sido al empezar a usar Visual Studio 2022. Lo primero que me saltó fue esta advertencia:

NU1803    You are running the ‘restore’ operation with an ‘HTTP’ source. Non-HTTPS access will be removed in a future version. Consider migrating to an ‘HTTPS’ source.

Siguiendo el enlace de la advertencia, me encuentro con lo siguiente:

«El acceso no HTTPS se quitará en una versión futura.»

Toma ya. ¿En qué mundo viven estos? Busqué en el GitHub de NuGet el tema y lo encontré rápido, junto con las mismas quejas que podía escribir yo. Que, básicamente es:

Pero, alma de cántaro, ¿no te has parado a pensar que los que usamos servidores NuGet con http lo hacemos porque son servidores locales, montados para el grupo de desarrollo de la empresa? Yo lo hago con NuGet Server y ahora lo tengo en un servidor virtualizado que se utiliza para otras cosas, con los archivos alojados en un servidor de archivos aparte. Es muy cómodo para compartir nuestras bibliotecas comunes entre los distintos proyectos. Y esta decisión nos va a complicar la vida una barbaridad. ¿Qué hacemos? ¿Https con certificado autofirmado? Esto dará problemas por otro lado, seguro. ¿Pagar un certificado para un ordenador que ahora está (física o virtualmente) en un rincón, sin acceso a internet? ¿Y el tiempo de investigación y configuración de todo el tinglado?

Me queda bastante claro que a los que se les ha ocurrido la maravillosa idea no han trabajado mucho en pequeñas y medianas empresas.

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.