29
Como trabalhar com Postgres SQL e NOSql juntos com Entity Framework Core?
Olá. Vou mostrar um passo a passo de como trabalhar com banco de dado relacional e não relacional ao mesmo tempo com Postgres e suporte para EFCore.
Postgres é uma banco de dados objeto-relational que pertence a empresa Oracle, porém é um banco de dados open source com uma forte comunidade mantendo-o. Postgres é incrivelmente robusto e confiável, dado seu histórico de 30 anos no mercado.
Primitives: Integer, Numeric, String, Boolean
Structured: Date/Time, Array, Range / Multirange, UUID
Document: JSON/JSONB, XML, Key-value (Hstore)
Geometry: Point, Line, Circle, Polygon
Customizations: Composite, Custom Types
Uma das maravilhas do banco de Postgres é a possibilidade de trabalhar de forma relacional e não relacional no mesmo banco, no mesmo objeto, na mesma tabela. SIM ! É possível, através do tipo de dado Document, que recebe dados Json e JsonBinary (JsonB).
Para podermos usar o EFcore nos nossos métodos usando o NSql, precisamos instalar um pacote nuget chamado npgsql.entityframeworkcore.postgresql
ele vai permitir fazer os métodos CRUD de forma mais parecida com o EFCore ORM que estamos acostumados.
npgsql.entityframeworkcore.postgresql
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Toll
EFCore.NamingConventions
ConfigureServices Method
services.AddDbContext<PostgresNsql.MyContext>(option => option.UseNpgsql(Configuration.GetConnectionString("Nsql")));
public class MyContext : DbContext
{
public MyContext(DbContextOptions options) :base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql()
.UseSnakeCaseNamingConvention();
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder
.Entity<DataModel>()
.Property(e => e.Id)
.UseIdentityAlwaysColumn();
public DbSet<DataModel> DataModels { get; set; }
}
UseSnakeCaseNamingConvention()
Snake Case pode ser necessário para lidar com JSONs que separam 2 palavras com _ underline. Dessa forma não tera problemas com serialização.
Definindo auto-increment na coluna ID
.Property(e => e.Id)
Identity always column é um dos tipos de atribuição de valor que você pode dar, nessa modalidade você define que os valores serão gerados diretamente no banco, impossibilitando você setar o valor no momento de inserção no banco de dados.
.UseIdentityAlwaysColumn();
Na criação da model é que está o grande pulo do gato no uso de SQL e NSql juntos. Caso você tenha dados instáveis ainda e eles não são 100% mapeaveis e estruturados, você pode usar o DataType Json para receber a parte NSql dos seus dados.
Para isso, você precisa adicionar a biblioteca System.Text.Json
e tipar a sua propriedade com a classe JsonDocument, pois ele já identificará que ali será recebido dados em JSON e facilitará a descerialização.
A model precisa ser IDisposable pois a classe JsonDocument é IDisposable também, melhorando o gerenciamento de memória.
public class DataModel : IDisposable
{
public int Id { get; set; }
public string Nome { get; set; }
public int idade { get; set; }
public JsonDocument Data { get; set; }
public void Dispose() => Data?.Dispose();
}
Para identificar a parte NSql da nossa model, é preciso adicionar a Data Notation [Column(TypeName = "jsonb")]
para identificar o objeto Json e mapear as propriedades.
public class DataModel
{
public int Id { get; set; }
public string Nome { get; set; }
public int idade { get; set; }
[Column(TypeName = "jsonb")]
public Endereco Address { get; set; }
}
public class Endereco // Mapeando os dados recebidos em Json
{
public string Rua { get; set; }
public int Numero { get; set; }
public Casa[] Casas { get; set; }
}
public class Casa
{
public decimal Preco { get; set; }
public string EnderecoCompleto { get; set; }
}
Eu não usei um repositório ou alguma arquitetura mais complexa para facilitar o entendimento do artigo.
Mas mostrarei agora na Controller como podemos trabalhar com os dados do tipo JSON.
Percebam que nada muda na listagem de todas as colunas.
public List<DataModel> GetAll()
{
return _myContext.DataModels.ToList();
}
Uma dúvida que tinha quando começando a trabalhar com Postgres SQL e NSql junto é se dava pra fazer em uma consulta, juntar os dados SQL e NSql. Abaixo está um exemplo de um Get onde eu parametrizo que quero apenas resultados de pessoas com 12 anos E com o ultimo nome igual a "Paixao". Idade é um valor SQL da coluna idade e "lastname" é um item dos dados que recebemos em JSON.
public IEnumerable<string> Get()
{
var resultado = _myContext.DataModels;
return resultado.Where(x => x.idade == 12 && x.Data.RootElement.GetProperty("lastName").GetString() == "Paixao").ToList();
}
Um outro exemplo que trouxe, é caso você quero exibir apenas 1 dos itens dos dados em JSON.
public IEnumerable<string> Get()
{
var resultado = _myContext.DataModels;
return resultado.Select(x=>x.Data.RootElement.GetProperty("lastName").GetString()).ToList();
}
RootElement
é uma classe que vai pegar os dados JSON da propriedade Data
permitindo que você então denomine com o método GetProperty("propriedade")
qual propriedade do JSON você vai trabalhar e por final você deve colocar o método GetString()
para converter o dados JSON que você filtrou em string.
Obrigado
A VaiVoa incentiva seus Desenvolvedores em seu processo de crescimento e aceleração técnica. Os artigos publicados não traduzem a opinião da VaiVoa. A publicação obedece ao propósito de estimular o debate.
29