Mover ningún esquema hacia arriba con C# y tipos dinámicos

Uno de los beneficios significativos de trabajar con Couchbase Server 2.0 es su esquema flexible. Los documentos se almacenan como JSON, permitiendo registros implícitamente estructurados que no imponen ningún orden entre sí. En el mundo real, esa "estructura implícita" proviene de tu aplicación. Cuando creas un nuevo usuario en tu aplicación, el documento asociado es una versión serializada en JSON de tu objeto de dominio.

público clase Usuario
{
    [JsonIgnore]
    público cadena Id { consiga; configure; }
   
    [JsonProperty("nombre de usuario")]
    público cadena Nombre de usuario { consiga; configure; }
   
    [JsonProperty("contraseña")]
    público cadena Contraseña { consiga; configure; }
   
    [JsonProperty("tipo")]
    público cadena Tipo { consiga { devolver "usuario"; } }
}

//almacenado como { "username" : "hmoody", "password" : "b3cca" }

Aunque este enfoque es habitual en aplicaciones en las que los documentos se leen y se escriben a partir de objetos de dominio bien definidos, hay casos en los que la estructura de los documentos está intencionadamente menos definida. En tales casos, podría no ser factible tener un objeto de dominio por tipo de documento. 

Mientras que en lenguajes como Python o Ruby, puede ser común utilizar un enfoque menos orientado a objetos (por ejemplo, diccionarios o hashes), en lenguajes fuertemente tipados como C# o Java, es mucho más común representar los datos de la aplicación utilizando objetos de datos fuertemente tipados, a menudo llamados objetos simples (Java|C#). Sin embargo, es ciertamente posible utilizar enfoques de lenguajes dinámicos con estos lenguajes. 

Cuando un usuario preguntó recientemente en StackOverflow cómo extraer documentos JSON de Couchbase y convertirlos en objetos C# de tipado flexible, propuse dos opciones. Para el resto de este post, voy a describir algunos métodos básicos de extensión que podrías utilizar para adoptar un enfoque similar con tus datos.

El primer enfoque consiste en almacenar Diccionario instancias. Los diccionarios se adaptan naturalmente a las estructuras JSON, por lo que son una opción natural para trabajar con documentos de forma menos estructurada. Los diccionarios anidados también se adaptan bien a estructuras JSON complejas. 

var usuario1 = nuevo Diccionario<cadena, objeto>
{
    { "nombre de usuario", "jzablocki" },
    { "preferencias", nuevo Diccionario<cadena, objeto>
        {
            { "tema",  "verde"},
            { "zona horaria",  "EST" }
        }
    }
};

Para guardar y leer este documento, añadiremos métodos de extensión para guardar y recuperar diccionarios. Estos métodos vivirán dentro de una nueva clase estática llamada CouchbaseDynamicExtensions.

público estático clase CouchbaseDynamicExtensions { }

El primer método simplemente envolverá el EjecutarTienda pero encapsulará algunas cosas. Primero, se encargará de serializar el Diccionario a JSON usando la librería Newtonsoft.JSON. Puede modificar la configuración del serializador para soportar camel casing u otras opciones de formato JSON. He dejado los valores por defecto en su lugar. Segundo, he encapsulado el IStoreOperationResponse en una devolución de tupla más sencilla. Dado que las tuplas son comúnmente devueltas en lenguajes dinámicos, y estoy tratando de ser más dinámico, esto parecía un enfoque apropiado.

público estático Tupla<bool, int, cadena> AlmacenarDiccionario(este ICouchbaseClient cliente, StoreMode storeMode,
                                            cadena clave, Diccionario<cadena, objeto> diccionario)
{
    var json = JsonConvert.SerializarObjeto(diccionario);
    var resultado = cliente.EjecutarTienda(storeMode, clave, json);

    si (!resultado.Éxito)
    {
        si (resultado.Excepción != null) tirar resultado.Excepción;

        devolver Tupla.Cree(falsoResultado.CódigoEstado.HasValue ? resultado.CódigoEstado.Valor : 1Resultado.Mensaje);
    }

    devolver Tupla.Cree(verdadero, 0, cadena.Vacío);
}

Recuperar el diccionario del JSON almacenado simplemente invierte el proceso. De nuevo, estoy envolviendo el IGetOperationResult en un Tuple y encargándome de deserializar el JSON almacenado en un archivo Diccionario instancia.

público estático Tupla<bool, int, cadenaDiccionario<cadena, objeto>> GetDictionary(este ICouchbaseClient cliente, cadena clave)
{
    var resultado = cliente.EjecuteGet<cadena>(clave);

    si (!resultado.Éxito)
    {
        si (resultado.Excepción != null) tirar resultado.Excepción;

        devolver Tupla.Cree<bool, int, cadenaDiccionario<cadena, objeto>>
                    (falsoResultado.CódigoEstado.HasValue ? resultado.CódigoEstado.Valor : 1Resultado.Mensaje, null);
    }

    var dict = JsonConvert.DeserializarObjeto<Diccionario<cadena, objeto>>(resultado.Valor);
    devolver Tupla.Cree(verdadero, 0, cadena.Vacío, dict);
}

Guardar y recuperar es sencillo (asegúrese de añadir un using al espacio de nombres de su clase de extensión).

var resultado = cliente.AlmacenarDiccionario(StoreMode.Establecer, "usuario_1"usuario1);
si (resultado.Artículo1)
{
   var dict = cliente.GetDictionary("usuario_1").Artículo4;
   Consola.WriteLine(dic); //debería ser la salida de Dictionary.ToString()
}

Un enfoque más interesante sería aprovechar la nueva función de C# dinámico mecanografía y la ExpandoObject clase. Estas características permiten a los desarrolladores indicar al compilador que realice la comprobación de tipos en tiempo de ejecución, no en tiempo de compilación. Trabajar con documentos JSON es un gran caso de uso para la dinámica.

Los métodos de extensión dinámica son casi idénticos, salvo que donde antes había diccionarios, ahora hay tipos dinámicos. 

público estático Tupla<bool, int, cadena> TiendaDinámica(este ICouchbaseClient cliente, StoreMode storeMode,
                                            cadena key, ExpandoObject obj)
{
    var json = JsonConvert.SerializarObjeto(obj);
    var resultado = cliente.EjecutarTienda(storeMode, clave, json);

    si (!resultado.Éxito)
    {
        si (resultado.Excepción != null) tirar resultado.Excepción como Excepción;

        devolver Tupla.Cree(falsoResultado.CódigoEstado.HasValue ? resultado.CódigoEstado.Valor : 1Resultado.Mensaje);
    }

    devolver Tupla.Cree(verdadero, 0, cadena.Vacío);
}

público estático Tupla<bool, int, cadenaExpandoObjeto> GetDynamic(este ICouchbaseClient cliente, cadena clave)
{
    var resultado = cliente.EjecuteGet<cadena>(clave);

    si (!resultado.Éxito)
    {
        si (resultado.Excepción != null) tirar resultado.Excepción;

        devolver Tupla.Cree<bool, int, cadenaExpandoObjeto>
                    (falsoResultado.CódigoEstado.HasValue ? resultado.CódigoEstado.Valor : 1Resultado.Mensaje, null);
    }

    var obj = JsonConvert.DeserializarObjeto<ExpandoObject>(resultado.Valor);
    devolver Tupla.Cree(verdadero, 0, cadena.Vacío, obj);
}

Usando instancias dinámicas en tu código, puedes guardar y recuperar datos desde y hacia Couchbase Server. Tenga en cuenta que también podría leer cualquier documento JSON en un ExpandoObject utilizando el enfoque de código a continuación. Para probarlo, puede llamar a GetDynamic con una clave de "usuario_1".

usuario dinámico2 = nuevo ExpandoObject();
usuario2.Nombre de usuario = "jzablocki";
usuario2.Preferencias = nuevo ExpandoObject();
usuario2.Preferencias.Tema = "verde";
usuario2.Preferencias.Zona horaria = "EST";

cliente.TiendaDinámica(StoreMode.Establecer, "usuario_2"usuario2 como ExpandoObject);
var getResultado = cliente.GetDynamic("usuario_2");
si (obtenerResultado.Artículo1)
{
    elemento dinámico = obtenerResultado.Artículo4;
    Consola.WriteLine(artículo.Preferencias.Tema);
}

Hay enfoques alternativos hacia las extensiones dinámicas que requieren casting, debido a las limitaciones de llamar a un método de extensión con argumentos dinámicos. Para simplificar las cosas, me he quedado con ExpandoObject argumentos. 

Obviamente, C# no es un lenguaje puramente dinámico y, por tanto, algunos de los métodos son menos concisos de lo que serían en sus homólogos puramente de tipado tardío. Sin embargo, estos métodos demuestran que no tienes que renunciar a toda la riqueza de una base de datos orientada a documentos sin esquema sólo porque tu lenguaje sea estáticamente tipado, siempre que ese lenguaje sea C#, por supuesto...
Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por John Zablocki, Desarrollador NET. Desarrollador SDK, Couchbase

John Zablocki es desarrollador de NET. SDK en Couchbase. John es también el organizador de Beantown ALT.NET y antiguo profesor adjunto en la Universidad de Fairfield. También puedes consultar el libro en Amazon llamado "Couchbase Essentials" que explica cómo instalar y configurar Couchbase Server.

2 Comentarios

  1. Mudanzas Rochester NY noviembre 27, 2013 a 7:05 am

    Muy buen post gracias por compartir...............

  2. Nandkishor Ingavale mayo 13, 2015 a 2:26 pm

    John su post.thanks muy útil

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.