atualização bd
This commit is contained in:
parent
02531f0861
commit
a12908efa6
@ -14,14 +14,16 @@ code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
code:not(pre *) {
|
code:not(pre *) {
|
||||||
|
font-size: .8em;
|
||||||
background-color: var(--color-code-bg);
|
background-color: var(--color-code-bg);
|
||||||
color: var(--color-code-fg);
|
color: var(--color-code-fg);
|
||||||
padding: 3px 6px;
|
padding: 2px 5px;
|
||||||
border: 1px solid var(--color-code-border);
|
border: 1px solid var(--color-code-border);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre:has(code) {
|
pre:has(code) {
|
||||||
|
font-size: .9em;
|
||||||
background-color: var(--color-codeblock-bg);
|
background-color: var(--color-codeblock-bg);
|
||||||
color: var(--color-codeblock-fg);
|
color: var(--color-codeblock-fg);
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|||||||
@ -20,7 +20,6 @@ h2 {
|
|||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
em {
|
em {
|
||||||
|
|||||||
@ -58,7 +58,8 @@ dotnet add package MySqlConnector`}</code></pre>
|
|||||||
O banco de dados que vamos utilizar possui uma tabela com o nome <code>Livro</code>. Esta tabela possui os seguintes campos:
|
O banco de dados que vamos utilizar possui uma tabela com o nome <code>Livro</code>. Esta tabela possui os seguintes campos:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`Isbn VARCHAR(255) PRIMARY KEY NOT NULL,
|
<pre><code>{`Id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
Isbn VARCHAR(255) NOT NULL,
|
||||||
Titulo VARCHAR(512) NOT NULL,
|
Titulo VARCHAR(512) NOT NULL,
|
||||||
Autor TEXT NOT NULL,
|
Autor TEXT NOT NULL,
|
||||||
Genero TEXT NOT NULL,
|
Genero TEXT NOT NULL,
|
||||||
@ -98,19 +99,19 @@ app.MapPost("/livros", () =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Edita um livro.
|
// Edita um livro.
|
||||||
app.MapPut("/livros/{isbn}", () =>
|
app.MapPut("/livros/{id}", () =>
|
||||||
{
|
{
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Obtém os dados de um livro individual.
|
// Obtém os dados de um livro individual.
|
||||||
app.MapGet("/livros/{isbn}", () =>
|
app.MapGet("/livros/{id}", () =>
|
||||||
{
|
{
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove um livro.
|
// Remove um livro.
|
||||||
app.MapDelete("/livros/{isbn}", () =>
|
app.MapDelete("/livros/{id}", () =>
|
||||||
{
|
{
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -126,6 +127,7 @@ app.Run();`}</code></pre>
|
|||||||
|
|
||||||
public class Livro
|
public class Livro
|
||||||
{
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
public string? Isbn { get; set; }
|
public string? Isbn { get; set; }
|
||||||
public string? Titulo { get; set; }
|
public string? Titulo { get; set; }
|
||||||
public string? Autor { get; set; }
|
public string? Autor { get; set; }
|
||||||
@ -184,7 +186,7 @@ public class LivroRepository
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
O valor de retorno será um <code>IEnumerable<Livro></code>. Um <code>IEnumerable</code> é uma interface do dotnet que representa
|
O valor de retorno será um <code>IEnumerable<Livro></code>. Um <code>IEnumerable</code> é uma interface que representa
|
||||||
qualquer sequência <em>iterável</em> de objetos. Por exemplo, um objeto <code>List<T></code> ou um vetor <code>T[]</code> são iteráveis,
|
qualquer sequência <em>iterável</em> de objetos. Por exemplo, um objeto <code>List<T></code> ou um vetor <code>T[]</code> são iteráveis,
|
||||||
portanto podem ser retornados neste método.
|
portanto podem ser retornados neste método.
|
||||||
</p>
|
</p>
|
||||||
@ -215,7 +217,7 @@ public class LivroRepository
|
|||||||
var offset = take * Math.Max(pagina-1, 0);
|
var offset = take * Math.Max(pagina-1, 0);
|
||||||
var lista = new List<Livro>();
|
var lista = new List<Livro>();
|
||||||
|
|
||||||
cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
|
cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
|
||||||
cmd.Parameters.AddWithValue("offset", offset);
|
cmd.Parameters.AddWithValue("offset", offset);
|
||||||
cmd.Parameters.AddWithValue("take", take);
|
cmd.Parameters.AddWithValue("take", take);
|
||||||
|
|
||||||
@ -225,16 +227,17 @@ public class LivroRepository
|
|||||||
{
|
{
|
||||||
lista.Add(new()
|
lista.Add(new()
|
||||||
{
|
{
|
||||||
Isbn = reader.GetString(0),
|
Id = reader.GetInt64(0),
|
||||||
Titulo = reader.GetString(1),
|
Isbn = reader.GetString(1),
|
||||||
Autor = reader.GetString(2),
|
Titulo = reader.GetString(2),
|
||||||
Genero = reader.GetString(3),
|
Autor = reader.GetString(3),
|
||||||
Descricao = reader.GetString(4),
|
Genero = reader.GetString(4),
|
||||||
Foto = reader.GetString(5),
|
Descricao = reader.GetString(5),
|
||||||
Keywords = reader.GetString(6),
|
Foto = reader.GetString(6),
|
||||||
Ativo = reader.GetBoolean(7),
|
Keywords = reader.GetString(7),
|
||||||
CriadoEm = reader.GetDateTime(8),
|
Ativo = reader.GetBoolean(8),
|
||||||
AtualizadoEm = reader.GetDateTime(9),
|
CriadoEm = reader.GetDateTime(9),
|
||||||
|
AtualizadoEm = reader.GetDateTime(10),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +271,7 @@ await conn.OpenAsync();`}</code></pre>
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
O <a href="https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/" target="_blank">modelo de programação assíncrona</a> é uma característica que
|
O <a href="https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/" target="_blank">modelo de programação assíncrona</a> é uma característica que
|
||||||
é praticamente ubíqua no dotnet, mas não precisamos nos aprofundar nela por enquanto. Basta saber que devemos utilizar <code>await</code> em métodos assíncronos, e
|
está presente em quase toda a linguagem, mas não precisamos nos aprofundar nela por enquanto. Basta saber que devemos utilizar <code>await</code> em métodos assíncronos, e
|
||||||
que se o utilizarmos, o nosso método deve ser também assíncrono, sendo declarado com <code>async Task</code>.
|
que se o utilizarmos, o nosso método deve ser também assíncrono, sendo declarado com <code>async Task</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -292,7 +295,7 @@ var lista = new List<Livro>();`}</code></pre>
|
|||||||
A variável <code>lista</code> é uma lista de objetos <code>Livro</code> que irá guardar todos os resultados da consulta, e depois será retornada.
|
A variável <code>lista</code> é uma lista de objetos <code>Livro</code> que irá guardar todos os resultados da consulta, e depois será retornada.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
|
<pre><code>{`cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
|
||||||
cmd.Parameters.AddWithValue("offset", offset);
|
cmd.Parameters.AddWithValue("offset", offset);
|
||||||
cmd.Parameters.AddWithValue("take", take);`}</code></pre>
|
cmd.Parameters.AddWithValue("take", take);`}</code></pre>
|
||||||
|
|
||||||
@ -312,24 +315,26 @@ cmd.Parameters.AddWithValue("take", take);`}</code></pre>
|
|||||||
{
|
{
|
||||||
lista.Add(new()
|
lista.Add(new()
|
||||||
{
|
{
|
||||||
Isbn = reader.GetString(0),
|
Id = reader.GetInt64(0),
|
||||||
Titulo = reader.GetString(1),
|
Isbn = reader.GetString(1),
|
||||||
Autor = reader.GetString(2),
|
Titulo = reader.GetString(2),
|
||||||
Genero = reader.GetString(3),
|
Autor = reader.GetString(3),
|
||||||
Descricao = reader.GetString(4),
|
Genero = reader.GetString(4),
|
||||||
Foto = reader.GetString(5),
|
Descricao = reader.GetString(5),
|
||||||
Keywords = reader.GetString(6),
|
Foto = reader.GetString(6),
|
||||||
Ativo = reader.GetBoolean(7),
|
Keywords = reader.GetString(7),
|
||||||
CriadoEm = reader.GetDateTime(8),
|
Ativo = reader.GetBoolean(8),
|
||||||
AtualizadoEm = reader.GetDateTime(9),
|
CriadoEm = reader.GetDateTime(9),
|
||||||
|
AtualizadoEm = reader.GetDateTime(10),
|
||||||
});
|
});
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Este laço é repetido enquanto <code>await reader.ReadAsync()</code> retornar <code>true</code>, o que significa que existe um resultado da consulta que pode ser lido.
|
Este laço é repetido enquanto <code>await reader.ReadAsync()</code> retornar <code>true</code>, o que significa que existe um resultado da consulta que pode ser lido.
|
||||||
Quando isso acontece, podemos ler as colunas do resultado através dos métodos de <code>reader</code>, como <code>reader.GetString(0)</code>. O número passado como
|
Quando isso acontece, podemos ler as colunas do resultado através dos métodos de <code>reader</code>, como <code>reader.GetString(0)</code>. O número passado como
|
||||||
parâmetro para estas funções indica a posição da coluna lida. Por exemplo, na consulta que realizamos (<code>SELECT Isbn, Titulo, ...</code>), a coluna <code>Isbn</code> é a primeira,
|
parâmetro para estas funções indica a posição da coluna lida. Por exemplo, na consulta que realizamos (<code>SELECT Id, Isbn, Titulo, ...</code>), a coluna <code>Id</code> é a primeira,
|
||||||
portanto, para ler este valor, devemos executar <code>reader.GetString(0)</code>. <code>Titulo</code> é a segunda, então o seu valor é obtido através de <code>reader.GetString(1)</code>, e assim
|
portanto, para ler este valor, devemos executar <code>reader.GetInt64(0)</code> (<code>Int64</code>, um número inteiro de 64-bits, é um sinônimo para <code>long</code>).
|
||||||
|
<code>Isbn</code> é a segunda, então o seu valor é obtido através de <code>reader.GetString(1)</code>, e assim
|
||||||
sucessivamente.
|
sucessivamente.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -362,21 +367,21 @@ app.MapGet("/livros", async () =>
|
|||||||
Agora execute este endpoint. Se tudo deu certo, você verá alguns livros cadastrados no retorno.
|
Agora execute este endpoint. Se tudo deu certo, você verá alguns livros cadastrados no retorno.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Obtendo um livro pelo ISBN</h2>
|
<h2>Obtendo um livro pela chave primária</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
O ISBN é a chave primária da tabela. Vamos implementar um método que consulta um único livro a partir deste dado.
|
O Id é a chave primária da tabela. Vamos implementar um método que consulta um único livro a partir deste dado.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`public async Task<Livro> Obter(string isbn)
|
<pre><code>{`public async Task<Livro> Obter(long id)
|
||||||
{
|
{
|
||||||
using var conn = new MySqlConnection(ConnString);
|
using var conn = new MySqlConnection(ConnString);
|
||||||
using var cmd = conn.CreateCommand();
|
using var cmd = conn.CreateCommand();
|
||||||
|
|
||||||
await conn.OpenAsync();
|
await conn.OpenAsync();
|
||||||
|
|
||||||
cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Isbn=@isbn";
|
cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Id=@id";
|
||||||
cmd.Parameters.AddWithValue("isbn", isbn);
|
cmd.Parameters.AddWithValue("id", id);
|
||||||
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
|
||||||
@ -384,21 +389,22 @@ app.MapGet("/livros", async () =>
|
|||||||
|
|
||||||
if (!existe)
|
if (!existe)
|
||||||
{
|
{
|
||||||
throw new Exception($"Livro com ISBN {isbn} não encontrado");
|
throw new Exception($"Livro {id} não encontrado");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Isbn = reader.GetString(0),
|
Id = reader.GetInt64(0),
|
||||||
Titulo = reader.GetString(1),
|
Isbn = reader.GetString(1),
|
||||||
Autor = reader.GetString(2),
|
Titulo = reader.GetString(2),
|
||||||
Genero = reader.GetString(3),
|
Autor = reader.GetString(3),
|
||||||
Descricao = reader.GetString(4),
|
Genero = reader.GetString(4),
|
||||||
Foto = reader.GetString(5),
|
Descricao = reader.GetString(5),
|
||||||
Keywords = reader.GetString(6),
|
Foto = reader.GetString(6),
|
||||||
Ativo = reader.GetBoolean(7),
|
Keywords = reader.GetString(7),
|
||||||
CriadoEm = reader.GetDateTime(8),
|
Ativo = reader.GetBoolean(8),
|
||||||
AtualizadoEm = reader.GetDateTime(9),
|
CriadoEm = reader.GetDateTime(9),
|
||||||
|
AtualizadoEm = reader.GetDateTime(10),
|
||||||
};
|
};
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
|
|
||||||
@ -406,11 +412,11 @@ app.MapGet("/livros", async () =>
|
|||||||
As três primeiras linhas deste método, assim como no de listagem, abre uma conexão com o banco de dados.
|
As três primeiras linhas deste método, assim como no de listagem, abre uma conexão com o banco de dados.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Isbn=@isbn";
|
<pre><code>{`cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Id=@id";
|
||||||
cmd.Parameters.AddWithValue("isbn", isbn);`}</code></pre>
|
cmd.Parameters.AddWithValue("id", id);`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A consulta é montada na variável <code>cmd</code>, o parâmetro <code>isbn</code> é adicionado ao comando.
|
A consulta é montada na variável <code>cmd</code>, o parâmetro <code>id</code> é adicionado ao comando.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`using var reader = await cmd.ExecuteReaderAsync();
|
<pre><code>{`using var reader = await cmd.ExecuteReaderAsync();
|
||||||
@ -419,27 +425,28 @@ var existe = await reader.ReadAsync();
|
|||||||
|
|
||||||
if (!existe)
|
if (!existe)
|
||||||
{
|
{
|
||||||
throw new Exception($"Livro com ISBN {isbn} não encontrado");
|
throw new Exception($"Livro {id} não encontrado");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Isbn = reader.GetString(0),
|
Id = reader.GetInt64(0),
|
||||||
Titulo = reader.GetString(1),
|
Isbn = reader.GetString(1),
|
||||||
Autor = reader.GetString(2),
|
Titulo = reader.GetString(2),
|
||||||
Genero = reader.GetString(3),
|
Autor = reader.GetString(3),
|
||||||
Descricao = reader.GetString(4),
|
Genero = reader.GetString(4),
|
||||||
Foto = reader.GetString(5),
|
Descricao = reader.GetString(5),
|
||||||
Keywords = reader.GetString(6),
|
Foto = reader.GetString(6),
|
||||||
Ativo = reader.GetBoolean(7),
|
Keywords = reader.GetString(7),
|
||||||
CriadoEm = reader.GetDateTime(8),
|
Ativo = reader.GetBoolean(8),
|
||||||
AtualizadoEm = reader.GetDateTime(9),
|
CriadoEm = reader.GetDateTime(9),
|
||||||
|
AtualizadoEm = reader.GetDateTime(10),
|
||||||
};`}</code></pre>
|
};`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Assim como na listagem, <code>await cmd.ExecuteReaderAsync()</code> é chamado para ler os resultados da consulta.
|
Assim como na listagem, <code>await cmd.ExecuteReaderAsync()</code> é chamado para ler os resultados da consulta.
|
||||||
Como esperamos que só haja um registro com aquele ISBN, executamos <code>await reader.ReadAsync()</code> apenas uma vez.
|
Como esperamos que só haja um registro com aquele Id, executamos <code>await reader.ReadAsync()</code> apenas uma vez.
|
||||||
Se este método retorna <code>false</code>, é por que nenhum registro foi encontrado com aquele ISBN. Neste caso, lançamos um erro.
|
Se este método retorna <code>false</code>, é por que nenhum registro foi encontrado com esta chave primária. Neste caso, lançamos um erro.
|
||||||
Do contrário, utilizamos os métodos de leitura do registro lido para montar um objeto <code>Livro</code> que será retornado.
|
Do contrário, utilizamos os métodos de leitura do registro lido para montar um objeto <code>Livro</code> que será retornado.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -448,10 +455,10 @@ return new()
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`// Obtém os dados de um livro individual.
|
<pre><code>{`// Obtém os dados de um livro individual.
|
||||||
app.MapGet("/livros/{isbn}", async (string isbn) =>
|
app.MapGet("/livros/{id}", async (long id) =>
|
||||||
{
|
{
|
||||||
var repo = new LivroRepository();
|
var repo = new LivroRepository();
|
||||||
var res = await repo.Obter(isbn);
|
var res = await repo.Obter(id);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
});`}</code></pre>
|
});`}</code></pre>
|
||||||
@ -492,11 +499,6 @@ app.MapGet("/livros/{isbn}", async (string isbn) =>
|
|||||||
AtualizadoEm = default,
|
AtualizadoEm = default,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (livro.Isbn == "")
|
|
||||||
{
|
|
||||||
throw new Exception("O ISBN do livro é obrigatório.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (livro.Titulo == "")
|
if (livro.Titulo == "")
|
||||||
{
|
{
|
||||||
throw new Exception("O título do livro é obrigatório.");
|
throw new Exception("O título do livro é obrigatório.");
|
||||||
@ -570,12 +572,7 @@ app.MapGet("/livros/{isbn}", async (string isbn) =>
|
|||||||
Fazemos isso nos campos do objeto <code>livro</code> para garantir que nenhum deles seja nulo, já que no banco de dados, todos os campos da tabela são <code>NOT NULL</code>.
|
Fazemos isso nos campos do objeto <code>livro</code> para garantir que nenhum deles seja nulo, já que no banco de dados, todos os campos da tabela são <code>NOT NULL</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`if (livro.Isbn == "")
|
<pre><code>{`if (livro.Titulo == "")
|
||||||
{
|
|
||||||
throw new Exception("O ISBN do livro é obrigatório.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (livro.Titulo == "")
|
|
||||||
{
|
{
|
||||||
throw new Exception("O título do livro é obrigatório.");
|
throw new Exception("O título do livro é obrigatório.");
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
@ -635,14 +632,14 @@ app.MapPost("/livros", async (Livro livro) =>
|
|||||||
O método de edição é similar ao de criação.
|
O método de edição é similar ao de criação.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`public async Task<Livro> Editar(string isbn, Livro dados)
|
<pre><code>{`public async Task<Livro> Editar(long id, Livro dados)
|
||||||
{
|
{
|
||||||
using var conn = new MySqlConnection(ConnString);
|
using var conn = new MySqlConnection(ConnString);
|
||||||
using var cmd = conn.CreateCommand();
|
using var cmd = conn.CreateCommand();
|
||||||
|
|
||||||
await conn.OpenAsync();
|
await conn.OpenAsync();
|
||||||
|
|
||||||
var livro = await Obter(isbn);
|
var livro = await Obter(id);
|
||||||
|
|
||||||
livro.Titulo = dados.Titulo?.Trim() ?? "";
|
livro.Titulo = dados.Titulo?.Trim() ?? "";
|
||||||
livro.Autor = dados.Autor?.Trim() ?? "";
|
livro.Autor = dados.Autor?.Trim() ?? "";
|
||||||
@ -656,10 +653,10 @@ app.MapPost("/livros", async (Livro livro) =>
|
|||||||
@"
|
@"
|
||||||
UPDATE Livro SET
|
UPDATE Livro SET
|
||||||
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
|
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
|
||||||
WHERE Isbn=@isbn
|
WHERE Id=@id
|
||||||
";
|
";
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("isbn", isbn);
|
cmd.Parameters.AddWithValue("id", id);
|
||||||
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
|
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
|
||||||
cmd.Parameters.AddWithValue("autor", livro.Autor);
|
cmd.Parameters.AddWithValue("autor", livro.Autor);
|
||||||
cmd.Parameters.AddWithValue("genero", livro.Genero);
|
cmd.Parameters.AddWithValue("genero", livro.Genero);
|
||||||
@ -677,7 +674,7 @@ app.MapPost("/livros", async (Livro livro) =>
|
|||||||
O método recebe dois parâmetros, um isbn que identifica o livro que será editado, e um objeto com os novos dados do livro.
|
O método recebe dois parâmetros, um isbn que identifica o livro que será editado, e um objeto com os novos dados do livro.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`var livro = await Obter(isbn);
|
<pre><code>{`var livro = await Obter(id);
|
||||||
|
|
||||||
livro.Titulo = dados.Titulo?.Trim() ?? "";
|
livro.Titulo = dados.Titulo?.Trim() ?? "";
|
||||||
livro.Autor = dados.Autor?.Trim() ?? "";
|
livro.Autor = dados.Autor?.Trim() ?? "";
|
||||||
@ -688,7 +685,7 @@ livro.Keywords = dados.Keywords?.Trim() ?? "";
|
|||||||
livro.AtualizadoEm = DateTime.Now;`}</code></pre>
|
livro.AtualizadoEm = DateTime.Now;`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Chamamos a função <code>Obter(string)</code> que criamos para obter do banco de dados o livro que será editado. Em seguida, atribuímos a este objeto
|
Chamamos a função <code>Obter(long)</code> que criamos para obter do banco de dados o livro que será editado. Em seguida, atribuímos a este objeto
|
||||||
os valores do objeto <code>dados</code>, formatando-os devidamente.
|
os valores do objeto <code>dados</code>, formatando-os devidamente.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -696,10 +693,10 @@ livro.AtualizadoEm = DateTime.Now;`}</code></pre>
|
|||||||
@"
|
@"
|
||||||
UPDATE Livro SET
|
UPDATE Livro SET
|
||||||
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
|
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
|
||||||
WHERE Isbn=@isbn
|
WHERE Id=@id
|
||||||
";
|
";
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("isbn", isbn);
|
cmd.Parameters.AddWithValue("id", id);
|
||||||
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
|
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
|
||||||
cmd.Parameters.AddWithValue("autor", livro.Autor);
|
cmd.Parameters.AddWithValue("autor", livro.Autor);
|
||||||
cmd.Parameters.AddWithValue("genero", livro.Genero);
|
cmd.Parameters.AddWithValue("genero", livro.Genero);
|
||||||
@ -721,10 +718,10 @@ return livro;`}</code></pre>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`// Edita um livro.
|
<pre><code>{`// Edita um livro.
|
||||||
app.MapPut("/livros/{isbn}", async (string isbn, Livro livro) =>
|
app.MapPut("/livros/{id}", async (long id, Livro livro) =>
|
||||||
{
|
{
|
||||||
var repo = new LivroRepository();
|
var repo = new LivroRepository();
|
||||||
var res = await repo.Editar(isbn, livro);
|
var res = await repo.Editar(id, livro);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
});`}</code></pre>
|
});`}</code></pre>
|
||||||
@ -737,15 +734,15 @@ app.MapPut("/livros/{isbn}", async (string isbn, Livro livro) =>
|
|||||||
Portanto, o método de remover será basicamente uma edição.
|
Portanto, o método de remover será basicamente uma edição.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`public async Task Desativar(string isbn)
|
<pre><code>{`public async Task Desativar(long id)
|
||||||
{
|
{
|
||||||
using var conn = new MySqlConnection(ConnString);
|
using var conn = new MySqlConnection(ConnString);
|
||||||
using var cmd = conn.CreateCommand();
|
using var cmd = conn.CreateCommand();
|
||||||
|
|
||||||
await conn.OpenAsync();
|
await conn.OpenAsync();
|
||||||
|
|
||||||
cmd.CommandText = "UPDATE Livro SET Ativo=false WHERE Isbn=@isbn";
|
cmd.CommandText = "UPDATE Livro SET Ativo=false WHERE Id=@id";
|
||||||
cmd.Parameters.AddWithValue("isbn", isbn);
|
cmd.Parameters.AddWithValue("id", id);
|
||||||
|
|
||||||
await cmd.ExecuteNonQueryAsync();
|
await cmd.ExecuteNonQueryAsync();
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
@ -755,11 +752,11 @@ app.MapPut("/livros/{isbn}", async (string isbn, Livro livro) =>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`// Remove um livro.
|
<pre><code>{`// Remove um livro.
|
||||||
app.MapDelete("/livros/{isbn}", async (string isbn) =>
|
app.MapDelete("/livros/{id}", async (long id) =>
|
||||||
{
|
{
|
||||||
var repo = new LivroRepository();
|
var repo = new LivroRepository();
|
||||||
|
|
||||||
await repo.Desativar(isbn);
|
await repo.Desativar(id);
|
||||||
});`}</code></pre>
|
});`}</code></pre>
|
||||||
|
|
||||||
<h2>Finalizando</h2>
|
<h2>Finalizando</h2>
|
||||||
|
|||||||
@ -114,7 +114,7 @@ Donald Knuth - The Art of Computer Programming`}</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
E se desejássemos obter um único livro, identificado pelo seu ISBN. Poderíamos fazer um endpoint:
|
E se desejássemos obter um único livro, identificado pela sua chave primária. Poderíamos fazer um endpoint:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`Request:
|
<pre><code>{`Request:
|
||||||
@ -125,7 +125,7 @@ Response:
|
|||||||
Yasunari Kawabata - Contos da Palma da Mão`}</code></pre>
|
Yasunari Kawabata - Contos da Palma da Mão`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note que agora a URI ficou <code>/livros/<b>9788574481371</b></code> onde <code><b>9788574481371</b></code> é o ISBN do livro, é um dado que o identifica e pode ser uma chave primária.
|
Note que agora a URI ficou <code>/livros/<b>9788574481371</b></code> onde <code><b>9788574481371</b></code> é a chave primária do livro, o dado que o identifica.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -140,7 +140,7 @@ Response:
|
|||||||
200 OK
|
200 OK
|
||||||
|
|
||||||
<livro>
|
<livro>
|
||||||
<isbn>9788574481371</isbn>
|
<id>9788574481371</id>
|
||||||
<titulo>Contos da Palma da Mão</titulo>
|
<titulo>Contos da Palma da Mão</titulo>
|
||||||
<autor>Yasunari Kawabata</autor>
|
<autor>Yasunari Kawabata</autor>
|
||||||
</livro>`}</code></pre>
|
</livro>`}</code></pre>
|
||||||
@ -155,7 +155,7 @@ GET /livros/9788574481371
|
|||||||
Response:
|
Response:
|
||||||
200 Ok
|
200 Ok
|
||||||
{
|
{
|
||||||
"isbn": "9788574481371",
|
"id": "9788574481371",
|
||||||
"titulo": "Contos da Palma da Mão",
|
"titulo": "Contos da Palma da Mão",
|
||||||
"autor": "Yasunari Kawabata"
|
"autor": "Yasunari Kawabata"
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
@ -168,7 +168,6 @@ Response:
|
|||||||
POST /livros
|
POST /livros
|
||||||
|
|
||||||
{
|
{
|
||||||
"isbn": "9780262510875",
|
|
||||||
"titulo": "Structure and Interpretation of Computer Programs",
|
"titulo": "Structure and Interpretation of Computer Programs",
|
||||||
"autor": "Gerald Jay Sussman"
|
"autor": "Gerald Jay Sussman"
|
||||||
}
|
}
|
||||||
@ -176,7 +175,7 @@ POST /livros
|
|||||||
Response:
|
Response:
|
||||||
201 Created
|
201 Created
|
||||||
{
|
{
|
||||||
"isbn": "9780262510875",
|
"id": "9780262510875",
|
||||||
"titulo": "Structure and Interpretation of Computer Programs",
|
"titulo": "Structure and Interpretation of Computer Programs",
|
||||||
"autor": "Gerald Jay Sussman"
|
"autor": "Gerald Jay Sussman"
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
@ -194,7 +193,7 @@ Response:
|
|||||||
PUT /livros/9780262510875
|
PUT /livros/9780262510875
|
||||||
|
|
||||||
{
|
{
|
||||||
"isbn": "9780262510875",
|
"id": "9780262510875",
|
||||||
"titulo": "Structure and Interpretation of Computer Programs, 2nd ed.",
|
"titulo": "Structure and Interpretation of Computer Programs, 2nd ed.",
|
||||||
"autor": "Harold Abelson, Gerald Jay Sussman, Julie Sussman"
|
"autor": "Harold Abelson, Gerald Jay Sussman, Julie Sussman"
|
||||||
}
|
}
|
||||||
@ -202,7 +201,7 @@ PUT /livros/9780262510875
|
|||||||
Response:
|
Response:
|
||||||
200 Ok
|
200 Ok
|
||||||
{
|
{
|
||||||
"isbn": "9780262510875",
|
"id": "9780262510875",
|
||||||
"titulo": "Structure and Interpretation of Computer Programs, 2nd ed.",
|
"titulo": "Structure and Interpretation of Computer Programs, 2nd ed.",
|
||||||
"autor": "Harold Abelson, Gerald Jay Sussman, Julie Sussman"
|
"autor": "Harold Abelson, Gerald Jay Sussman, Julie Sussman"
|
||||||
}`}</code></pre>
|
}`}</code></pre>
|
||||||
@ -243,10 +242,10 @@ Response:
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>GET /livros</code> para obter todos os livros no sistema;</li>
|
<li><code>GET /livros</code> para obter todos os livros no sistema;</li>
|
||||||
<li><code>GET /livros/{`{isbn}`}</code> para obter um único livro, identificado pelo seu ISBN;</li>
|
<li><code>GET /livros/{`{id}`}</code> para obter um único livro, identificado pela sua chave primária;</li>
|
||||||
<li><code>POST /livros</code> para inserir um novo livro;</li>
|
<li><code>POST /livros</code> para inserir um novo livro;</li>
|
||||||
<li><code>PUT /livros/{`{isbn}`}</code> para editar um livro;</li>
|
<li><code>PUT /livros/{`{id}`}</code> para editar um livro;</li>
|
||||||
<li><code>DELETE /livros/{`{isbn}`}</code> para remover um livro.</li>
|
<li><code>DELETE /livros/{`{id}`}</code> para remover um livro.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -285,13 +284,14 @@ app.Run();
|
|||||||
|
|
||||||
public class Livro
|
public class Livro
|
||||||
{
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
public string? Isbn { get; set; }
|
public string? Isbn { get; set; }
|
||||||
public string? Titulo { get; set; }
|
public string? Titulo { get; set; }
|
||||||
public string? Autor { get; set; }
|
public string? Autor { get; set; }
|
||||||
};`}</code></pre>
|
};`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Adicione esta classe no fim do arquivo. Todos os campos são do tipo <code>string?</code>. O <code>?</code> após o tipo determina a <em>nulabilidade</em> daquela propriedade - ou seja, determina se a propriedade pode receber valores nulos.
|
Adicione esta classe no fim do arquivo. Todos os campos, com exceção do <code>Id</code>, são do tipo <code>string?</code>. O <code>?</code> após o tipo determina a <em>nulabilidade</em> daquela propriedade - ou seja, determina se a propriedade pode receber valores nulos.
|
||||||
Desta forma, o compilador consegue te auxiliar gerando avisos quando você faz uma referência a uma variável que pode ser nula sem antes verificá-la, o que, se acontecesse, geraria um erro em tempo de execução.
|
Desta forma, o compilador consegue te auxiliar gerando avisos quando você faz uma referência a uma variável que pode ser nula sem antes verificá-la, o que, se acontecesse, geraria um erro em tempo de execução.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -311,18 +311,21 @@ app.MapGet("/livros", () =>
|
|||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Id = 1,
|
||||||
Isbn = "9780262510875",
|
Isbn = "9780262510875",
|
||||||
Titulo = "Structure and Interpretation of Computer Programs",
|
Titulo = "Structure and Interpretation of Computer Programs",
|
||||||
Autor = "Gerald Jay Sussman"
|
Autor = "Gerald Jay Sussman"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Id = 2,
|
||||||
Isbn = "9780131103627",
|
Isbn = "9780131103627",
|
||||||
Titulo = "C Programming Language: ANSI C Version",
|
Titulo = "C Programming Language: ANSI C Version",
|
||||||
Autor = "Dennis Ritchie, Brian Kerningham"
|
Autor = "Dennis Ritchie, Brian Kerningham"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Id = 3,
|
||||||
Isbn = "9780134190440",
|
Isbn = "9780134190440",
|
||||||
Titulo = "The Go Programming Language",
|
Titulo = "The Go Programming Language",
|
||||||
Autor = "Brian Kerningham"
|
Autor = "Brian Kerningham"
|
||||||
@ -450,14 +453,14 @@ Content-Type: application/json
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`// Edita um livro.
|
<pre><code>{`// Edita um livro.
|
||||||
app.MapPut("/livros/{isbn}", (string isbn, Livro livro) =>
|
app.MapPut("/livros/{id}", (long id, Livro livro) =>
|
||||||
{
|
{
|
||||||
return new { editando = isbn, dados = livro };
|
return new { editando = id, dados = livro };
|
||||||
});`}</code></pre>
|
});`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A url que definimos agora possui um <em>parâmetro</em> definido por <code>"{`{isbn}`}"</code>. Isto significa que este pedaço da
|
A url que definimos agora possui um <em>parâmetro</em> definido por <code>"{`{id}`}"</code>. Isto significa que este pedaço da
|
||||||
url delimitado por chaves pode assumir qualquer valor, por exemplo, <code>PUT /livros/A</code>, <code>PUT /livros/B</code>, etc.
|
url delimitado por chaves pode assumir qualquer valor numérico, por exemplo, <code>PUT /livros/100</code>, <code>PUT /livros/200</code>, etc.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -466,7 +469,7 @@ app.MapPut("/livros/{isbn}", (string isbn, Livro livro) =>
|
|||||||
|
|
||||||
<pre><code>{`### Edita um livro
|
<pre><code>{`### Edita um livro
|
||||||
|
|
||||||
PUT {{url}}/livros/9780321741769
|
PUT {{url}}/livros/1
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
@ -481,17 +484,17 @@ Content-Type: application/json
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Agora, só falta o <code>GET /livros/{`{isbn}`}</code> e o <code>DELETE /livros/{`{isbn}`}</code>:
|
Agora, só falta o <code>GET /livros/{`{id}`}</code> e o <code>DELETE /livros/{`{id}`}</code>:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{`// Obtém os dados de um livro individual.
|
<pre><code>{`// Obtém os dados de um livro individual.
|
||||||
app.MapGet("/livros/{isbn}", (string isbn) =>
|
app.MapGet("/livros/{id}", (long id) =>
|
||||||
{
|
{
|
||||||
return new Livro() { Isbn = isbn };
|
return new Livro() { Id = id };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove um livro.
|
// Remove um livro.
|
||||||
app.MapDelete("/livros/{isbn}", (string isbn) =>
|
app.MapDelete("/livros/{id}", (long id) =>
|
||||||
{
|
{
|
||||||
return Results.NoContent();
|
return Results.NoContent();
|
||||||
});`}</code></pre>
|
});`}</code></pre>
|
||||||
@ -502,12 +505,12 @@ app.MapDelete("/livros/{isbn}", (string isbn) =>
|
|||||||
|
|
||||||
<pre><code>{`### Obtém um livro individual
|
<pre><code>{`### Obtém um livro individual
|
||||||
|
|
||||||
GET {{url}}/livros/9780321741769
|
GET {{url}}/livros/2
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
|
|
||||||
### Remove um livro
|
### Remove um livro
|
||||||
|
|
||||||
DELETE {{url}}/livros/9780321741769
|
DELETE {{url}}/livros/3
|
||||||
Accept: application/json`}</code></pre>
|
Accept: application/json`}</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -519,5 +522,10 @@ Accept: application/json`}</code></pre>
|
|||||||
<p>
|
<p>
|
||||||
O código fonte do projeto até agora pode ser baixado <a href="https://git.gbrl.dev/Gabriel/Biblioteca/archive/etapa2.zip">aqui</a>.
|
O código fonte do projeto até agora pode ser baixado <a href="https://git.gbrl.dev/Gabriel/Biblioteca/archive/etapa2.zip">aqui</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<span>Próximo:</span>
|
||||||
|
<a href="/bd">Conectando com o banco de dados</a>
|
||||||
|
</nav>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
Loading…
x
Reference in New Issue
Block a user