Como utilizar o ORM SQLite-net para bancos de dados na Unity

João Vitor Amorim
6 min readApr 27, 2020

É conhecido que a Unity não apresenta aos desenvolvedores uma forma padrão de se trabalhar com banco de dados. Um dos sistemas de gerenciamento de bancos de dados mais conhecidos e utilizados nessa plataforma é o SQLite, que é conhecido por sua compatibilidade, leveza, agilidade e facilidade de configuração.

Ao trabalharmos com bancos de dados utilizando um ORM (mapeamento objeto-relacional) a tarefa muitas vezes torna-se menos trabalhosa, menos demorada e menos suscetível a erros, além de aumentar o reaproveitamento de código no projeto. O ORM que será utilizado aqui é o SQLite-net, que é open-source e destinado a projetos .NET em C#.

Instalação

Antes de tudo, caso deseje utilizar encriptação no seu banco de dados (o que é recomendável fazer), é necessário que instale em seu projeto o SQLCipher, uma extensão para o SQLite que provê encriptação para os bancos de dados. Há uma forma fácil de utilizar o SQLCipher na Unity, e abordo isso neste meu outro artigo. De qualquer forma, todas as instruções contidas na parte de “Utilização” deste presente artigo continuam válidas, já que no plugin que possibilita a utilização do SQLCipher na Unity, também está incluído o SQLite-net. Para mais informações, consulte o artigo que citei.

Caso ainda não tenha o SQLite instalado no seu projeto Unity, faça o download aqui. Após o download, descompacte o .zip e copie a pasta Plugins para dentro do seu projeto Unity, e pronto! O SQLite já está pronto para utilização. Bem simples, não? A instalação do SQLite-net é tão simples quanto.

Faça o download do SQLite-net neste link (é somente esse arquivo de código C# mesmo). Para realizar a instalação do SQLite-net em seu projeto Unity, basta importar esse arquivo de código para o seu projeto, ou seja, colocar dentro da pasta Assets. É interessante importar o arquivo para a mesma pasta do seu SQLite, por motivos de organização.

Utilização

Após ter instalado, crie um script de teste, anexe-o à um GameObject vazio em sua cena da Unity e abra esse script no Visual Studio (ou no editor que você utiliza). Para realizar a utilização da biblioteca do SQLite-net, é necessário importá-la para o seu arquivo de script. Você pode fazer isso digitando a seguinte linha no início do seu arquivo:

using SQLite;

Todo arquivo de script criado na Unity já vem com uma classe padrão, que possui o mesmo nome do arquivo. Essa classe herda da classe MonoBehaviour. Para criarmos nossas tabelas no banco de dados, deveremos incluir mais classes nesse arquivo de script, onde cada classe representa uma tabela. Entretanto, essas classes (chamadas de Models na arquitetura MVC) não deverão herdar de MonoBehaviour, pois elas terão como única finalidade servir como protótipo para os objetos que obterão e armazenarão temporariamente informações do banco de dados, além de serem protótipos para as próprias tabelas do banco de dados. O recomendado mesmo, por motivos de organização, é que você coloque essas classes em um arquivo separado.

Criação dos classes modelos para as tabelas:

Abaixo, as classes User e Administrator poderão ser usadas para a criação de tabelas no banco de dados:

public class User
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public System.DateTime AccountCreation { get; set; }
}
public class Administrator
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}

Acima dos atributos das classes é possível passar algumas configurações relacionadas à atributos dos campos da tabela do DB, como [PrimaryKey], [AutoIncrement], [MaxLength], entre outros.

Sobre a criação de tabelas com ForeignKey (chave estrangeira), leia o penúltimo tópico deste artigo.

Abrindo a conexão com o banco de dados:

Antes de realizar a criação das tabelas, abra a conexão com o banco de dados:

