As melhorias de produtividade para o Entity Framework
Antecedentes
Temos ouvido muito bom feedback sobre a atualização recém-lançado para o Entity Framework no .NET 4. Este lançamento marca um avanço significativo a partir do primeiro lançamento que acompanha o .NET 3.5 SP1. Eu não estou indo para passar o tempo aqui falando sobre o que há de novo, mas você pode conferir aqui para ver por si mesmo.
Com tudo o que disse, ainda há uma série de coisas que podemos fazer para simplificar o processo de escrever código de acesso a dados com o Entity Framework. Temos vindo a prestar atenção aos padrões mais comuns que vemos os desenvolvedores que usam com a EF e foram fabricam cerveja acima de um conjunto de melhorias para o Entity Framework projetado para permitir que desenvolvedores para realizar as mesmas tarefas com menos código e menos conceitos.
Estas melhorias oferecem uma superfície mais limpa e mais simples API que se concentra a sua atenção sobre os cenários mais comuns, mas ainda lhe permite detalhar a funcionalidade mais avançada quando é necessário. Nós esperamos que você vai desfrutar desta experiência simples, mas devemos ser rápidos para assegurar-lhe que esta não é uma nova tecnologia de acesso a dados. Estas melhorias são construídos sobre a mesma tecnologia para mapeamento, LINQ, prestadores e todas as outras partes do Entity Framework. Pense nisso como um caminho rápido para escrever código de acesso a dados usando as convenções sobre configuração, APIs melhor sintonizado e outras técnicas destinadas a reduzir o tempo de desenvolvimento ao usar o EF.
Nesta fase, temos trabalhado através do que nós pensamos que a API do núcleo e funcionalidade deve ser semelhante e gostaria que seu feedback. Existem ainda algumas capacidades, tais como ligação de dados e resolução de simultaneidade que fará com que a API a evoluir à medida que continuamos o processo de design, mas os principais conceitos estão no lugar, por isso é um bom momento para o gabarito.
Apresentando DbContext & DbSet
No coração do Entity Framework melhorias de produtividade são dois novos tipos, DbContext e DbSet . DbContext é uma alternativa simplificada para ObjectContext e é o objecto principal para interagir com uma base de dados usando um modelo específico. DbSet é uma alternativa simplificada para ObjectSet e é utilizado para realizar operações CRUD contra um tipo específico a partir do modelo. Estes novos tipos podem ser usados independentemente de se você criou o seu modelo usando o Entity Designer ou código.
A pergunta óbvia é 'Por que não simplificar ObjectContext e ObjectSet ?' Estamos optando por introduzir esses novos tipos, a fim de, por um lado, preservar a compatibilidade retroativa total com aplicações EF existentes e continuar a tratar toda a avançado cenários que são possíveis dada a flexibilidade existente da EF, enquanto por outro lado simplificar a experiência de usar o EF e sintonizá-la para os casos mais comuns. Nós acreditamos que é fundamental que a experiência de programação EF melhorar em alguns aspectos fundamentais, e ao mesmo tempo estamos absolutamente comprometidos com nossos clientes existentes. O estabelecimento de uma relação de colaboração entre os tipos existentes e os novos tipos nos permite alcançar ambos os requisitos. Além disso, existem maneiras fáceis de obter a ObjectContext e ObjectSet a partir DbContext e DbSet caso você queira mais controle para uma determinada tarefa.
Um ponto que queremos ser muito claros sobre é que esses novos tipos não estão substituindo quaisquer tipos existentes; eles são uma alternativa simplificada que construir sobre os tipos existentes, e como adicionar recursos para o Entity Framework eles estarão sempre disponíveis no ObjectContext / ObjectSet, e eles também estarão disponíveis em DbContext / DbSet se for caso disso.
Vamos perfurar na superfície da API mais tarde, mas primeiro vamos dar uma olhada na experiência de codificação usando esses novos tipos.
Code First Experience
DbContext fornece um padrão simplificado Code First que requer menos código e cuida de algumas preocupações comuns, tais como modelo de caching, provisionamento de banco de dados, criação de esquema e de gerenciamento de conexão. Este padrão simplificada utiliza uma série de convenções para cuidar dessas tarefas e permite ajustes ou primordial deste comportamento quando necessário. Vamos começar usando estas convenções para escrever o código necessário para construir um aplicativo de console que executa acesso a dados usando um modelo:
using
System.Collections.Generic;
using
System.Data.Entity;
namespace
MyDataAccessDemo
{
class
Program
{
static
void Main(string[] args)
{
using (var context =
new ProductContext())
{
var food = new Category { CategoryId = "FOOD" };
context.Categories.Add(food);
var cheese = new
Product { Name = "Cheese" };
cheese.Category =
context.Categories.Find("FOOD");
context.Products.Add(cheese);
context.SaveChanges();
}
}
}
public
class ProductContext : DbContext
{
public
DbSet<Product> Products { get; set;
}
public
DbSet<Category> Categories { get; set;
}
}
public
class Product
{
public
int ProductId { get; set;
}
public
string Name { get; set;
}
public
Category Category { get; set;
}
}
public
class Category
{
public
string CategoryId { get; set;
}
public
string Name { get; set;
}
public
ICollection<Product> Products { get; set;
}
}
}
Que é 100% do código que você escreveria para obter este programa em execução. Sem definição de modelo separada, metadados XML, arquivo de configuração ou qualquer outra coisa é necessária. Convenções são usados para preencher todas estas informações. Obviamente há um pouco acontecendo debaixo das cobertas por isso vamos dar uma olhada em algumas das coisas que está fazendo DbContext automaticamente.
Modelo Descoberta
Durante a construção que digitalizar o contexto derivado para propriedades DbSet e incluir os tipos do modelo. Modelo Descoberta usa a funcionalidade Code First existente para as novas convenções padrão que recentemente escrevi sobre são processados durante a descoberta. Você pode optar por sair de descoberta conjunto, especificando um atributo nas propriedades do conjunto que devem ser ignorados.É claro que haverá momentos em que você quer para descrever um modelo ou mudar o que foi detectado por convenção. Por exemplo, dizer que você tem uma entidade Livro cuja propriedade ISBN é a chave primária, este não será detectado por convenção. Há duas opções aqui; você pode usar anotações de dados para anotar a propriedade em sua definição de classe:
public class Book
{
[Key]
public
string ISBN { get; set;
}
public
string Title { get; set;
}
}
Alternativamente DbContext inclui um método virtual que pode ser substituído a usar o Código Primeira API fluente em ModelBuilder para configurar ainda mais o modelo:
public class ProductContext : DbContext
{
public
DbSet<Book> Books { get; set;
}
protected
override void
OnModelCreating(ModelBuilder
modelBuilder)
{
modelBuilder.Entity<Book>().HasKey(b =>
b.ISBN);
}
}
Modelo Caching
Há alguns custos envolvidos em descobrir o modelo, o processamento de anotações de dados e aplicação de configuração API fluente. Para evitar incorrer esse custo cada vez que um DbContext derivado é instanciado o modelo é armazenado em cache durante a primeira inicialização. O modelo em cache é então re-utilizado cada vez que o mesmo contexto derivado é construído no mesmo domínio de aplicação. Caching modelo pode ser desligado, definindo a propriedade CacheForContextType em ModelBuilder para "falso" no método OnModelCreating.
DbSet Inicialização
Você notará na amostra que nós não atribuir um valor a uma das propriedades DbSet no contexto derivada. Durante a construção DbContext irá verificar o contexto derivado para propriedades DbSet e, se eles expõem um setter público, vai construir uma nova DbSet e atribuí-lo à propriedade. Você pode optar por sair de inicialização conjunto, especificando um atributo sobre as propriedades do conjunto de que não devem ser inicializados.
Você também pode criar instâncias DbSet usando o método () o DbContext.Set se você não deseja expor setters públicas para as propriedades DbSet.
Provisioning banco de dados
Por padrão, o banco de dados é criado e fornecido utilizando SqlClient contra localhost \ SQLEXPRESS e tem o mesmo nome que o contexto derivada. Esta convenção é configurável e é controlado por uma configuração AppDomain que pode ser ajustado ou substituído. Você pode ajustar a convenção SqlClient padrão para se conectar a um banco de dados diferente, substitua-a por uma convenção Sqlce que incluir ou definir sua própria convenção implementando a interface IDbConnectionFactory.
public interface IDbConnectionFactory
{
DbConnection CreateConnection(string databaseName);
}
O IDbConnectionFactory ativo pode ser recuperada ou definida através da propriedade estática, Database.DefaultConnectionFactory.
DbContext também inclui um construtor que aceita uma cadeia para controlar o valor que é passado para a convenção, as fábricas SqlClient e Sqlce permitem que você especifique um nome de banco de dados ou toda a cadeia de conexão.
Antes de ligar para a convenção, DbContext irá verificar no arquivo app / web.config para uma cadeia de conexão com o mesmo nome de seu contexto (ou o valor da cadeia se você usou o construtor que especifica uma string). Se houver uma entrada correspondente, vamos usar isso ao invés de chamar a convenção. Como as entradas de cadeia de conexão também incluem informações sobre o provedor isso permite-lhe atingir vários fornecedores em um único aplicativo.
Finalmente, se você quer controle total sobre suas conexões existe um construtor em DbContext que aceita um DbConnection.
Primeiro banco de dados e Modelo Primeira Experiência
Na última versão do Entity Framework que acompanha o .Net Framework 4.0 e Visual Studio 2010, introduzimos a geração de código baseada T4. T4 permite que você personalize o código que é gerado com base em um modelo que você definiu usando o designer em qualquer banco de dados ou Modelo Primeira, Primeira abordagem. O modelo padrão gera um ObjectContext derivada com um ObjectSet para cada conjunto de entidades no seu modelo.
As melhorias de produtividade também irá incluir um modelo que gera uma DbContext determinada com uma DbSet para cada conjunto de entidades no seu modelo. Isto permite Modelo Primeira e banco de dados primeiro desenvolvedores para fazer uso da superfície API simplificado descrito na próxima seção.
Superfície API
DbContext é o ponto de partida para interagir com o seu modelo. Em comparação com ObjectContext que tem um número muito reduzido de métodos e propriedades que são expostas no nível de raiz. O objetivo é expor apenas os métodos mais comumente usados em DbContext e têm a capacidade de perfurar até APIs mais avançadas. Um exemplo disso é a propriedade de banco de dados que expõe APIs banco de dados relacionados. Nós vamos adicionar mais um par de membros, enquanto trabalhamos através de adicionar o resto da funcionalidade avançada, mas nós queremos mantê-lo o mínimo possível. Na maioria dos casos, você iria trabalhar com um contexto que deriva de DbContext e expõe fortemente digitado propriedades DbSet para os tipos em seu modelo.
public class DbContext :
IDisposable
{
public
DbContext(DbModel model, string
nameOrConnectionString);
public
DbContext(DbModel model, DbConnection existingConnection);
public DbContext(ObjectContext objectContext);
public DbContext(ObjectContext objectContext);
protected
DbContext();
protected
DbContext(string
nameOrConnectionString);
protected
DbContext(DbConnection existingConnection);
public
Database Database { get; }
protected
ObjectContext ObjectContext { get; }
protected
virtual void
OnModelCreating(ModelBuilder
modelBuilder);
public
virtual int
SaveChanges();
public
DbSet Set()
where TEntity : class;
public void Dispose();
}
DbModel Construtores
Esses construtores podem ser utilizados com Banco de Dados Primeiro, Modelo Primeira e Code First desenvolvimento. Eles são utilizados pelo nosso modelo de T4 para banco de dados e Primeiro Modelo primeiro desenvolvimento e também pode ser usado em cenários de código primeiro em que um modelo é construído usando Modelbuilder externamente.
Code First anteriormente continha um tipo ContextBuilder que temos agora dividido em dois componentes, ModelBuilder e DbModel. ModelBuilder é mutável e expõe a API fluente para definir o seu modelo. Modelbuilder cria um tipo de DbModel imutável que pode ser utilizado para construir um ObjectContext ou DbContext. DbModel também pode ser construído a partir de um banco de dados Primeiro ou Modelo Primeira abordagem em que um arquivo edmx é gerado.
ObjectContext Constructor
Se você tiver uma base de código existente que usa ObjectContext e quiser fazer uso da superfície suplente do DbContext em algumas partes de seu código, em seguida, esse construtor permite que você enrole o ObjectContext com a superfície mais simples.Construtores protegidos
Os três construtores protegidas podem ser expostos ou utilizados dentro de um contexto derivado onde você quiser fazer uso do Código Primeira experiência simplificada, que foi explicado na seção "Code First Experience '. Eles são protegidos porque os mecanismos de descoberta modelo, provisionamento de banco de dados e modelo de cache dependem de ter um contexto derivada.Banco de dados
A propriedade de banco de dados expõe um exemplo do novo tipo de banco de dados que contém métodos para interagir com o banco de dados subjacente.
public class Database
{
public
DbConnection Connection { get; }
public
void Create ();
public
bool CreateIfNotExists();
public
bool Exists();
public
static bool
Exists(string
nameOrConnectionString);
public
static bool
Exists(DbConnection
existingConnection);
public
void Delete ();
public
static void
Delete (string
nameOrConnectionString);
public
static void
Delete (DbConnection
existingConnection);
public
bool DeleteIfExists();
public
static bool
DeleteIfExists(string
nameOrConnectionString);
public
static bool
DeleteIfExists(DbConnection
existingConnection);
}
ObjectContext
DbContext usa um ObjectContext internamente e nós torná-lo disponível como uma propriedade protegida apenas no caso de você precisar cair para a API de nível inferior. Você pode usar ou expor a funcionalidade necessária de um DbContext derivada.OnModelCreating
Este membro protegida pode ser substituído ao definir um contexto derivado em desenvolvimento CodeFirst e permite que você ajustar o formato do seu modelo que foi detectado por convenção.SaveChanges
Este método expõe a mesma funcionalidade que SaveChanges sobre ObjectContext e persiste todas as alterações pendentes no banco de dados. Ele representa a unidade de trabalho para o contexto.
Defina
Este método irá criar um DbSet DbSet representa uma coleção de um determinado tipo de entidade em seu modelo, semelhante ao ObjectSet
public class DbSet : IDbSet, IQueryable where TEntity : class
{
public
void Add(TEntity entity);
public
void Remove(TEntity
entity);
public
void Attach(TEntity
entity);
public
TEntity Find(params object[] keyValues);
}
Adicionar, Remover e anexar
Adicionar, Remover e anexar são semelhantes aos AddObject, ExcluirObjeto e Anexar em ObjectSet . Temos renomeado Adicionar e remover para manter DbSet consistente com outros conjuntos no quadro.
Adicionar e anexar agora pode ser chamado em objetos que já são controlados pelo contexto, Adicionar garantirá o objeto está no estado adicionado e anexar o estado inalterado. Isso é útil em n-tier e Web cenários onde você tem um gráfico separado contendo entidades existentes e novos que precisam ser ligado a um contexto.
Por exemplo supor que você tem um novo produto que está ligada a uma categoria existente, nem instância é anexado a um contexto (que podem ter sido devolvido a partir de um cliente distribuído através de uma chamada de serviço web ou construídos a partir de um posto de volta em uma aplicação web). Porque Adicionar e anexar são as operações de gráficos, chamando Adicionar no produto também irá adicionar a categoria. Anteriormente você precisaria cair para APIs de nível inferior (ObjectStateManager.ChangeObjectState) para marcar a categoria como inalterada. Agora, no entanto isto pode ser conseguido chamando Anexar:
public void AddProduct(Product product)
{
using
(var context = new ProductContext())
{
context.Products.Add(product);
context.Categories.Attach(product.Category);
context.SaveChanges();
}
}
Encontrar
O novo método Find irá localizar um objeto com o valor da chave primária fornecido (s). Encontre inicialmente verifica os objetos em memória antes de consultar o banco de dados e é capaz de encontrar entidades adicionais que não foram persistiram até a loja ainda. Se encontrar não localizar uma entidade com a correspondente chave que ela retorna null.
IDbSet
DbSet implementa IDbSet para facilitar a criação de aplicativos testáveis.
public interface IDbSet : IQueryable where TEntity : class
{
void
Add(TEntity entity);
void
Attach(TEntity entity);
void
Remove(TEntity entity);
TEntity Find(params object[]
keyValues);
}
IDbSet
public interface IProductContext
{
IDbSet<Product> Products { get; }
IDbSet<Category> Categories { get; }
}
public class ProductContext : DbContext, IProductContext
{
public
IDbSet<Product> Products { get; set;
}
public
IDbSet<Category> Categories { get; set;
}
}
Resumo
Estas melhorias são projetados para fornecer uma superfície de API mais limpa e mais simples que lhe permite alcançar cenários comuns com facilidade enquanto também permite que você para detalhar a funcionalidade mais avançada, quando necessário. As melhorias construir em cima dos componentes do Entity Framework existentes usando convenções sobre configuração e uma superfície API simplificada.
Nós gostaríamos de ouvir qualquer feedback que você tem sobre a funcionalidade e API superfície proposto.
Rowan Miller
Gerenciador de programa
Equipe ADO.NET Entity Framework
Tradução Alexssandro Lima, +Alexssandrolima Dutra
Link traduzido:
http://blogs.msdn.com/b/efdesign/archive/2010/06/21/productivity-improvements-for-the-entity-framework.aspx?wa=wsignin1.0
Nenhum comentário:
Postar um comentário