Parte 2: Criando os modelos de domínio

por Rick Anderson

Baixar Projeto Concluído

Adicionar modelos

Há três maneiras de abordar o Entity Framework:

  • Primeiro banco de dados: você começa com um banco de dados e o Entity Framework gera o código.
  • Model-first: você começa com um modelo visual e o Entity Framework gera o banco de dados e o código.
  • Code-first: você começa com o código e o Entity Framework gera o banco de dados.

Estamos usando a abordagem code-first, portanto, começamos definindo nossos objetos de domínio como POCOs (objetos CLR simples). Com a abordagem code-first, os objetos de domínio não precisam de nenhum código extra para dar suporte à camada de banco de dados, como transações ou persistência. (Especificamente, eles não precisam herdar da classe EntityObject .) Você ainda pode usar anotações de dados para controlar como o Entity Framework cria o esquema de banco de dados.

Como os POCOs não carregam nenhuma propriedade extra que descreva o estado do banco de dados, eles podem ser facilmente serializados para JSON ou XML. No entanto, isso não significa que você sempre deve expor seus modelos do Entity Framework diretamente aos clientes, como veremos posteriormente no tutorial.

Criaremos os seguintes POCOs:

  • Produto
  • Ordem
  • OrderDetail

Para criar cada classe, clique com o botão direito do mouse na pasta Modelos no Gerenciador de Soluções. No menu de contexto, selecione Adicionar e, em seguida, selecione Classe.

Captura de tela do menu Soluções Explorer da pasta Modelos. O menu Adicionar está aberto e a opção Classe está realçada.

Adicione uma Product classe com a seguinte implementação:

namespace ProductStore.Models
{
    using System.ComponentModel.DataAnnotations;

    public class Product
    {
        [ScaffoldColumn(false)]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        public decimal Price { get; set; }
        public decimal ActualCost { get; set; }
    }
}

Por convenção, o Entity Framework usa a Id propriedade como a chave primária e a mapeia para uma coluna de identidade na tabela de banco de dados. Ao criar uma nova Product instância, você não definirá um valor para Id, porque o banco de dados gera o valor.

O atributo ScaffoldColumn informa ASP.NET MVC para ignorar a Id propriedade ao gerar um formulário de editor. O atributo Obrigatório é usado para validar o modelo. Ele especifica que a Name propriedade deve ser uma cadeia de caracteres não vazia.

Adicione a Order classe :

namespace ProductStore.Models
{
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    public class Order
    {
        public int Id { get; set; }
        [Required]
        public string Customer { get; set; }

        // Navigation property
        public  ICollection<OrderDetail> OrderDetails { get; set; }
    }
}

Adicione a OrderDetail classe :

namespace ProductStore.Models
{
    public class OrderDetail
    {
        public int Id { get; set; }
        public int Quantity { get; set; }
        public int OrderId { get; set; }
        public int ProductId { get; set; }

        // Navigation properties
        public Product Product { get; set; }
        public Order Order { get; set; }
    }
}

Relações de Chave Externa

Um pedido contém muitos detalhes do pedido e cada detalhe do pedido refere-se a um único produto. Para representar essas relações, a OrderDetail classe define as propriedades denominadas OrderId e ProductId. O Entity Framework inferirá que essas propriedades representam chaves estrangeiras e adicionará restrições de chave estrangeira ao banco de dados.

Captura de tela dos menus do Visual Studio para as classes Orders, Products e OrderDetails.

As Order classes e OrderDetail também incluem propriedades de "navegação", que contêm referências aos objetos relacionados. Dado um pedido, você pode navegar até os produtos na ordem seguindo as propriedades de navegação.

Compile o projeto agora. O Entity Framework usa reflexão para descobrir as propriedades dos modelos, portanto, requer um assembly compilado para criar o esquema de banco de dados.

Configurar os formatadores de Media-Type

Um formatador de tipo de mídia é um objeto que serializa seus dados quando a API Web grava o corpo da resposta HTTP. Os formatadores internos dão suporte à saída JSON e XML. Por padrão, ambos os formatadores serializam todos os objetos por valor.

A serialização por valor criará um problema se um grafo de objeto contiver referências circulares. Esse é exatamente o caso com as Order classes e OrderDetail , porque cada uma tem uma referência à outra. O formatador seguirá as referências, gravando cada objeto por valor e entrará em círculos. Portanto, precisamos alterar o comportamento padrão.

Em Gerenciador de Soluções, expanda a pasta App_Start e abra o arquivo chamado WebApiConfig.cs. Adicione o código a seguir à classe WebApiConfig:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // New code:
        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling =
            Newtonsoft.Json.PreserveReferencesHandling.Objects;

        config.Formatters.Remove(config.Formatters.XmlFormatter);
    }
}

Esse código define o formatador JSON para preservar referências de objeto e remove totalmente o formatador XML do pipeline. (Você pode configurar o formatador XML para preservar referências de objeto, mas é um pouco mais de trabalho e só precisamos de JSON para este aplicativo. Para obter mais informações, consulte Manipulando referências de objeto circular.)