Se você pretende suportar multiplas línguas na sua aplicação, você deve começar por esse ARTIGO. Aqui também entra questões culturais, como ordem pradrão das datas dd/mm/aaaa ou mm/dd/aaaa, marcador de casa decimal , ou . e símbolo monetário da moeda vigente no país do usuário.
As opções de localidade podem ser definidas dentro método Configure() do arquivo Startup.cs, conforme o exemplo abaixo que define a localidade padrão baseada em english-United States
> Não esqueça de importar
> using System.Globalization;
> using Microsoft.AspNetCore.Localization;
//Instância um objeto CultureInfo
var enUS = new CultureInfo("en-US");
//Instância a opção de localização, com um conjunto de definições
var localizationOption = new RequestLocalizationOptions
{
//Definição da Cultura padrão
DefaultRequestCulture = new RequestCulture(enUS),
SupportedCultures = new List<CultureInfo> { enUS },
SupportedUICultures = new List<CultureInfo> { enUS }
};
//Define o Locale padrão
app.UseRequestLocalization(localizationOption);Podemos personalizar os labels das propriedades dos models por meio da annotation Display. Assim, serão exibidos termos mais adequados nas views.
[Display(Name = "Data de Nascimento")]
public DateTime BirthDate { get; set; }Por padrão o ASP.NET Core vai tratar propriedades do tipo DataTime como sendo dia, mês, ano, hora, minutos. Mas, nem sempre queremos ambas informações (data e hora). Então, podemos personalizar os labels das propriedades dos models por meio da annotation DataType. Assim, serão exibidos termos mais adequados nas views.
No exemplo abaixo definimos que na view essa propriedade vai ser tratada apenas como Data. Note que também podemos usar a annotation DataType para definirmos o comportamento nas views para outros tipos de propriedades, como uma propriedade que armazena um e-mail pode ter o DataType.Email, fazendo com que a view se comporte de maneira mais adequada para esse tipo de dado. Nesse caso do e-mail, o valor da propriedade vai ser mostrado como um link mailto para abrir o seu cliente de e-mail padrão.
[Display(Name = "Data de Nascimento")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }Podemos personalizar os padrões de formatação da exibição dos dados por meio da annotation DisplayFormat. Como por exemplo definir o número de casas decimais que você deseja mostrar ou o formato da data.
/*O valor 0-zero indica o valor do atributo, o qual vai ter a formatação F2,
* a qual é a formatação que define que serão exibidas duas casas decimais*/
[DisplayFormat(DataFormatString ="{0:F2}")]
public double Salary { get; set; }
/*O valor 0-zero indica o valor do atributo, o qual vai ter a formatação dia, mês e ano,
* a qual é a formatação que define que serão exibidas duas casas decimais*/
[DisplayFormat(DataFormatString ="{0:dd/MM/yyyy}")]
public DateTime BirthDate { get; set; }Resumindo, um View Model representa um conjunto de uma ou mais Models e outros dados que serão representados em uma View que necessita exibir determinado conjunto de informações. Importante ressaltar que ViewModel é uma classe para ser usada especificamente em uma view. Com ela é possivel trabalhar com conjuntos de objetos contendo somente as propriedades necessárias de cada entidade/model.
É uma boa prática criar uma pasta ViewModels para armazenar suas classes ViewModels, as quais devem ter o nome relacionado à sua função, seguido da palavra ViewModel, como por exemplo AddClientViewModel, DashboardViewModel.
Após criar a classe do ViewModel, você pode utilizar ele como retorno em algum controlador existente, ou criar um novo controlador. Um exemplo de caso, onde pode-se usar o objeto ViewModel como retorno de um controlador existente, seria uma view onde você quer mostrar propriedades de outras entidades/tabelas/models, como em um formulário único de edição de dados de multiplos Models.
Quer saber mais sobre ViewModel? Recomendo a ler ou assistir os seguintes materiais: - tutorial bem didático de como usar esse recurso - pt-br - Outro tutorial bem didático de como usar esse recurso - inglês - Vídeo bem didático - inglês - Explicação resumida - inglês
> Há três formas de passar dados para a View:
> ViewBag - Sem verificação de erros - erros em runtime
> ViewData - Verificação de erros pré compilação
> Direto via parametro do return IActionResult
> Essas duas syntaxes são equivalentes
> ViewBag.livors = Livros.GetAll();
> ViewData["livros"] = Livros.GetAll();
>
> return View(meus_dados);
> Note que você declara @model com letra minúscula, mas acessa Model com letra maiúscula
Para saber mais sobre relações acesse esse ARTIGO
Lembre-se de definir o comportamento ao ser deletado um registro que tenha relação com outros registros!
Exemplo de código de relação um para um (1-1)
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public Post Post { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}Exemplo de código de relação um para muitos (1-n)
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogImage> BlogImages { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(p => p.BlogImage)
.WithOne(i => i.Blog)
.HasForeignKey<BlogImage>(b => b.BlogForeignKey);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int BlogImageId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogForeignKey { get; set; }
public Blog Blog { get; set; }
}Exemplo de código de relação muitos para muitos (n-n)
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(pt => new { pt.PostId, pt.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}Ao deletar um registro de uma tabela, os registros de outras tabelas que tenham relação com esse registro são impactados. Precisamos garantir a consistência dos dados no banco relacional, sendo assim, devemos definir como tratar o impacto da remoção de um registro do banco no DBContext. O comportamento da exclusão normalmente deve ser baseado nas exigências do relacionamento, definidas apartir das regras de negócio.
Por exemplo, Em um cenário onde haja uma tabela Post e uma tabela Comentários, qual o comportamento mais adequado ao excluir um registro da Tabela Post que tenha vários comentários (Tabela Comentários tem uma chave estrangeira da table Post)?
- Deletar o registro de Post e todos os registros relacionados da tabela Comentários?
- Deletar o registro de Post e definir o valor NULL para a chave estrangeira desse registro em Comentários?
- Não permitir a exlusão do registro da tabela Post?
Clique aqui para ver um código de exemplo!
Você também pode fazer download do código aqui
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public List<Post> Posts { get; set; } = new List<Post>();
} public class Comment
{
public int CommentId { get; set; }
public string Content { get; set; }
/*a exclamação após a palavra int indica que esse campo é opcional,
sendo assim, podemos apagar o post em que esse comentário foi feito grandes impactos.
Nesse caso, os comentários ficariam orfãos, não tendo relação com nenhuma postagem.*/
public int? PostId { get; set; }
public Post Post { get; set; }
} public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
/*Relação entre a postagem e seu autor.
O campo AuthorId torna-se obrigatório por padrão,
afinal o framework entende que ele é uma chave estrangeira,
sendo assim, até podemos apagar o autor de uma postagem, porém isso terá um impacto nas
postagens feitas pelo autor.
Nesse caso, poderiamos deletar as postagens do autor ou definir o campo AuthorId como NULL,
já que o mesmo é um campo obrigatório*/
public int AuthorId { get; set; }
public Author Author { get; set; }
public List<Comment> Comments { get; set; } = new List<Comment>();
}Aproveite o exemplo para alterar o comportamento de delete e testar.
/*Arquivo DBContext*/
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
/*Uma postagem tem um autor, o qual tem várias postagens*/
modelBuilder.Entity<Post>()
.HasOne(p => p.Author)
.WithMany(b => b.Posts)
.OnDelete(DeleteBehavior.Cascade); /*Comportamento ao deletar uma postagem*/
/*Uma postagem vários comentários, os quais são de/pertencem à apenas uma postagem*/
modelBuilder.Entity<Post>()
.HasMany(c => c.Comments)
.WithOne(p => p.Post)
.OnDelete(DeleteBehavior.ClientSetNull);/*Comportamento ao deletar uma postagem*/
/*Uma autor tem vários posts, os quais são de/pertencem à apenas um autor*/
modelBuilder.Entity<Author>()
.HasMany(p => p.Posts)
.WithOne(a => a.Author)
.OnDelete(DeleteBehavior.Cascade);/*Comportamento ao deletar autor*/
}Descubra como fazer isso por meio desse ARTIGO
- Ambeinte
- Criando Projeto
- Criando Department
- Criando Demais Modelos
- Criando Controlador de Vendedores
- Formulário para add Vendedores
- Deletando Vendedores]
- Tipos de notações (resumo)
- Criando Modelos
- Modelagem do banco de dados
- Data Annotations
- Helper Tag - validação
- Série de tutoriais
- Tutorial básico
- Tutorial Básico do zero
- Relações - Ver exclusões
- Tutorial: Criar um modelo de dados complexo - ASP.NET MVC com EF Core
- Many-to-many artigo 1
- Many-to-many artigo 2 **New: ** Consultas
- Paginação, caixa de pesquisa e filtros