Skip to content

romuloreis/P4I

Repository files navigation

Projetos desenvolvidos na cadeira de Programação para Internet III

Tópicos semi-diários

Definição de localidade (Locale) e Formatação de datas & números

Globalização e localização (Locale) no ASP.NET Core

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);

Labels Customizados - [Display]

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; }

Semântica da data - [DataType]

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; }

Formato de exebição - [DisplayFormat]

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; }

ViewModel

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

Relações (Apenas Model)

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; }
}

Deletando registros: Comportamentos de exclusão

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

Material

Seeding Service

Projetos feitos em aula atualizados

Material

Material Extra

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages