【IT168 专稿】.NET框架4.0的发行推出了许多优秀的增强功能,其中当首推ADO.NET实体框架。该框架已经克服了以前的许多错误,并提供了一组增强的API,其中包括许多新的LINQ to SQL框架方面的改善。在本文中,我们将使用这些API的功能来创建一个通用版本的数据仓库。
一、实体框架概述
实体框架针对数据模型提供了一些更方便的操作方法。默认情况下,设计器可以生成一个描述数据库的模型。
尽管表格间的映射未必都是1:1的映射。每个表格使用一个ObjectSet加以描述,进而ObjectSet对象又提供了相应的方法来创建、更新或反射实体和实体间的关系。实体框架使用一个实体键(这是一个看上去像EntitySet=Customers;CustomerID=4的值)来唯一标识模型内的一个实体及其标识符。使用实体键,我们就有了一个方法来更新对象、从数据库中查询的对象,等等。
二、创建和更新
让我们首先来看一个基类示例仓库的实现。我想分别地讨论CRUD操作,首先来学习创建和更新操作。
清单1:创建/更新操作
where T : EntityObject
{
public virtual bool CreateNew(T entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
var ctx = CreateContext();
try
{
ctx.AddObject(this.GetFullEntitySetName(ctx), entity);
ctx.SaveChanges();
return true;
}
catch (Exception ex) { .. }
}
protected abstract string GetEntitySetName(AdventureWorksObjectContext context);
public virtual bool Update(T entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
var ctx = CreateContext();
entity.EntityKey = ctx.CreateEntityKey(this.GetFullEntitySetName(ctx),
entity);
try
{
T oldEntity = (T)ctx.GetObjectByKey(entity.EntityKey);
if (oldEntity == null) return false;
ctx.ApplyCurrentValues(this.GetFullEntitySetName(ctx), entity);
ctx.SaveChanges();
return true;
}
catch (Exception ex) { .. }
}
}
上述代码中,我们的BaseRepository类使用ObjectContext类(需要使用CreateContext方法创建每一个请求)和AddObject方法实现添加新的对象,而通过使用ObjectContext类和AttachTo方法实现更新现有的对象。对于创建对象而言,我们需要知道要更新哪种类型的方法。使用我们的助理GetFullEntitySetName方法可以很好地处理这个问题。这个方法能够返回要添加的标识实体的对象(一个如DotNetSamplesObjectContext.Customers的值)的标识。
对于更新一个对象而言,我们遇到了与上下文有关的问题。每个从数据库中查询的对象都使用ObjectStateManager类中的ObjectContext成员进行跟踪。MVC绑定过程实际上已经构建了它自己的对象副本,并通过反射把这些值注入到此对象中。这意味着我们有一个新的对象,而不是附加到ObjectContext上的对象。
这不是一个大问题,我们首先需要查询旧记录。这将为我们的实体生成一个ObjectStateEntry,并且我们可以成功地执行更新(因为它需要知道旧记录是什么)。该实体还需要使用一个EntityKey实体,提供适当的主键信息(记住,EntityKey是确定出已存在的实体的唯一的方式)。
最后,调用ApplyCurrentValues能够把MVC框架所创建的新的实体值应用到旧实体上。在这里,我们仍然需要使用实体集的名称来唯一标识它。
三、元数据
在上面代码中,我们看到了实体集名称的使用方法,用来确定ADO.NET实体框架中的实体的类型。例如,它可以用于描述Products表和Product实体之间的一个映射。还例如,对于我们的产品信息库来说,它可以执行下列操作以获取实体集。
清单2—返回产品实体集名称
{
return j => j.ProductID;
}
protected override string GetEntitySetName(AdventureWorksObjectContext context)
{
return context.Products.EntitySet.Name;
}
我们很快将会看到GetDefaultSortingExpression的使用。请注意,这里的GetFullEntitySetName方法把对象的上下文名称追加到实体集名称的后面,以取得添加,更新等操作对应对象的正确名称。