Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
por Tom Dykstra
Esta série de tutoriais baseia-se no aplicativo Web da Contoso University criado pela série de tutoriais Getting Started with the Entity Framework 4.0. Se você não concluiu os tutoriais anteriores, como ponto de partida para este tutorial, poderá baixar o aplicativo que teria criado. Você também pode baixar o aplicativo criado pela série de tutoriais completa.
O aplicativo Web de exemplo da Contoso University demonstra como criar aplicativos ASP.NET Web Forms usando o Entity Framework 4.0 e o Visual Studio 2010. O aplicativo de exemplo é um site para uma fictícia Universidade Contoso. Ele inclui funcionalidades como admissão de alunos, criação de cursos e atribuições de instrutor.
O tutorial mostra exemplos em C#. O exemplo para download contém código no C# e no Visual Basic.
Database First
Há três maneiras de trabalhar com dados no Entity Framework: Database First, Model First e Code First. Este tutorial é para Database First. Para obter informações sobre as diferenças entre esses fluxos de trabalho e diretrizes sobre como escolher o melhor para seu cenário, consulte Fluxos de trabalho de desenvolvimento do Entity Framework.
Web Forms
Assim como a série Introdução, esta série de tutoriais usa o modelo ASP.NET Web Forms e pressupõe que você saiba como trabalhar com ASP.NET Web Forms no Visual Studio. Se você não fizer isso, consulte Introdução ao ASP.NET Web Forms 4.5. Se você preferir trabalhar com a estrutura ASP.NET MVC, consulte Introdução ao Entity Framework usando ASP.NET MVC.
Versões de software
Mostrado no tutorial Também funciona com Windows 7 Windows 8 Visual Studio 2010 Visual Studio 2010 Express para Web. O tutorial não foi testado com versões posteriores do Visual Studio. Há muitas diferenças nas seleções de menu, caixas de diálogo e modelos. .NET 4 .NET 4.5 é retrocompatível com o .NET 4, mas o tutorial não foi testado com .NET 4.5. Entity Framework 4 O tutorial não foi testado com versões posteriores do Entity Framework. A partir do Entity Framework 5, o EF passa a usar, por padrão, o DbContext APIintroduzido com o EF 4.1. O controle EntityDataSource foi projetado para usar aObjectContextAPI. Para obter informações sobre como usar o controle EntityDataSource com aDbContextAPI, consulte esta postagem no blog.Perguntas
Se você tiver perguntas que não estejam diretamente relacionadas ao tutorial, poderá postá-las no fórum do ASP.NET Entity Framework, no fórum do Entity Framework e do LINQ to Entities ou StackOverflow.com.
O EntityDataSource controle permite que você crie um aplicativo muito rapidamente, mas normalmente exige que você mantenha uma quantidade significativa de lógica de negócios e lógica de acesso a dados em suas páginas de .aspx . Se você espera que seu aplicativo cresça em complexidade e exija manutenção contínua, você poderá investir mais tempo de desenvolvimento antecipadamente para criar uma estrutura de aplicativos em camadas ou n que seja mais mantenedível. Para implementar essa arquitetura, você separa a camada de apresentação da BLL (camada lógica de negócios) e da DAL (camada de acesso a dados). Uma maneira de implementar essa estrutura é usar o ObjectDataSource controle em vez do EntityDataSource controle. Ao usar o ObjectDataSource controle, você implementa seu próprio código de acesso a dados e, em seguida, o invoca em páginas .aspx usando um controle que tem muitos dos mesmos recursos que outros controles de fonte de dados. Isso permite combinar as vantagens de uma abordagem de n camadas com os benefícios de usar um controle do Web Forms para acesso a dados.
O ObjectDataSource controle também oferece mais flexibilidade de outras maneiras. Como você escreve seu próprio código de acesso a dados, é mais fácil fazer mais do que apenas ler, inserir, atualizar ou excluir um tipo de entidade específico, que são as tarefas que o EntityDataSource controle foi projetado para executar. Por exemplo, você pode executar o registro em log sempre que uma entidade for atualizada, arquivar dados sempre que uma entidade for excluída ou verificar e atualizar automaticamente os dados relacionados conforme necessário ao inserir uma linha com um valor de chave estrangeira.
Classes de repositório e lógica de negócios
Um ObjectDataSource controle funciona invocando uma classe que você cria. A classe inclui métodos que recuperam e atualizam dados e você fornece os nomes desses métodos para o ObjectDataSource controle na marcação. Durante o processamento de renderização ou de postback, o ObjectDataSource chama os métodos que você especificou.
Além das operações CRUD básicas, a classe que você cria para usar com o ObjectDataSource pode precisar executar lógica de negócios quando o ObjectDataSource lê ou atualiza dados. Por exemplo, ao atualizar um departamento, talvez seja necessário validar que nenhum outro departamento tem o mesmo administrador porque uma pessoa não pode ser administrador de mais de um departamento.
Em algumas ObjectDataSource documentações, como a visão geral da Classe ObjectDataSource, o controle chama uma classe conhecida como um objeto de negócios que inclui lógica de negócios e lógica de acesso a dados. Neste tutorial, você criará classes separadas para lógica de negócios e para lógica de acesso a dados. A classe que encapsula a lógica de acesso a dados é chamada de repositório. A classe lógica de negócios inclui métodos de lógica de negócios e métodos de acesso a dados, mas os métodos de acesso a dados chamam o repositório para executar tarefas de acesso a dados.
Você também criará uma camada de abstração entre a BLL e a DAL que facilita o teste de unidade automatizado da BLL. Essa camada de abstração é implementada criando uma interface e usando a interface quando você instancia o repositório na classe de lógica de negócios. Isso possibilita que você forneça à classe de lógica de negócios uma referência a qualquer objeto que implemente a interface do repositório. Para a operação normal, você fornece um objeto de repositório que funciona com o Entity Framework. Para testar, você fornece um objeto de repositório que funciona com dados armazenados de uma maneira que você pode manipular facilmente, como variáveis de classe definidas como coleções.
A ilustração a seguir mostra a diferença entre uma classe de lógica de negócios que inclui lógica de acesso a dados sem um repositório e uma que usa um repositório.
Você começará criando páginas da Web nas quais o ObjectDataSource controle está associado diretamente a um repositório porque ele executa apenas tarefas básicas de acesso a dados. No próximo tutorial, você criará uma classe lógica de negócios com lógica de validação e associará o ObjectDataSource controle a essa classe em vez de à classe de repositório. Você também criará testes de unidade para a lógica de validação. No terceiro tutorial desta série, você adicionará a funcionalidade de classificação e filtragem ao aplicativo.
As páginas criadas neste tutorial funcionam com o Departments conjunto de entidades do modelo de dados que você criou na série de tutoriais de Introdução.
Atualizando o banco de dados e o modelo de dados
Você começará este tutorial fazendo duas alterações no banco de dados, as quais exigem alterações correspondentes ao modelo de dados que você criou nos tutoriais da Entity Framework e do Web Forms . Em um desses tutoriais, você fez alterações no designer manualmente para sincronizar o modelo de dados com o banco de dados após uma alteração de banco de dados. Neste tutorial, você usará a ferramenta Modelo de Atualização do Banco de Dados do designer para atualizar o modelo de dados automaticamente.
Adicionando uma relação ao banco de dados
No Visual Studio, abra o aplicativo Web da Contoso University que você criou na série de tutoriais Introdução ao Entity Framework e ao Web Forms e abra o diagrama de banco de dados SchoolDiagram.
Se você examinar a Department tabela no diagrama de banco de dados, verá que ela tem uma Administrator coluna. Esta coluna é uma chave estrangeira para a Person tabela, mas nenhuma relação de chave estrangeira é definida no banco de dados. Você precisa criar a relação e atualizar o modelo de dados para que o Entity Framework possa lidar automaticamente com essa relação.
No diagrama do banco de dados, clique com o botão direito do mouse na Department tabela e selecione Relações.
Na caixa Relações de Chave Estrangeira, clique em Adicionar e, em seguida, clique no botão de reticências ao lado de Especificação de Tabelas e Colunas.
Na caixa de diálogo Tabelas e Colunas , defina a tabela e o campo da chave primária como Person e PersonIDdefina a tabela e o campo de chave estrangeira como Department e Administrator. (Quando você fizer isso, o nome da relação mudará de FK_Department_Department para FK_Department_Person.)
Clique em OK na caixa Tabelas e Colunas , clique em Fechar na caixa Relações de Chave Estrangeira e salve as alterações. Se você for perguntado se deseja salvar as tabelas Person e Department, clique em Sim.
Observação
Se você excluiu Person linhas que correspondem aos dados que já estão na Administrator coluna, não será possível salvar essa alteração. Nesse caso, use o editor de tabelas no Gerenciador de Servidores para garantir que o Administrator valor em cada Department linha contenha a ID de um registro que realmente existe na Person tabela.
Depois de salvar a alteração, você não poderá excluir uma linha da Person tabela se essa pessoa for administradora do departamento. Em um aplicativo de produção, você forneceria uma mensagem de erro específica quando uma restrição de banco de dados impede uma exclusão ou especificaria uma exclusão em cascata. Para obter um exemplo de como especificar uma exclusão em cascata, consulte The Entity Framework e ASP.NET – Getting Started Part 2.
Adicionando uma exibição ao banco de dados
Na nova página Departments.aspx que você criará, você deseja fornecer uma lista suspensa de instrutores, com nomes no formato "sobrenome, nome", para que os usuários possam selecionar os administradores de departamento. Para tornar mais fácil fazer isso, você criará uma exibição no banco de dados. A visualização será composta apenas pelos dados necessários para a lista suspensa: o nome completo (formatado corretamente) e a chave de registro.
No Gerenciador de Servidores, expanda School.mdf, clique com o botão direito do mouse na pasta Exibições e selecione Adicionar Nova Exibição.
Clique em Fechar quando a caixa de diálogo Adicionar Tabela for exibida e cole a seguinte instrução SQL no painel SQL:
SELECT LastName + ',' + FirstName AS FullName, PersonID
FROM dbo.Person
WHERE (HireDate IS NOT NULL)
Salve o modo de exibição como vInstructorName.
Atualizando o modelo de dados
Na pasta DAL , abra o arquivo SchoolModel.edmx , clique com o botão direito do mouse na superfície de design e selecione Atualizar Modelo do Banco de Dados.
Na caixa de diálogo Escolher Seus Objetos de Banco de Dados , selecione a guia Adicionar e selecione a exibição que você acabou de criar.
Clique em Concluir.
No designer, você vê que a ferramenta criou uma entidade vInstructorName e uma nova associação entre as entidades Department e Person.
Observação
Nas janelas Saída e Lista de Erros , você pode ver uma mensagem de aviso informando que a ferramenta criou automaticamente uma chave primária para o novo vInstructorName modo de exibição. Este comportamento é esperado.
Quando você se refere à nova entidade vInstructorName no código, não deseja usar a convenção de banco de dados de prefixar um "v" minúsculo. Portanto, você renomeará a entidade e o conjunto de entidades no modelo.
Abra o Navegador de Modelos. Você vê vInstructorName listado como um tipo de entidade e uma visão.
Em SchoolModel (não SchoolModel.Store), clique com o botão direito do mouse em vInstructorName e selecione Propriedades. Na janela Propriedades , altere a propriedade Name para "InstructorName" e altere a propriedade Nome do Conjunto de Entidades para "InstructorNames".
Salve e feche o modelo de dados e recompile o projeto.
Usando uma classe de repositório e um controle ObjectDataSource
Crie um novo arquivo de classe na pasta DAL , nomeie-o SchoolRepository.cs e substitua o código existente pelo seguinte código:
using System;
using System.Collections.Generic;
using System.Linq;
using ContosoUniversity.DAL;
namespace ContosoUniversity.DAL
{
public class SchoolRepository : IDisposable
{
private SchoolEntities context = new SchoolEntities();
public IEnumerable<Department> GetDepartments()
{
return context.Departments.Include("Person").ToList();
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
context.Dispose();
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Esse código fornece um único GetDepartments método que retorna todas as entidades no Departments conjunto de entidades. Como você sabe que acessará a Person propriedade de navegação para cada linha retornada, especifique o carregamento antecipado para essa propriedade usando o método Include. A classe também implementa a IDisposable interface para garantir que a conexão de banco de dados seja liberada quando o objeto for descartado.
Observação
Uma prática comum é criar uma classe de repositório para cada tipo de entidade. Neste tutorial, uma classe de repositório para vários tipos de entidade é usada. Para obter mais informações sobre o padrão de repositório, consulte as postagens no blog da equipe do Entity Framework e no blog de Julie Lerman.
O GetDepartments método retorna um IEnumerable objeto em vez de um IQueryable objeto para garantir que a coleção retornada seja utilizável mesmo após o próprio objeto de repositório ser descartado. Um IQueryable objeto pode causar acesso ao banco de dados sempre que é acessado, mas pode ser que o objeto de repositório já tenha sido descartado no momento em que um controle vinculado a dados tenta renderizar os dados. Você pode retornar outro tipo de coleção, como um IList objeto em vez de um IEnumerable objeto. No entanto, retornar um IEnumerable objeto garante que você possa executar tarefas típicas de processamento de lista somente leitura, como foreach loops e consultas LINQ, mas não é possível adicionar ou remover itens na coleção, o que pode implicar que essas alterações seriam mantidas no banco de dados.
Crie uma página Departments.aspx que use a página mestra Site.Master e adicione a seguinte marcação no Content controle chamado Content2:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" >
</asp:ObjectDataSource>
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" >
<Columns>
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True"
ItemStyle-VerticalAlign="Top">
</asp:CommandField>
<asp:DynamicField DataField="Name" HeaderText="Name" SortExpression="Name" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" SortExpression="Budget" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" ItemStyle-VerticalAlign="Top" />
<asp:TemplateField HeaderText="Administrator" SortExpression="Person.LastName" ItemStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label ID="AdministratorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
<asp:Label ID="AdministratorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Essa marcação cria um ObjectDataSource controle que usa a classe de repositório que você acabou de criar e um GridView controle para exibir os dados. O GridView controle especifica comandos Editar e Excluir , mas você ainda não adicionou código para dar suporte a eles.
Várias colunas usam DynamicField controles para que você possa aproveitar a formatação automática de dados e a funcionalidade de validação. Para que eles funcionem, você precisará chamar o EnableDynamicData método no Page_Init manipulador de eventos. (DynamicControl os controles não são usados no campo Administrator porque não funcionam com propriedades de navegação.)
Os Vertical-Align="Top" atributos se tornarão importantes posteriormente quando você adicionar uma coluna que tenha um controle aninhado GridView à grade.
Abra o arquivo Departments.aspx.cs e adicione a seguinte using instrução:
using ContosoUniversity.DAL;
Em seguida, adicione o seguinte manipulador para o evento da Init página:
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsGridView.EnableDynamicData(typeof(Department));
}
Na pasta DAL , crie um novo arquivo de classe chamado Department.cs e substitua o código existente pelo seguinte código:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.DAL
{
[MetadataType(typeof(DepartmentMetaData))]
public partial class Department
{
}
public class DepartmentMetaData
{
[DataType(DataType.Currency)]
[Range(0, 1000000, ErrorMessage = "Budget must be less than $1,000,000.00")]
public Decimal Budget { get; set; }
[DisplayFormat(DataFormatString="{0:d}",ApplyFormatInEditMode=true)]
public DateTime StartDate { get; set; }
}
}
Esse código adiciona metadados ao modelo de dados. Ele especifica que a Budget propriedade da entidade realmente representa a Department moeda, embora seu tipo de dados seja Decimal, e especifica que o valor deve estar entre 0 e US $ 1.000.000,00. Ele também especifica que a StartDate propriedade deve ser formatada como uma data no formato mm/dd/yyyy.
Abra a página Departments.aspx.
Observe que, embora você não tenha especificado uma cadeia de caracteres de formato na marcação de página Departments.aspx para as colunas Orçamento ou Data de Início , a formatação de moeda e data padrão foi aplicada a elas pelos DynamicField controles, usando os metadados fornecidos no arquivo Department.cs .
Adicionando funcionalidade de inserção e exclusão
Abra SchoolRepository.cs, adicione o código a seguir para criar um Insert método e um Delete método. O código também inclui um método chamado GenerateDepartmentID que calcula o próximo valor de chave de registro disponível para uso pelo Insert método. Isso é necessário porque o banco de dados não está configurado para calcular isso automaticamente para a Department tabela.
public void InsertDepartment(Department department)
{
try
{
department.DepartmentID = GenerateDepartmentID();
context.Departments.AddObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
public void DeleteDepartment(Department department)
{
try
{
context.Departments.Attach(department);
context.Departments.DeleteObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
private Int32 GenerateDepartmentID()
{
Int32 maxDepartmentID = 0;
var department = (from d in GetDepartments()
orderby d.DepartmentID descending
select d).FirstOrDefault();
if (department != null)
{
maxDepartmentID = department.DepartmentID + 1;
}
return maxDepartmentID;
}
O método Attach
O método DeleteDepartment invoca o método Attach para reestabelecer o vínculo mantido pelo gerenciador de estado do contexto de objetos entre a entidade na memória e a linha de banco de dados que ela representa. Isso deve ocorrer antes que o método chame o SaveChanges método.
O termo contexto do objeto refere-se à classe do Entity Framework que deriva da ObjectContext classe usada para acessar conjuntos de entidades e entidades. No código deste projeto, a classe é nomeada SchoolEntitiese uma instância dela é sempre nomeada context. O gerenciador de estado do objeto do contexto do objeto é uma classe derivada da ObjectStateManager classe. O contato com o objeto usa o gerenciador de estado do objeto para armazenar objetos de entidade e acompanhar se cada um está em sincronia com sua linha de tabela ou linhas correspondentes no banco de dados.
Quando você lê uma entidade, o contexto do objeto a armazena no gerenciador de estado do objeto e controla se essa representação do objeto está em sincronia com o banco de dados. Por exemplo, se você alterar um valor de propriedade, um sinalizador será definido para indicar que a propriedade que você alterou não está mais em sincronia com o banco de dados. Em seguida, quando você chama o SaveChanges método, o contexto do objeto sabe o que fazer no banco de dados porque o gerenciador de estado do objeto sabe exatamente o que é diferente entre o estado atual da entidade e o estado do banco de dados.
No entanto, esse processo normalmente não funciona em um aplicativo Web, pois a instância de contexto de objeto que lê uma entidade, juntamente com tudo em seu gerenciador de estado de objeto, é descartada depois que uma página é renderizada. A instância de contexto de objeto que deve aplicar alterações é uma nova instância que é criada para processamento de postback. No caso do DeleteDepartment método, o ObjectDataSource controle recria a versão original da entidade para você a partir de valores no estado de exibição, mas essa entidade recriada Department não existe no gerenciador de estado do objeto. Se você chamou o DeleteObject método nessa entidade recriada, a chamada falhará porque o contexto do objeto não sabe se a entidade está em sincronia com o banco de dados. No entanto, chamar o método Attach reestabelece o mesmo acompanhamento entre a entidade recriada e os valores no banco de dados que originalmente eram feitos automaticamente quando a entidade era lida em uma instância anterior do contexto de objeto.
Há momentos em que você não deseja que o contexto do objeto rastreie entidades no gerenciador de estado do objeto e você pode definir sinalizadores para impedir que ele faça isso. Exemplos disso são mostrados em tutoriais posteriores nesta série.
O método SaveChanges
Esta classe de repositório simples ilustra os princípios básicos de como executar operações CRUD. Neste exemplo, o SaveChanges método é chamado imediatamente após cada atualização. Em um aplicativo de produção, talvez você queira chamar o SaveChanges método de um método separado para fornecer mais controle sobre quando o banco de dados é atualizado. (No final do próximo tutorial, você encontrará um link para um white paper que discute a unidade de padrão de trabalho que é uma abordagem para coordenar atualizações relacionadas.) Observe também que, no exemplo, o DeleteDepartment método não inclui código para lidar com conflitos de simultaneidade; o código para fazer isso será adicionado em um tutorial posterior nesta série.
Recuperação dos nomes dos instrutores para seleção ao inserir
Os usuários devem ser capazes de selecionar um administrador a partir da lista suspensa de instrutores ao criar novos departamentos. Portanto, adicione o seguinte código a SchoolRepository.cs para criar um método para recuperar a lista de instrutores usando a exibição que você criou anteriormente:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.InstructorNames.OrderBy("it.FullName").ToList();
}
Criando uma página para inserir departamentos
Crie uma página DepartmentsAdd.aspx que use a página Site.Mestre e adicione a seguinte marcação no Content controle denominado Content2:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository" DataObjectTypeName="ContosoUniversity.DAL.Department"
InsertMethod="InsertDepartment" >
</asp:ObjectDataSource>
<asp:DetailsView ID="DepartmentsDetailsView" runat="server"
DataSourceID="DepartmentsObjectDataSource" AutoGenerateRows="False"
DefaultMode="Insert" OnItemInserting="DepartmentsDetailsView_ItemInserting">
<Fields>
<asp:DynamicField DataField="Name" HeaderText="Name" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" />
<asp:TemplateField HeaderText="Administrator">
<InsertItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" >
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server"
DataSourceID="InstructorsObjectDataSource"
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Esta marcação cria dois controles ObjectDataSource, um para inserir novas entidades Department e outro para recuperar nomes de instrutores para o controle DropDownList usado na seleção de administradores de departamento. A marcação cria um DetailsView controle para inserir novos departamentos e especifica um manipulador para o evento do ItemInserting controle para que você possa definir o valor da Administrator chave estrangeira. No final, há um ValidationSummary controle para exibir mensagens de erro.
Abra DepartmentsAdd.aspx.cs e adicione a seguinte using instrução:
using ContosoUniversity.DAL;
Adicione a seguinte variável de classe e métodos:
private DropDownList administratorsDropDownList;
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsDetailsView.EnableDynamicData(typeof(Department));
}
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
e.Values["Administrator"] = administratorsDropDownList.SelectedValue;
}
O Page_Init método habilita a funcionalidade de Dados Dinâmicos. O manipulador do evento Init do controle DropDownList salva uma referência ao controle, e o manipulador do evento Inserting do controle DetailsView usa essa referência para obter o PersonID valor do instrutor selecionado e atualizar a propriedade de chave estrangeira Administrator da entidade Department.
Execute a página, adicione informações para um novo departamento e clique no link Inserir .
Insira valores para outro novo departamento. Insira um número maior que 1.000.000,00 no campo Orçamento e tab para o próximo campo. Um asterisco aparece no campo e, se você segurar o ponteiro do mouse sobre ele, poderá ver a mensagem de erro que você inseriu nos metadados desse campo.
Clique em Inserir e você verá a mensagem de erro exibida pelo ValidationSummary controle na parte inferior da página.
Em seguida, feche o navegador e abra a página Departments.aspx . Adicione a funcionalidade de exclusão à página Departments.aspx adicionando um DeleteMethod atributo ao ObjectDataSource controle e um DataKeyNames atributo ao GridView controle. As marcas de abertura para esses controles agora serão semelhantes ao seguinte exemplo:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments"
DeleteMethod="DeleteDepartment" >
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID" >
Execute a página.
Exclua o departamento que você adicionou ao executar a página DepartmentsAdd.aspx .
Adicionando funcionalidade de atualização
Abra SchoolRepository.cs e adicione o seguinte Update método:
public void UpdateDepartment(Department department, Department origDepartment)
{
try
{
context.Departments.Attach(origDepartment);
context.ApplyCurrentValues("Departments", department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
Quando você clica em Atualizar na página Departments.aspx , o ObjectDataSource controle cria duas Department entidades para passar para o UpdateDepartment método. Um contém os valores originais que foram armazenados no estado de exibição e o outro contém os novos valores que foram inseridos no GridView controle. O código no método UpdateDepartment passa a entidade Department, que tem os valores originais, para o método Attach para estabelecer o acompanhamento entre a entidade e o que está no banco de dados. Em seguida, o código passa a Department entidade que tem os novos valores para o ApplyCurrentValues método. O contexto do objeto compara os valores antigos e novos. Se um novo valor for diferente de um valor antigo, o contexto do objeto alterará o valor da propriedade. Em SaveChanges seguida, o método atualiza apenas as colunas alteradas no banco de dados. (No entanto, se a função de atualização dessa entidade fosse mapeada para um procedimento armazenado, toda a linha seria atualizada independentemente de quais colunas foram alteradas.)
Abra o arquivo Departments.aspx e adicione os seguintes atributos ao DepartmentsObjectDataSource controle:
UpdateMethod="UpdateDepartment"ConflictDetection="CompareAllValues"
Isso faz com que os valores antigos sejam armazenados no estado de exibição para que possam ser comparados com os novos valores noUpdatemétodo.OldValuesParameterFormatString="orig{0}"
Isso informa ao controle que o nome do parâmetro de valores originais éorigDepartment.
A marcação da tag de abertura do elemento de controle ObjectDataSource agora se assemelha ao seguinte exemplo:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment"
UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="orig{0}" >
Adicione um OnRowUpdating="DepartmentsGridView_RowUpdating" atributo ao GridView controle. Você usará isso para definir o valor da Administrator propriedade com base na linha selecionada pelo usuário em uma lista suspensa. A GridView marca de abertura agora se assemelha ao seguinte exemplo:
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
OnRowUpdating="DepartmentsGridView_RowUpdating">
Adicione um EditItemTemplate controle para a Administrator coluna ao GridView controle, imediatamente após o ItemTemplate controle dessa coluna:
<EditItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" TypeName="ContosoUniversity.DAL.SchoolRepository">
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsObjectDataSource"
SelectedValue='<%# Eval("Administrator") %>'
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init" >
</asp:DropDownList>
</EditItemTemplate>
Esse EditItemTemplate controle é semelhante ao InsertItemTemplate controle na página DepartmentsAdd.aspx . A diferença é que o valor inicial do controle é definido usando o SelectedValue atributo.
Antes do controle GridView, adicione o controle ValidationSummary como você fez na página DepartmentsAdd.aspx.
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Abra Departments.aspx.cs e imediatamente após a declaração de classe parcial, adicione o seguinte código para criar um campo privado para referenciar o DropDownList controle:
private DropDownList administratorsDropDownList;
Em seguida, adicione manipuladores para o controle DropDownList do evento Init e o controle GridView do evento RowUpdating:
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
e.NewValues["Administrator"] = administratorsDropDownList.SelectedValue;
}
O manipulador do Init evento salva uma referência ao DropDownList controle no campo de classe. O manipulador do RowUpdating evento usa a referência para obter o valor inserido pelo usuário e aplicá-lo à Administrator propriedade da Department entidade.
Use a página DepartmentsAdd.aspx para adicionar um novo departamento e, em seguida, execute a página Departments.aspx e clique em Editar na linha que você adicionou.
Observação
Você não poderá editar linhas que não adicionou (ou seja, que já estavam no banco de dados), devido a dados inválidos no banco de dados; os administradores das linhas que foram criadas com o banco de dados são alunos. Se você tentar editar um deles, receberá uma página de erro que relata um erro como 'InstructorsDropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.
Se você inserir um valor de Orçamento inválido e clicar em Atualizar, verá o mesmo asterisco e a mensagem de erro que viu na página Departments.aspx .
Altere um valor de campo ou selecione um administrador diferente e clique em Atualizar. A alteração é exibida.
Com isso, concluímos a introdução ao uso do ObjectDataSource controle para operações CRUD básicas (criar, ler, atualizar, excluir) com o Entity Framework. Você criou um aplicativo simples de n camadas, mas a camada de lógica de negócios ainda está fortemente acoplada à camada de acesso a dados, o que complica o teste de unidade automatizado. No tutorial a seguir, você verá como implementar o padrão de repositório para facilitar o teste de unidade.