Este site usa cookies e tecnologias afins que nos ajudam a oferecer uma melhor experiência. Ao clicar no botão "Aceitar" ou continuar sua navegação você concorda com o uso de cookies.

Aceitar
Mapeamento objeto-relacional (ORM) Em Operações De Banco De Dados

Banco de dados

Mapeamento objeto-relacional (ORM) Em Operações De Banco De Dados

Elias
Escrito por Elias

Como desenvolvedor, simplificar as interações do banco de dados (como o uso de ORM), mantendo a eficiência, é crucial.

Sem mencionar que, em alguns casos, devemos nos concentrar em entregar o produto rapidamente, sem muitas abstrações, e criar um ORM pode remover essa camada de complexidade para focar no produto em si.

Portanto, hoje, vamos nos aprofundar na criação de um ORM, uma ferramenta poderosa que agiliza as operações do banco de dados, encapsulando-as em classes e métodos intuitivos.

Criação da classe e inicialização do ORM:

O método __init__ inicializa o ORM estabelecendo uma conexão com o banco de dados SQLite usando o módulo sqlite3.

import sqlite3

class SimpleORM:

  def __init__(self, db_name):
    self.conn = sqlite3.connect(db_name)
    self.cursor = self.conn.cursor()
Python

Além disso, adicionando uma nova variável que permite a criação de consultas neste banco de dados já conectamos.

Iniciando uma nova conexão com o banco de dados via ORM:

Nessa abordagem, estabelecemos uma conexão com o banco de dados usando a classe SimpleORM, permitindo a execução de várias consultas dentro do banco de dados especificado.

Como é evidente, o ‘db.sqlite3‘ representa o caminho do arquivo onde o banco de dados está localizado, designado dentro do método sqlite3.connection() para estabelecimento da conexão.

Criando tabelas com o método create_table na ORM:

O método create_table habilita a criação de tabelas dentro do banco de dados. Ele recebe parâmetros para table_name e colunas, executando a consulta SQL para criar a tabela se ela ainda não existir.

def create_table(self, table_name, columns):
  self.cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})")
  self.conn.commit()
Python

Portanto, usar essa abordagem pode facilitar a criação de uma tabela simples com a redução de pequenas melhorias, mas sem muita complicação.

Criando uma nova tabela com o método create_table:

# Create a table with an auto-incremental ID
orm.create_table("users", "id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER")
Python

Neste cenário, há alterações mínimas necessárias para a criação da tabela. No entanto, algumas intricadas e complexidades de consultas SQL, como definições de nomes de colunas. Elas podem ser simplificadas pela introdução de um BaseModel. (Vou me aprofundar mais nessa abordagem em um próximo post).

Inserindo dados na tabela criada usando o método insert_data:

O método insert_data insere dados na tabela especificada. Ele gera dinamicamente a consulta SQL, inserindo dados passados ​​como argumentos na tabela designada.

# Os outros metodos acima....

def insert_data(self, table_name, **kwargs):
  columns = ", ".join(kwargs.keys())
  placeholders = ", ".join(["?"] * len(kwargs))
  query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
  values = tuple(kwargs.values())
  self.cursor.execute(query, values)
  self.conn.commit()
Python

A propósito, como funciona? O método insert_data() cria dinamicamente uma consulta SQL INSERT gerando nomes de colunas e espaços reservados para valores com base no nome da tabela e argumentos de palavra-chave fornecidos.

Em seguida, ele executa essa consulta para inserir dados na tabela especificada usando o cursor, confirmando as alterações no banco de dados posteriormente.

Esse método permite a inserção flexível de dados em tabelas sem especificar explicitamente nomes de colunas na consulta, aproveitando os argumentos de palavra-chave fornecidos como pares coluna-valor.

Como usar o método insert_data():

# Insert data (ID é auto-incrementado)
orm.insert_data("users", name="John", age=32)
orm.insert_data("users", name="Maria", age=22)
Python

Neste exemplo foram utilizadas duas consultas para adicionar duas linhas dentro da tabela users.

Lendo dados de uma tabela específica com o método read_data():

# Os outros metodos acima....

def read_data(self, table_name):
  self.cursor.execute(f"SELECT * FROM {table_name}")
  return self.cursor.fetchall()
Python

O método read_data() é simples, até agora ele só lê todos os dados de uma tabela específica. Basicamente, é similar a TableName.objects.all() usando o Django ORM.

Usando o método read_data():

# Ler e print data
data = orm.read_data("users")
print("Data:", data)

# Resultado ---
# Data: [(1, 'John', 32), (2, 'Maria', 22)]
Python

Este é o resultado do metodo read_data().

Atualizando linhas dentro de tabelas específicas usando o método update_data():