public class SQLiteExamples : MonoBehaviour
{
private void Start()
{
var databasePath =
Application.dataPath + "/SoftwareDatabase.db";

var db = new SQLiteConnection(databasePath);

Ao instanciar uma nova SQLiteConnection, o banco de dados será criado, caso não exista e após isso será aberta uma conexão com o mesmo. Caso ele já exista, apenas a conexão será aberta.

Criando as tabelas:

Com a conexão aberta, já é possível realizar a criação das tabelas:

db.CreateTable<User>();
db.CreateTable<Administrator>();

O método CreateTable<T>( ) só criará uma nova tabela caso ela não exista.

Inserindo dados:

Para inserir novos dados em nosso banco de dados, também é bem simples:

User newUser = new User()
{
Name = "Luke Skywalker",
Country = "Tatooine",
Email = "iam@jedi.com",
AccountCreation = System.DateTime.Now
};
int newUserID = db.Insert(newUser);Debug.Log(newUserID); // 1Administrator newAdm = new Administrator()
{
Name = "Han Solo",
Email = "millenium@falcon.com"
};
db.Insert(newAdm);

Como pode-se observar, após o objeto ser instanciado e ter seus valores atribuídos, basta utilizar o método Insert para inserir os dados no DB (banco de dados). O próprio ORM irá direcionar os dados para a tabela correta. Este método também retorna a chave primária criada por auto incremento, caso seja o caso.

Obtendo, atualizando ou apagando dados:

As operações de SELECT, UPDATE e DELETE também podem ser executadas normalmente através do ORM, através dos métodos Query e Execute. O método Query é adequado para quando se espera um retorno do banco de dados, ou seja, quando desejamos pegar informações contidas nele, que é o caso do SELECT. Já o método Execute deve ser usado em operações onde não haverá retorno de dados do DB, como é o caso das operações de UPDATE e DELETE.

Acima, exemplo da utilização do método Query, onde há retorno de dados:

string country = "Tatooine";List<User> usersOfTatooine = 
db.Query<User>("SELECT * FROM User WHERE Country=?", country);
Debug.Log(usersOfTatooine[0].Name); // Luke Skywalker

Os dados deverão ser recebidos em uma Lista, cujo tipo é a classe que possui o mesmo nome da tabela (nesse caso, User). Essa Lista conterá todos os objetos que atenderam aos requisitos da SQL Query passada no método, onde os seus atributos podem ser acessados normalmente, como em qualquer objeto.

Utilização do método Execute, onde não se espera retorno de dados:

string email = "millenium@falcon.com";db.Execute("DELETE FROM Administrator WHERE Email=?", email);// RIP Han Solo.

Parâmetros na SQL Query

Outra característica interessante do ORM, presente nos dois últimos exemplos acima, é a possibilidade de substituir os parâmetros do comando por um “ ? “, e assim passar os parâmetros de forma separada, ainda dentro do método. Isso possibilita a criação de funções CRUD mais genéricas, além de impedir problemas de segurança como o SQL Injection (nunca faça concatenação de strings como forma de passar os parâmetros para o comando SQL, pois pode ocasionar em problemas graves de segurança, dependendo da sua aplicação).

Limitações

Infelizmente, o SQLite-net ainda não possui suporte à criação de tabelas com Foreign Key (chave estrangeira) utilizando classes (não há o atributo [ForeignKey]). Há uma alternativa para a criação de tabelas que necessitam possuir a Foreign Key:

  1. Abra a conexão com o DB;
  2. Escreva o SQL da sua tabela em uma string;
  3. Crie um novo SQLiteCommand a partir dessa string;
  4. Execute o método ExecuteNonQuery( ).

Exemplo:

SQLiteConnection database = new SQLiteConnection(databasePath);string sqlCommand =
"CREATE TABLE IF NOT EXISTS " +
"Users (" +
"Id INT PRIMARY KEY AUTOINCREMENT, " +
"Name VARCHAR(25), " +
"Password VARCHAR(100), " +
"CountryName VARCHAR(100), " +
"FOREIGN KEY(CountryName) REFERENCES Countries (CountryName) )";
SQLiteCommand dbCommand = database.CreateCommand(sqlCommand);dbCommand.ExecuteNonQuery();

Felizmente, mesmo tendo de criar as tabelas assim, ainda é possível para utilizar todos os outros recursos citados aqui, basta apenas criar uma classe com os mesmos os atributos dessa tabela criada.

Links

Links citados no decorrer do artigo:

--

--

João Vitor Amorim

Career in the areas of Computer Science and Software Engineering in evolution. Working as Angular front-end developer.