1. Introducción a las operaciones de entidades en ent

Este tutorial te guiará de forma exhaustiva para dominar las operaciones de entidades en el marco de trabajo ent, abarcando el proceso completo de creación, consulta, actualización y eliminación de entidades. Es adecuado para principiantes que desean adentrarse gradualmente en la funcionalidad central de ent.

3. Operación de Creación de Entidades

3.1 Creación de una sola entidad

Crear una entidad es la operación fundamental para la persistencia de datos. A continuación se detallan los pasos para crear un objeto de entidad único utilizando el marco de trabajo ent y guardarlo en la base de datos:

  1. En primer lugar, define la estructura y campos de una entidad, es decir, define el modelo de la entidad en el archivo de schema.
  2. Ejecuta el comando ent generate para generar el código de operación de entidad correspondiente.
  3. Utiliza el método Create generado para construir una nueva entidad y establecer los valores de campo de la entidad mediante llamadas encadenadas.
  4. Finalmente, llama al método Save para guardar la entidad en la base de datos.

A continuación se muestra un ejemplo que demuestra cómo crear y guardar una entidad de usuario:

package main

import (
    "context"
    "log"
    "entdemo/ent"
)

func main() {
    // Crea una instancia de Cliente para la interacción con la base de datos
    cliente, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
    if err != nil {
        log.Fatalf("Error al abrir la conexión a la base de datos: %v", err)
    }
    defer cliente.Close()

    // Crea un contexto
    ctx := context.Background()
    
    // Crea una entidad de usuario utilizando el Cliente
    a8m, err := cliente.User.
        Create().
        SetName("a8m").
        Save(ctx)
    if err != nil {
        log.Fatalf("Error al crear la entidad de usuario: %v", err)
    }

    // Entidad guardada con éxito en la base de datos
    log.Printf("Entidad de usuario guardada: %v", a8m)
}

En este ejemplo, se crea primero un cliente de base de datos cliente. Luego, se utiliza el método User.Create para establecer los atributos del nuevo usuario y, finalmente, se llama al método Save para guardar al usuario en la base de datos.

3.2 Creación de Entidades en Lote

En ciertos escenarios, puede ser necesario crear múltiples entidades, como durante la inicialización de la base de datos o operaciones de importación masiva de datos. El marco de trabajo ent proporciona la capacidad de crear entidades en lotes, lo que ofrece un mejor rendimiento en comparación con la creación y guardado de entidades de forma individual.

Los pasos para la creación de entidades en lotes son los siguientes:

  1. Utiliza el método CreateBulk en lugar del método Create, que permite la creación de múltiples entidades en una sola operación.
  2. Llama a Create para cada entidad que se va a crear.
  3. Una vez que se han creado todas las entidades, utiliza el método Save para guardar las entidades en la base de datos de forma masiva.

A continuación se muestra un ejemplo de creación de entidades en lotes:

package main

import (
    "context"
    "log"
    "entdemo/ent"
)

func main() {
    cliente, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
    if err != nil {
        log.Fatalf("Error al abrir la conexión a la base de datos: %v", err)
    }
    defer cliente.Close()
    ctx := context.Background()

    // Crear entidades de Mascota en lotes
    mascotas, err := cliente.Pet.CreateBulk(
        cliente.Pet.Create().SetName("pedro").SetOwner(a8m),
        cliente.Pet.Create().SetName("xabi").SetOwner(a8m),
        cliente.Pet.Create().SetName("layla").SetOwner(a8m),
    ).Save(ctx)
    if err != nil {
        log.Fatalf("Error al crear entidades de Mascota en lotes: %v", err)
    }

    log.Printf("Se crearon %d entidades de Mascota en lote\n", len(mascotas))
}

En este ejemplo, se crea primero un cliente, y luego se construyen múltiples entidades de Pet utilizando el método CreateBulk, estableciendo sus nombres y campos de propietario. Todas las entidades se guardan en la base de datos a la vez cuando se llama al método Save, lo que proporciona un mejor rendimiento para manejar grandes cantidades de datos.

4. Operaciones de Consulta de Entidades

4.1 Consulta básica

La consulta de base de datos es la forma fundamental de recuperar información. En ent, el método Query se utiliza para iniciar una consulta. A continuación se presentan los pasos y un ejemplo de consulta básica de entidades:

  1. Asegúrese de tener una instancia utilizable de Client.
  2. Utilice Client.Query() o métodos auxiliares de entidad como Pet.Query() para crear una consulta.
  3. Agregue condiciones de filtrado según sea necesario, como Where.
  4. Ejecute la consulta y recupere los resultados llamando al método All.
paquete principal

import (
    "context"
    "registrar"
    "entdemo/ent"
    "entdemo/ent/user"
)

func main() {
    cliente, err := ent.Open("sqlite3", "archivo:ent?cache=shared&_fk=1")
    if err != nil {
        log.Fatalf("Error al abrir la conexión a la base de datos: %v", err)
    }
    defer cliente.Close()
    ctx := context.Background()

    // Consulta de todos los usuarios con el nombre "a8m"
    usuarios, err := cliente.User.
        Query().
        Where(user.NameEQ("a8m")).
        All(ctx)
    if err != nil {
        log.Fatalf("Error al consultar usuarios: %v", err)
    }

    para _, u := rango usuarios {
        log.Printf("Usuario encontrado: %#v\n", u)
    }
}

Este ejemplo demuestra cómo encontrar todos los usuarios con el nombre "a8m".

4.2 Paginación y ordenación

