MyDinaup
El paquete NuGet que Dinaup genera con una clase por sección, informe y documento dinámico de tu esquema.
MyDinaup es la biblioteca .NET que Dinaup genera leyendo tu esquema: cada sección, informe y documento dinámico de tu licencia se convierte en una clase con los nombres reales de tus campos. El SDK Dinaup se conecta a la API; MyDinaup añade las clases de tu modelo.
Antes de empezar
- El paquete NuGet
Dinaup, paranet10.0. Ver SDK .NET. - Una clave API de tu licencia. Ver Claves API.
- Tu paquete
{Empresa}.MyDinaup. Los ejemplos de esta página salen deDemoUp.MyDinaup, un modelo de ejemplo que depende deDinaupy compila paranet10.0.
dotnet add package Dinaup
dotnet add package DemoUp.MyDinaupClaves internas frente a constantes
Sin MyDinaup identificas cada campo por su clave interna:
// Sin MyDinaup: claves de columna a pelo
var data = new Dictionary<string, string>
{
{ "pr_30655031", "SC-4471" },
{ "nombre", "Almacén central" }
};Esas claves (pr_30655031, pr_506847515) no se autocompletan y un error tipográfico solo aparece cuando la petición falla. MyDinaup las expone como constantes con el nombre del campo:
// Con MyDinaup: nombres de tu esquema
using static DemoUp.MyDinaup.SectionsD;
var data = new Dictionary<string, string>
{
{ AlmacenesD.AlmacenesES.SendcloudID, "SC-4471" },
{ AlmacenesD.AlmacenesES.TextoPrincipal, "Almacén central" }
};SectionsD, Reports y DynamicDocuments son clases parciales, no espacios de nombres: se importan con using static. Un using sin static sobre ellas no compila.
using Dinaup;
using static DemoUp.MyDinaup.SectionsD;
using static DemoUp.MyDinaup.Reports.FuncionalidadD;Qué contiene
| Carpeta | Clase generada | Hereda de |
|---|---|---|
Secciones/ | SectionsD.{Seccion}D, con {Seccion}ES y {Seccion}C anidadas | DinaupRowBase (la fila C) |
Informes/{Categoria}/ | Reports.{Categoria}D.{Informe}C con su fila {Informe}_RowC | DinaupReportBase<RowC> |
DocDinamicos/{Categoria}/ | DynamicDocuments.{Categoria}D.{Documento}C | DinaupDynamicDocumentBase |
Enumeraciones.vb | Los tipos de lista de tu esquema como enum | |
Constants.vb | Constants.{Catalogo}.{Valor} como DinaupBasicInformation, solo para las secciones de catálogo y hasta 50 valores por sección | |
PGSync/ | PGSync.{Informe}Model, solo en licencias con PG Sync | Dinaup.Database.Definitions.BaseModelConverter |
El código generado es VB.NET con OptionStrict Off. Lo consumes igual desde C#.
Secciones
Una sección es una tabla de tu licencia: Almacenes, Entidades, Ventas. Por cada una, MyDinaup genera dentro de SectionsD una clase {Seccion}D con dos clases anidadas y dos métodos de lectura:
| Miembro | Qué es |
|---|---|
{Seccion}D._SectionID | El GUID de la sección como string. |
{Seccion}D._SectionIDGUID | El mismo GUID como Guid. Es el que piden RunWriteOperationAsync y RowsGetAsync. |
{Seccion}D.GetRowByIdAsync(client, id) | Devuelve una fila {Seccion}C, o null si id es Guid.Empty o no existe. |
{Seccion}D.GetRowsAsync(client, RowsRequestParameters) | Devuelve List<{Seccion}C> con las filas que cumplen el filtro. |
{Seccion}ES | Las claves de campo como constantes string, con _SectionID (Guid), _Table (nombre de la tabla), _FieldIDs (clave a GUID de campo) y FieldsByRole. |
{Seccion}C | La fila tipada. Hereda de DinaupRowBase: LoadData, ToDic, ToWriteOperation(), Base__ID, Base__Label. |
Las plantillas base de cada sección (ficheros B. - {Seccion}.vb) generan {Seccion}BaseD con la misma forma.
Partial Public Class SectionsD
Public Class AlmacenesD
Public Shared ReadOnly _SectionID As String = "7eec3e34-fbbd-4f1e-a77b-d4a6145686a3"
Public Shared ReadOnly _SectionIDGUID As New Guid("7eec3e34-fbbd-4f1e-a77b-d4a6145686a3")
Public Class AlmacenesES
Public Shared ReadOnly SendcloudID$ = "pr_30655031"
Public Shared ReadOnly TextoPrincipal$ = "nombre"
Public Shared ReadOnly FechaAlta_UTC$ = "pr_400105496714"
Public Shared ReadOnly ReferenciaResponsable$ = "pr_20010549681"
End Class
Public Class AlmacenesC
Inherits DinaupRowBase
Public Property SendcloudID As String
Public Property FechaAlta_UTC As DateTime?
Public Property Color As EnumTextoEstiloE?
Public Property ReferenciaResponsable As Dinaup.DinaupBasicInformation
End Class
End Class
End ClassUn campo que apunta a otra sección se tipa como DinaupBasicInformation: Id, Title, SectionID e ImageId del registro relacionado, sin segunda consulta. Los campos de sistema (ID, FechaAltaDato_UTC, FechaUltimaModificacion_UTC, Eliminado, Empresa) tienen el setter privado: los pone el servidor.
using Dinaup;
using static DemoUp.MyDinaup.SectionsD;
var almacenes = await AlmacenesD.GetRowsAsync(client, new RowsRequestParameters("eliminado", "=", false));
foreach (var almacen in almacenes)
{
Console.WriteLine($"{almacen.TextoPrincipal}: {almacen.ReferenciaResponsable?.Title}");
}
var uno = await AlmacenesD.GetRowByIdAsync(client, almacenes[0].ID);RowsRequestParameters tiene constructores por Guid, por lista de Guid y por (campo, operador, valor), y las propiedades Limit, Skip y QuerySearch. Limit vale 100 por defecto. Para leer muchas filas, pagina con Skip.
GetRowsAsync trae la sección entera más los textos de sus relaciones. Para listados o volumen, usa un informe: solo devuelve las columnas que pide y pagina en el servidor.
Para escribir, combina las constantes de {Seccion}ES con una WriteOperation:
var wop = new WriteOperation(Guid.Empty);
wop.DataMainRow.Add(AlmacenesD.AlmacenesES.TextoPrincipal, "Almacén central");
wop.DataMainRow.Add(AlmacenesD.AlmacenesES.SendcloudID, "SC-4471");
await client.RunWriteOperationAsync(AlmacenesD._SectionIDGUID, wop, false);
wop.EnsureSuccess();
Guid nuevoId = wop.WriteOperationResult.RowID;Informes
Un informe es una consulta tipada. Por cada uno, MyDinaup genera Reports.{Categoria}D.{Informe}C, heredera de DinaupReportBase<RowC>, con la fila anidada {Informe}_RowC: una propiedad por columna, ya con su tipo.
Partial Public Class Reports
Partial Public Class FuncionalidadD
Public Class APIAlmacenesC
Inherits dinaup.DinaupReportBase(Of APIAlmacenes_RowC)
Public Shared _ReportID As String = "83fd57a3-893c-4651-adf9-d5d980af2c85"
Public Shared _ReportIDGuid As Guid = New Guid("83fd57a3-893c-4651-adf9-d5d980af2c85")
Public Shared _SectionIdGuid As Guid = New Guid("7eec3e34-fbbd-4f1e-a77b-d4a6145686a3")
Public Class APIAlmacenes_RowC
Implements IReportRow
Public Property ID As Guid
Public Property TextoPrincipal As String = ""
Public Property DisponibleEnTPV As Boolean
Public Property FechaIA As DateTime
Public Property Color As EnumTextoEstiloE
End Class
End Class
End Class
End ClassLa fila implementa IReportRow, IDinaupRow (Id, Label, SectionID, ImageId) e IDataFechaIA, lleva atributos ProtoBuf para caché y la constante SchemaHash del esquema con el que se generó. Al cargar la respuesta, cada columna se convierte con una extensión del paquete Dinaup según su tipo: .STR() para texto, .ToGUID() para identificadores, .BOOL() para booleanos, .ToDateTime_UTC() para fechas y .INT(0) para enteros y enums.
Miembros heredados de DinaupReportBase<RowC> que usas a diario:
| Miembro | Qué hace |
|---|---|
ExecuteQueryAsync(client, page, resultsPerPage = 2000, querysearch = "", adminMode = false, includeFiles = false, includeFieldsDetails = false) | Ejecuta una página del informe. |
LoadAllRowsAsync(client, pageSize = 10000, maxRows = 50000000, adminMode = false) | Recorre todas las páginas y devuelve List<RowC>. |
Rows, RowsDic | Las filas de la última respuesta, como lista y como diccionario por ID. |
CurrentPage, ExistNextPage, ExecuteQuery_NextPageAsync(), TotalResults, TotalPages | Paginación. TotalResults y TotalPages están marcadas [Obsolete]: el recuento del servidor no es fiable y ExistNextPage depende de él. Recorre pidiendo páginas hasta que una vuelva corta, o con LoadAllRowsAsync. Ver Cliente Dinaup. |
AddFilter(campo, operador, valor), AddFilterIn, AddFilterBetween, AddOrder(campo, desc), AddVariable(clave, valor) | Filtros, orden y variables antes de ejecutar. |
TolerateMissingColumns | Qué pasa si el servidor no devuelve una columna del modelo. |
MaxFechaIA, TokenChanges | Fecha de actividad más alta y token que cambia con cada carga. |
ColIdByColProperty, GetColIDByProperty(prop) | GUID de columna a partir del nombre de la propiedad. |
using Dinaup;
using static DemoUp.MyDinaup.Reports.FuncionalidadD;
var client = await DinaupClientC.ConnectAsync(
endPoint: "https://api.dinaup.com/v2/tu-codigo",
publicKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
secretKey: "tu-secret-key"
);
var report = new APIAlmacenesC();
report.AddFilter("eliminado", "=", false);
await report.ExecuteQueryAsync(client, page: 1, resultsPerPage: 50);
foreach (var row in report.Rows)
{
Console.WriteLine($"{row.TextoPrincipal}: {row.DisponibleEnTPV}");
}El informe generado comprueba que cada columna existe antes de leerla. Si falta alguna, TolerateMissingColumns decide:
false(valor por defecto): lanzaExceptioncon el nombre del informe y las columnas ausentes, y lo registra conDinaup.Logs.Error.true: registra un aviso conDinaup.Logs.Warningy deja esas propiedades en su valor por defecto.
Dinaup.DinaupReportSettings.TolerateMissingColumns fija el valor inicial para todos los informes del proceso; cada instancia lo puede cambiar.
Documentos dinámicos
Un documento dinámico es un guion que se ejecuta en el servidor y devuelve HTML, JSON o PDF: una factura, un correo, un volcado JSON. MyDinaup genera DynamicDocuments.{Categoria}D.{Documento}C, heredera de DinaupDynamicDocumentBase, que fija RequestParameters, Id y Title en su constructor. Encima de la clase va un comentario con el tipo del documento y su código en forma legible.
Partial Public Class DynamicDocuments
Partial Class APID
' DOCUMENTO DINAMICO: Sesión
' Tipo: API
' Codigo (forma legible: campos/secciones/funciones por nombre):
' <!--: F.WriteText(D.SesionActual.TextoPrincipal) :-->
Public Class SesionC
Inherits DinaupDynamicDocumentBase
Sub New()
RequestParameters = New DynamicDocumentGetRequestParameters(New Guid("73fd6203-3109-4572-8ad0-8c58702dd1a5"))
Me.ID = New Guid("73fd6203-3109-4572-8ad0-8c58702dd1a5")
Me.Title = "Sesión"
End Sub
End Class
End Class
End ClassSetVariableValue(clave, valor) rellena las variables del documento y ExecuteAsync(client) devuelve un DynamicDocumentsGetResponse con Content, URL, FileName y Metadata.
using static DemoUp.MyDinaup.DynamicDocuments;
var doc = new APID.SesionC();
var respuesta = await doc.ExecuteAsync(client);
Console.WriteLine(respuesta.Content);Enumeraciones y constantes
-
Enumeraciones.vb: los tipos de lista de tu esquema comoenumde .NET, cada valor con su atributoDescription.EnumTextoEstiloEva deIndefinido = 0aEstilo20 = 20;EnumTareaEstadoErecoge los estados de tarea. Las filas con campos de ese tipo los usan. -
Constants.vb: los valores de las secciones de catálogo como constantes.Constants.EstadosDeVentas.Abierta,PagadayAnuladasonDinaupBasicInformationconId,TitleySectionID; cada catálogo tieneGetDic(), que devuelveDictionary<Guid, DinaupBasicInformation>.No todas las secciones entran. Entra si deriva de una de las 25 secciones base de catálogo del núcleo: estados, tipos, categorías, familias, motivos, métodos, libros registro y jornadas. También entra si su título empieza por Estado, Tipo, Categoría, Clasificación, Familia, Motivo, Método, Fase, Etapa o Prioridad. En inglés cuenta la última palabra: Status, Type, Category y sus equivalentes. Cada sección da como mucho 50 constantes: las de sus 50 primeras filas por fecha de alta. Una fila sin nombre no da constante.
PGSync
En licencias con PG Sync, la carpeta PGSync/ trae una clase PGSync.{Informe}Model por informe sincronizado: hereda de Dinaup.Database.Definitions.BaseModelConverter, implementa IRow y declara Tabla, Campos y LastModifiedFieldDatetimeUTC para leer la réplica de PostgreSQL con Dinaup.Database.
El esquema documentado en el código
Cada constante de campo lleva su comportamiento en el servidor como documentación XML, y cada sección incluye sus scripts como comentarios.
Anotaciones de cada campo
El comentario aparece en el editor al pasar el cursor o autocompletar. Un campo real de la sección Proyectos:
''' <summary>
''' Field ID: 6cde977d-fc04-04f6-27ac-3247ad830765
''' This field is related to the 'bd46bc13-a3be-43c7-bdf6-b063bcc082aa' section (Tipos de proyecto).
''' Auto-filled with Referencia dato: To Do (Siempre).
''' Auto-managed: filled and locked by the server, do not provide it.
''' Text field: up to 36 characters.
''' </summary>
Public Shared ReadOnly ReferenciaTipo$ = "pr_30010431914"| Anotación | Qué significa para tu código |
|---|---|
Field ID: <guid> | El GUID del campo, el mismo que _FieldIDs. |
This field is related to the '<guid>' section (Nombre). | Es una relación: escribe el GUID de un registro de esa sección. |
Auto-filled with <origen> (Siempre). | El servidor lo rellena con un campo de la sesión, una constante o un dato de referencia. Con Siempre, no intentes sobrescribirlo. |
Auto-managed: filled and locked by the server, do not provide it. | No lo envíes en la escritura: lo pone y bloquea el servidor. |
READ-ONLY: auto-calculated by the server from the section: <guid> (Nombre). Do not write it. | Contador o suma calculada desde otra sección. Escribirlo no tiene efecto. |
Read-only: mirror/embedded field derived by the server from its source section. | Campo espejo de otra sección. |
Read-only: the main text is generated automatically. / Read-only: the main date is assigned automatically. | Texto principal o fecha principal calculados por el servidor. |
Read-only: auto-filled from its list document; it cannot be assigned. | Lo rellena el documento de su lista. |
REST write policy: can be set when creating the record, but read-only on update. | Solo acepta valor en el alta. |
Read-only via REST: auto-set by the server, never writable. | Campos de sistema: nunca se escriben. |
Required: you must provide this value when creating the record. | Obligatorio al crear. |
Unique: the value must not be duplicated within the section. | Sin duplicados en la sección. |
Text field: up to N characters. | Longitud máxima del texto. |
Numeric size: up to N integer digits and N decimals. | Dígitos enteros y decimales admitidos. |
Numeric validation: only values greater than 0 / only zero or positive values | El servidor rechaza negativos, y el cero en el primer caso. |
Semantic role: URL / phone number / email address / Spanish tax id NIF/CIF | Formato que el servidor valida o normaliza (correo a minúsculas, NIF a mayúsculas). |
Revisar estas anotaciones antes de construir una WriteOperation evita los dos fallos típicos: enviar campos que gestiona el servidor y omitir los obligatorios.
Los scripts de la sección
Debajo de las constantes, cada sección incluye un bloque COMPORTAMIENTO / SCRIPTS con la lógica que el servidor ejecuta sobre sus registros. Cada script trae Script, Cuando, Campo y Codigo:
' ---------------------------------------------------------------------
' Script: Estado cambiado
' Cuando: Campo cambiado
' Campo: pr_50010431912
' Codigo:
' if C.ReferenciaEstado.Estado = S.Enums.estadotramite.pendiente
' C.EnProceso = 1
' else
' C.EnProceso = 0
' end
' ---------------------------------------------------------------------Tu aplicación no ejecuta ese código: documenta lo que pasa en el servidor cuando escribes en esa sección. Si una escritura devuelve un error de validación o un campo cambia de valor solo, la explicación está en este bloque. La sintaxis es DinaScript, con C. apuntando al registro en edición.
Regenerar la biblioteca
MyDinaup no se escribe: lo genera Dinaup. Cuando cambias el modelo en Flex (un campo, una sección, un informe), regeneras la biblioteca para que el código vuelva a reflejar el esquema.
Abre SDK .NET
En play.dinaup.com, abre la app Desarrollo y, en el menú, Conectar → SDK .NET. La tarjeta 5. Tu biblioteca MyDinaup la ve cualquiera con acceso a Desarrollo.
Regenera
Pulsa Regenerar MyDinaup y confirma con Regenerar. Dinaup vuelve a escribir la biblioteca entera. Tarda varios minutos y la pantalla espera hasta que termina: no la cierres. Al acabar, el aviso MyDinaup regenerado confirma que la biblioteca está lista.
Actualiza la referencia
Sube la versión de {Empresa}.MyDinaup en tu proyecto. El paquete depende del SDK Dinaup, así que actualiza los dos a la vez.
Si el esquema cambia y no regeneras, el modelo y el servidor se desincronizan: un informe pide una columna que ya no existe y lanza excepción. TolerateMissingColumns te deja cargar el resto; regenerar es la solución de fondo.
Qué modelo elegir
| Paquete | Cuándo |
|---|---|
{Empresa}.MyDinaup | Aplicación vinculada a tu licencia. Es el único que refleja tu esquema. |
DemoUp.MyDinaup | Pruebas y ejemplos. Su esquema no es el tuyo. |
Límites
- Nombres del esquema. Las clases salen con los nombres de tus secciones y campos (
APIVentasC,ProductosES). No es configurable. - VB.NET generado. El idioma del paquete no condiciona el de tu aplicación.
- Regeneración a mano. Un cambio de esquema exige volver a pulsar Regenerar MyDinaup.
- Datos maestros con
GetRowsAsync. Lee la sección entera; para listados usa informes.
La conexión, la lectura y la escritura están en Cliente Dinaup; la pantalla de Play, en SDK .NET de Play.