Criação de uma aplicação Web ASP.NET MVC usando Code First Visual Studio > File > New Project… > (Visual C#, Web) ASP.NET MVC 4 Web Application Name: MvcApplication11 Ok Project Template: Internet Application View Engine: Razor Ok Criar o Modelo Models > botão direito do rato: Add > Class… > Name: Filme.cs Add Colocar propriedades dentro da classe Filme, que representam um filme na base de dados. using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication11.Models { public class Filme { public int FilmeId { get; set; } public string Titulo { get; set; } public DateTime Data { get; set; } public string Genero { get; set; } public decimal Preco { get; set; } } } Entity Framework Entity Framework (EF) cria automaticamente a base de dados. A API de acesso a dados que foi desenvolvida para o Code First baseia‐se na classe DbContext. Para o EF coordenar as funcionalidades de gerir os acessos à base de dados, para um dado modelo de dados, temos de criar uma classe derivada da classe DbContext. Nesta classe especificámos que entidades estão incluídas no nosso modelo de dados. Também se podem configurar certos comportamentos do Entity Framework. Criar uma pasta DAL. Dentro desta pasta criar a classe FilmesDbContext derivada de DbContext, que representa o contexto da base de dados, e trata de retribuir (select), guardar (insert), actualizar (update), e apagar (delete) instâncias da classe Filme na base de dados. MvcApplication11 > botão direito do rato: Add > New Folder > DAL DAL > botão direito do rato: Add > Class… > Name: FilmesDbContext.cs Add Acrescentar using System.Data.Entity; para referenciar DbContext e DbSet. Acrescentar using MvcApplication11.Models; para referenciar a classe Filme. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; using MvcApplication11.Models; namespace MvcApplication11.DAL { public class FilmesDbContext : DbContext { public FilmesDbContext() : base("DefaultConnection"){ } public DbSet<Filme> Filmes { get; set; } } } Este código cria uma propriedade para cada entity set. No EF, um entity set tipicamente corresponde a uma tabela da base de dados, e uma entidade corresponde a uma linha da tabela. Por omissão Entity Framework usa a SqlConnectionFactory definida na secção de configuração do Entity Framework no web.config, que aponta para o .\SQLEXPRESS. Para usar localDb em vez de SQLExpress colocámos um construtor na subclasse de DbContext especificando o nome da connectionString public FilmesDbContext() : base("DefaultConnection") { } Em alternativa, poderíamos definir uma connectionString no web.config, com o nome da classe de contexto. Build > Build Solution Scaffolding para criar Controladores e Vistas Controllers > botão direito do rato: Add > Controller… > Controller name: FilmesController Scaffolding options: MVC controller with read/write actions and views, using Entity Framework Model class: Filme (MvcApplication11.Models) Data context class: FilmesDbContext (MvcApplication11.DAL) Views: Razor (CSHTML) Add Executar a aplicação A base de dados é criada pelo Entity Framework. Na barra de endereços do browser acrescentar /Filmes localhost:xxxx/Filmes clicar Create New Titulo: Data: Genero: Preco: When Harry Met Sally 1/1/1989 Comédia 9.99 Create Botão Edit > Save: Surgem erros de validação de campos. Web.config Colocar no web.config da aplicação, dentro do elemento <system.web> o seguinte elemento <globalization culture="en-US" /> Mudar de: <system.web> <compilation debug="true" targetFramework="4.0" /> … Para: <system.web> <globalization culture="en‐US" /> <compilation debug="true" targetFramework="4.0" /> … Culture contém as regras para línguas e países, tais como, formato de números, símbolos de moedas, etc. Inspecionar a base de dados criada automaticamente Mudar da janela Solution Explorer para a janela Server Explorer. Expandir a base de dados DefaultConnection (MvcApplication11) debaixo de Data Connections. Expandir Tables para ver as tabelas que foram criadas. Em cada tabela > Show Table Data Para criar as tabelas dos serviços de autenticação Executar a aplicação Na barra de endereços do browser acrescentar /Account/Login localhost:xxxx/ Account/Login Inspecionar novamente a base de dados criada. Para usar outras edições do SQL Server, saber a connection string que o entity framework está a usar, e inspeccionar as bases de dados criadas ver Nota no fim deste documento. Método Edit de FilmesController e Vista Edit Classe FilmesController, métodos Edit: // // GET: /Filmes/Edit/5 public ActionResult Edit(int id = 0) { Filme filme = db.Filmes.Find(id); if (filme == null) { return HttpNotFound(); } return View(filme); } // // POST: /Filmes/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(Filme filme) { if (ModelState.IsValid) { db.Entry(filme).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(filme); } O 2.º método Edit é precedido pelo atributo HttpPost, o que especifica que este método só é invocado por pedidos POST. O 1.º método Edit poderia ter o atributo HttpGet, mas não é necessário, porque é assumido por omissão. Este método HttpGet só é invocado por pedidos GET. Todos os métodos que criam, editam ou apagam dados devem ser invocados por POST. Modificar dados usando o método de envio GET cria riscos de segurança para além de violar as boas práticas http que especificam que os pedidos GET não devem mudar o estado da aplicação. Processamento do pedido GET Este método recebe o id do Filme a editar. Caso não receba este parâmetro, id=0, o que evita erro de execução. Se o método Find() encontra o filme, retorna o objecto filme para o template vista. Se não encontra o método, HttpNotFound() é invocado. Processamento do pedido POST O mecanismo Model Binder do framework ASP.NET recebe os valores do formulário enviados por POST, cria um objecto Filme, que é passado como parâmetro ao método de acção Edit. ModelState.IsValid verifica se todos os validadores tiveram sucesso. O objecto Filme já existe na base de dados mas sofreu modificações. O método Entry() retorna o objecto DBEntityEntry desta entidade, fornecendo acesso a informação sobre a entidade e à capacidade de alterar essa informação. O estado do objecto é mudado para modificado. SaveChanges() guarda na base de dados todas as modificações feitas no contexto, executando o comando SQL Update para as entidades com a flag Modified. Todas as colunas da correspondente linha da tabela da base de dados são actualizadas, incluindo as que o utilizador não modificou. Em seguida o controlo é redirigido para o método de acção Index(), que mostra uma listagem dos filmes já com este filme actualizado. Se a validação não teve sucesso o objecto filme que contém os valores recebidos do formulário é retorna para o template vista Edit.cshtml. Template Edit.cshtml @model MvcApplication11.Models.Filme @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Filme</legend> @Html.HiddenFor(model => model.FilmeId) <div class="editor‐label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor‐field"> @Html.EditorFor(model => model.Titulo) @Html.ValidationMessageFor(model => model.Titulo) </div> <div class="editor‐label"> @Html.LabelFor(model => model.Data) </div> <div class="editor‐field"> @Html.EditorFor(model => model.Data) @Html.ValidationMessageFor(model => model.Data) </div> <div class="editor‐label"> @Html.LabelFor(model => model.Genero) </div> <div class="editor‐field"> @Html.EditorFor(model => model.Genero) @Html.ValidationMessageFor(model => model.Genero) </div> <div class="editor‐label"> @Html.LabelFor(model => model.Preco) </div> <div class="editor‐field"> @Html.EditorFor(model => model.Preco) @Html.ValidationMessageFor(model => model.Preco) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") } Nota: Connection Strings para outra edições do SQL Server Se quisermos que o Entity Framework crie a base de dados numa dada edição do Sql Server, podemos acrescentar, no web.config, uma connection string com o nome da subclasse de DbContext criada (FilmesDbContext): 1) Para o Sql Server LocalDb <add name="FilmesDbContext" connectionString="Data Source=(LocalDb)\v11.0; AttachDbFilename=|DataDirectory|\FilmesDb.mdf; Integrated Security=True" providerName="System.Data.SqlClient" /> 2) Para o Sql Server Express <add name="FilmesDBContext" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=Filmes; Integrated Security=True" providerName="System.Data.SqlClient" /> 3) Para o Sql Server Compact Edition <add name="FilmesDBContext" connectionString="Data Source=|DataDirectory|\Repositorio.sdf" providerName="System.Data.SqlServerCe.4.0"/> 4) Para o Sql Server (Full Edition) <add name="FilmesDBContext" connectionString="Data Source=ServerName; Initial Catalog=Filmes; Integrated Security=False; User Id=userid Password=password" providerName="System.Data.SqlClient" /> Saber a Connection String que o Entity Framework está a usar Para saber qual a connectionString que o Entity Framework está a usar podemos adicionar um construtor por omissão à subclasse de DbContext criada: public class FilmesDbContext : DbContext { public FilmesDbContext() : base("DefaultConnection") { string s = Database.Connection.ConnectionString; } public DbSet<Filme> Filmes { get; set; } } Colocando um break point neste construtor e executando a aplicação em modo debug conseguimos observar a connectionString. Usar F11 quando a execução parar no break point. EF 5 e Visual Studio 2012: Visual Studio 2012 instala, por omissão, SQL Server LocalDb. Uma instância LocalDb guarda as bases de dados debaixo do directório App_Data. Explicitando a connectionString Podemos passar a connectionString ao construtor de DbContext: public FilmesDbContext() : base( @="Data Source=.; Initial Catalog=Filmes; Integrated Security=True"){} Ou passar o nome da connectionString colocada no web.config da aplicação: public FilmeDbContext() : base("FilmesDbContext") { } Se o Entity Framework não encontra a connectionString "FilmesDbContext" no ficheiro web.config, assume que "FilmesDbContext" é o nome da base de dados no servidor local Sql Express ou numa instância LocalDb, dependendo da connection factory configurada. Se não se passa qualquer argumento ao construtor de DbContext, Entity Framework procurará uma connectionString com o nome da classe DbContext criada (FilmesDbContext), no web.config da aplicação. Inspecionar a base de dados criada 1) no Sql Server Express Mudar para a janela Server Explorer, botão direito do rato em Data Connections : Add Connection… > Change > Microsoft Sql Server Ok Server name: .\SQLEXPRESS Refresh Use windows Auhentication Select or enter a database name: seleccionar MvcApplication11.Models.FilmesDbContext Test Connection Ok botão direito do rato em Tables > Filmes: Show Table Data 2) no Sql Server Compact Edition Mudar para a janela Server Explorer, botão direito do rato em Data Connections : Add Connection… > Change > Microsoft SQL Server Compact 4.0 (.NET Framework Data Provider for Microsoft SQL Server Compact 4.0) Ok Database: > Browse > …./App_Data/Filmes.sdf Test Connection Ok Janela Server Explorer > Filmes.sdf > botão direito do rato em Tables > Filmes: > Show Table Data