La paginación y la ordenación son características avanzadas comúnmente utilizadas al realizar consultas, y se utilizan para controlar el orden y la cantidad de datos de salida. Así es como se logra la paginación y las consultas de ordenación utilizando ent:

  1. Utilice el método Limit para establecer el número máximo de resultados que se devolverán.
  2. Utilice el método Offset para omitir algunos de los resultados anteriores.
  3. Utilice el método Order para especificar el campo de ordenación y la dirección.

Aquí hay un ejemplo de una consulta de paginación y ordenación:

paquete principal

import (
    "context"
    "registrar"
    "entdemo/ent"
    "entdemo/ent/pet"
)

func main() {
    cliente, err := ent.Open("sqlite3", "archivo:ent?cache=shared&_fk=1")
    if err != nil {
        log.Fatalf("Error al abrir la conexión a la base de datos: %v", err)
    }
    defer cliente.Close()
    ctx := context.Background()

    // Consulta de mascotas en orden descendente por edad con paginación
    mascotas, err := cliente.Pet.
        Query().
        Order(ent.Desc(pet.FieldAge)).
        Limit(10).
        Offset(0).
        All(ctx)
    if err != nil {
        log.Fatalf("Error al consultar mascotas: %v", err)
    }

    para _, p := rango mascotas {
        log.Printf("Mascota encontrada: %#v\n", p)
    }
}

Este ejemplo demuestra cómo recuperar la primera página, hasta 10 registros, de mascotas ordenadas en orden descendente por edad. Al modificar los valores de Limit y Offset, se puede lograr la paginación a través del conjunto de datos completo.

5. Operaciones de actualización de entidad

5.1 Actualización de una sola entidad

En muchas aplicaciones, la actualización de entidades es una parte esencial de las operaciones diarias. En esta sección, demostraremos cómo utilizar el marco Ent para actualizar una sola entidad en la base de datos.

En primer lugar, suponiendo que necesitamos actualizar la edad de un usuario, podemos utilizar el método Update generado por Ent.

// Suponiendo que ya tenemos una entidad de usuario 'a8m' y un contexto 'ctx'

a8m, err := a8m.Update().         // Crea un constructor de actualización de usuario
    SetAge(30).                   // Establece la edad del usuario en 30 años
    Save(ctx)                     // Realiza la operación de guardado y devuelve el resultado
if err != nil {
    log.Fatalf("Error al actualizar el usuario: %v", err)
}

También se pueden actualizar varios campos simultáneamente:

a8m, err := a8m.Update().
    SetAge(30).                    // Actualizar la edad
    SetName("Ariel").              // Actualizar el nombre
    AddRank(10).                   // Aumentar el rango en 10
    Save(ctx)
if err != nil {
    log.Fatalf("Error al actualizar el usuario: %v", err)
}

La operación de actualización se puede encadenar, lo que es muy flexible y fácil de leer. Llamar al método Save realizará la actualización y devolverá la entidad actualizada o un mensaje de error.

5.2 Actualizaciones Condicionales

Ent te permite realizar actualizaciones basadas en condiciones. Aquí tienes un ejemplo en el que solo se actualizarán los usuarios que cumplan condiciones específicas.

// Suponiendo que tenemos el `id` de un usuario y queremos marcar ese usuario como completado para la versión `currentVersion`

err := client.Todo.
    UpdateOneID(id).          // Crea un constructor para actualizar por ID de usuario
    SetStatus(todo.StatusDone).
    AddVersion(1).
    Where(
        todo.Version(currentVersion),  // La operación de actualización solo se ejecuta cuando la versión actual coincide
    ).
    Exec(ctx)
switch {
case ent.IsNotFound(err):
    fmt.Println("Tarea no encontrada")
case err != nil:
    fmt.Println("Error al actualizar:", err)
}

Al utilizar actualizaciones condicionales, el método .Where() debe estar involucrado. Esto te permite determinar si la actualización debe realizarse en función de los valores actuales en la base de datos, lo cual es crucial para garantizar la consistencia e integridad de los datos.

6. Operaciones de Eliminación de Entidades

6.1 Eliminación de una Única Entidad

Eliminar entidades es otra función importante en las operaciones de base de datos. El framework Ent proporciona una API sencilla para realizar operaciones de eliminación.

El siguiente ejemplo demuestra cómo eliminar una entidad de usuario específica:

err := client.User.
    DeleteOne(a8m).  // Crea un constructor de eliminación de usuario
    Exec(ctx)        // Ejecuta la operación de eliminación
if err != nil {
    log.Fatalf("Error al eliminar el usuario: %v", err)
}

6.2 Eliminación Condicional

Al igual que con las operaciones de actualización, también podemos realizar operaciones de eliminación basadas en condiciones específicas. En ciertos escenarios, es posible que solo queramos eliminar entidades que cumplan condiciones específicas. El uso del método .Where() puede definir estas condiciones:

// Supongamos que queremos eliminar todos los archivos con una fecha de actualización anterior a una fecha específica

afectados, err := client.File.
    Delete().
    Where(file.UpdatedAtLT(date)).  // Solo ejecutar la eliminación si la fecha de actualización del archivo es anterior a la fecha proporcionada
    Exec(ctx)
if err != nil {
    log.Fatalf("Error al eliminar archivos: %v", err)
}

// Esta operación devuelve el número de registros afectados por la operación de eliminación
fmt.Printf("%d archivos han sido eliminados\n", afectados)

El uso de operaciones de eliminación condicionales garantiza un control preciso sobre nuestras operaciones de datos, asegurando que solo se eliminen las entidades que realmente cumplan las condiciones. Esto mejora la seguridad y confiabilidad de las operaciones de base de datos.