# Os outros metodos acima....

def update_data(self, table_name, id, **new_data):
  set_values = ", ".join([f"{key} = ?" for key in new_data.keys()])
  query = f"UPDATE {table_name} SET {set_values} WHERE id = ?"
  values = tuple(new_data.values()) + (id,)
  self.cursor.execute(query, values)
  self.conn.commit()
Python

O método update_data() é um pouco mais complexo, pois precisa atualizar uma linha específica dentro de uma tabela. Usando os argumentos kword para criar a consulta dinamicamente.

Usando o metodo updated_data():

# Update data
orm.update_data("users", id=1, name="Alicy", age=27)
updated_data = orm.read_data("users")
print("Updated Data:", updated_data)
  
# Resultado ---
# Data: [(1, 'Alicy', 27), (2, 'Maria', 22)]
Python

Aqui está o método update_data() em ação. Seguindo a implementação acima, ele obtém as chaves dos novos valores dos argumentos (id, name, age) para inseri-los no lugar dos dados antigos na consulta. Além disso, os valores (1, ‘Alicy’ e 27) são inseridos como tupla na variável values, após a consulta ser executada no banco de dados.

Excluindo dados de uma tabela específica usando o método delete_data():

# Os outros metodos acima....

def delete_data(self, table_name, id):
  query = f"DELETE FROM {table_name} WHERE id = ?"
  self.cursor.execute(query, (id,))
  self.conn.commit()
Python

O método delete_data() não é um método muito complexo deste exemplo de ORM. Basicamente, ele recebe dois parâmetros, como table_name e id, os insere na consulta DELETE, executa e confirma o código no banco de dados.

Entenda mais sobre ORM nesta postagem.

Usando o método delete_data():

# Delete data
orm.delete_data("users", id=3)
new_data = orm.read_data("users")
print("Dados depois de deletar id especifico:", new_data)

# Resultado ---
# Dados depois de deletar id especifico: [(2, 'Maria', 22)]
Python

Este é um exemplo do metodo delete_data().

Como o codigo ficara finalizado:

import sqlite3

class SimpleORM:
    def __init__(self, db_name):
        self.conn = sqlite3.connect(db_name)
        self.cursor = self.conn.cursor()

    def create_table(self, table_name, columns):
        self.cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})")
        self.conn.commit()

    def insert_data(self, table_name, **kwargs):
        columns = ", ".join(kwargs.keys())
        placeholders = ", ".join(["?"] * len(kwargs))
        query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
        values = tuple(kwargs.values())
        self.cursor.execute(query, values)
        self.conn.commit()

    def read_data(self, table_name):
        self.cursor.execute(f"SELECT * FROM {table_name}")
        return self.cursor.fetchall()

    def update_data(self, table_name, id, **new_data):
        set_values = ", ".join([f"{key} = ?" for key in new_data.keys()])
        query = f"UPDATE {table_name} SET {set_values} WHERE id = ?"
        values = tuple(new_data.values()) + (id,)
        self.cursor.execute(query, values)
        self.conn.commit()

    def delete_data(self, table_name, id):
        query = f"DELETE FROM {table_name} WHERE id = ?"
        self.cursor.execute(query, (id,))
        self.conn.commit()

    def close_connection(self):
        self.conn.close()

# Example usage:
if __name__ == "__main__":
    orm = SimpleORM("db.sqlite3")

    # Create a table with an auto-incremental ID
    orm.create_table("users", "id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER")

    # Insert data (ID is auto-incremented)
    orm.insert_data("users", name="John", age=32)

    # Read and print data
    data = orm.read_data("users")
    print("Data:", data)

    # Update data
    orm.update_data("users", id=1, name="Alicy", age=27)
    updated_data = orm.read_data("users")
    print("Updated Data:", updated_data)

    # Delete data
    orm.delete_data("users", id=3)
    new_data = orm.read_data("users")
    print("Data after deletion:", new_data)

    # Close the connection
    orm.close_connection()
Python

Conclusão

Em resumo, este ORM exemplifica uma implementação direta dos princípios DRY. Ao utilizar esta abordagem, os desenvolvedores podem reduzir significativamente a complexidade do código e minimizar o número de consultas.

No entanto, enquanto um ORM simplifica o código e reduz a repetição, esta implementação em particular permanece relativamente simplista em comparação com ORMs mais estabelecidos.

Por exemplo, ele necessita da inclusão de um BaseModel para criar tabelas inteiramente via código Python. E não tem capacidades para estabelecer relacionamentos de tabela. Ou filtrar dados com base em valores específicos além de retornar todas as linhas.

No entanto, esta demonstração serve como um vislumbre perspicaz do funcionamento interno dos ORMs em relação às operações de banco de dados.