一起谈.NET技术,详解ASP.NET MVC 2中的新ADO.NET实体框架

简介:   .NET框架4.0的发行推出了许多优秀的增强功能,其中当首推ADO.NET实体框架。该框架已经克服了以前的许多错误,并提供了一组增强的API,其中包括许多新的LINQ to SQL框架方面的改善。在本文中,我们将使用这些API的功能来创建一个通用版本的数据仓库。

  .NET框架4.0的发行推出了许多优秀的增强功能,其中当首推ADO.NET实体框架。该框架已经克服了以前的许多错误,并提供了一组增强的API,其中包括许多新的LINQ to SQL框架方面的改善。在本文中,我们将使用这些API的功能来创建一个通用版本的数据仓库。

  一、实体框架概述

  实体框架针对数据模型提供了一些更方便的操作方法。默认情况下,设计器可以生成一个描述数据库的模型。

尽管表格间的映射未必都是1:1的映射。每个表格使用一个ObjectSet加以描述,进而ObjectSet对象又提供了相应的方法来创建、更新或反射实体和实体间的关系。实体框架使用一个实体键(这是一个看上去像EntitySet=Customers;CustomerID=4的值)来唯一标识模型内的一个实体及其标识符。使用实体键,我们就有了一个方法来更新对象、从数据库中查询的对象,等等。

  二、创建和更新

  让我们首先来看一个基类示例仓库的实现。我想分别地讨论CRUD操作,首先来学习创建和更新操作。

  清单1:创建/更新操作

 
 
1 . public abstract class BaseRepository < T > : IRepository < T >
2 . where T : EntityObject
3 . {
4 . public virtual bool CreateNew(T entity)
5 . {
6 . if (entity == null )
7 . throw new ArgumentNullException( " entity " );
8 . var ctx = CreateContext();
9 . try
10 . {
11 . ctx.AddObject( this .GetFullEntitySetName(ctx), entity);
12 . ctx.SaveChanges();
13 . return true ;
14 . }
15 . catch (Exception ex) { .. }
16 . }
17 . protected abstract string GetEntitySetName(AdventureWorksObjectContext context);
18 . public virtual bool Update(T entity)
19 . {
20 . if (entity == null )
21 . throw new ArgumentNullException( " entity " );
22 . var ctx = CreateContext();
23 . entity.EntityKey = ctx.CreateEntityKey( this .GetFullEntitySetName(ctx),
24 . entity);
25 . try
26 . {
27 . T oldEntity = (T)ctx.GetObjectByKey(entity.EntityKey);
28 . if (oldEntity == null ) return false ;
29 . ctx.ApplyCurrentValues( this .GetFullEntitySetName(ctx), entity);
30 . ctx.SaveChanges();
31 . return true ;
32 . }
33 . catch (Exception ex) { .. }
34 . }
}

  上述代码中,我们的BaseRepository类使用ObjectContext类(需要使用CreateContext方法创建每一个请求)和AddObject方法实现添加新的对象,而通过使用ObjectContext类和AttachTo方法实现更新现有的对象。对于创建对象而言,我们需要知道要更新哪种类型的方法。使用我们的助理GetFullEntitySetName方法可以很好地处理这个问题。这个方法能够返回要添加的标识实体的对象(一个如DotNetSamplesObjectContext.Customers的值)的标识。

  对于更新一个对象而言,我们遇到了与上下文有关的问题。每个从数据库中查询的对象都使用ObjectStateManager类中的ObjectContext成员进行跟踪。MVC绑定过程实际上已经构建了它自己的对象副本,并通过反射把这些值注入到此对象中。这意味着我们有一个新的对象,而不是附加到ObjectContext上的对象。

  这不是一个大问题,我们首先需要查询旧记录。这将为我们的实体生成一个ObjectStateEntry,并且我们可以成功地执行更新(因为它需要知道旧记录是什么)。该实体还需要使用一个EntityKey实体,提供适当的主键信息(记住,EntityKey是确定出已存在的实体的唯一的方式)。

  最后,调用ApplyCurrentValues能够把MVC框架所创建的新的实体值应用到旧实体上。在这里,我们仍然需要使用实体集的名称来唯一标识它。

  三、元数据

  在上面代码中,我们看到了实体集名称的使用方法,用来确定ADO.NET实体框架中的实体的类型。例如,它可以用于描述Products表和Product实体之间的一个映射。还例如,对于我们的产品信息库来说,它可以执行下列操作以获取实体集。

  清单2—返回产品实体集名称

 
 
1 . protected override Expression < Func < DA.Product, object >>
        GetDefaultSortingExpression()
2 . {
3 . return j => j.ProductID;
4 . }
5 . protected override string GetEntitySetName(AdventureWorksObjectContext context)
6 . {
7 . return context.Products.EntitySet.Name;
8 . }

  我们很快将会看到GetDefaultSortingExpression的使用。请注意,这里的GetFullEntitySetName方法把对象的上下文名称追加到实体集名称的后面,以取得添加,更新等操作对应对象的正确名称。 

  四、数据检索

  一般地,我们还可以执行一些读取操作,如下所示。

  清单3—从数据库读取数据

 
 
1 . protected virtual string GetKeyProperty()
2 . {
3 . PropertyInfo[] properties = typeof (T).GetProperties();
4 . foreach (PropertyInfo property in properties)
5 . {
6 . EdmScalarPropertyAttribute attrib = property.GetCustomAttributes
7 . ( typeof (EdmScalarPropertyAttribute), false ).FirstOrDefault()
          as
EdmScalarPropertyAttribute;
8 . if (attrib != null && attrib.EntityKeyProperty)
9 . return property.Name;
10 . }
11 . return null ;
12 . }
13 . public virtual T Get( int key)
14 . {
15 . string prop = this .GetKeyProperty();
16 . if ( string .IsNullOrEmpty(prop))
17 . return null ;
18 . var ctx = CreateContext();
19 . return (T)ctx.GetObjectByKey( new EntityKey( this .GetFullEntitySetName(ctx),
20 . prop, key));
21 . }
22 . public virtual IQueryable < T > GetAll( int pageIndex, int pageSize)
23 . {
24 . var ctx = CreateContext();
25 . return ctx.CreateObjectSet < T > ( this .GetFullEntitySetName(ctx)).OrderBy(
        
this .GetDefaultSortingExpression())
26 . .Skip(pageIndex * pageSize).Take(pageSize);
27 . }

  默认设计器生成的每个实体类都将把一组属性添加到它对应的每一个字段属性上。其中,EdmScalarPropertyAttribute拥有EntityKeyProperty设置,被设置为true,对应于实体的键字段。这就提供了一种灵活的方式来确定主键列而不需要使用一个lambda表达式手动指定。

  跟踪分析到ObjectContext方法内部,你会发现通过使用实体集名称构造一个对象集合可以取得一个数据实体的所有结果。对象集可以使用LINQ扩展方法来按索引页和大小加以过滤,例如只取得一个包含20个对象的结果集。不幸的是,调用Skip和Take方法需要先对对象进行排序。同样,你需要使用一个自定义Lambda表达式来执行这个排序操作。

  GetObjectByKey方法实际上使用它的键从它的数据库中检索对象。我们可以利用我们的新的GetKeyProperty反射方法来获取主键属性的名称。正如你所看到的,我们不能直接使用这个键而需要使用一个EntityKey对象来检索它。

  五、最终实现

  我可以利用一个类似下面的信息库,并且已经在基类中实现了Create、Delete、Update、Get和GetAll方法。我们只需要关心的是,实现其他的查询操作。

  清单4—最终版本的数据仓库类(其他其他前面已列举的内容)

 
 
1 . public class ProductsRepository : BaseRepository < DA.Product >
2 . {
3 . protected override Expression < Func < DA.Product, object >>
           GetDefaultSortingExpression()
4 . {
5 . return j => j.ProductID;
6 . }
7 . protected override string
         GetEntitySetName(DA.DotNetSamplesObjectContext context)
8 . {
9 . return context.Products.EntitySet.Name;
10 . }
11 . }

  在大多数情况下,代码生成将是最好的选择,有助于减少重复代码,但是,实体框架做了大量的内部基础工作(实现基础代码的自动生成)来实现这些特征支持而无需我们编写任何代码。

  六、结论

  ADO.NET实体框架提供了大量基础功能,节省了开发人员大量的代码编写时间。在本文中,我们讨论了ObjectContext类提供给我们的许多方法,其中包括从后端数据库获取和存入数据,等等。

  最后,我们有理由相信,ADO.NET实体框架必将在ASP.NET MVC框架应用程序开发的数据管理模型开发中发挥越来越大的作用。

目录
相关文章
|
7天前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
20 7
|
7天前
|
Linux C# Android开发
一个开源、跨平台的.NET UI框架 - Avalonia UI
一个开源、跨平台的.NET UI框架 - Avalonia UI
|
7天前
|
机器学习/深度学习 人工智能 算法
ML.NET:一个.NET开源、免费、跨平台的机器学习框架
ML.NET:一个.NET开源、免费、跨平台的机器学习框架
|
7天前
|
消息中间件 开发框架 前端开发
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
|
5天前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
16 0
|
7天前
|
JSON 测试技术 C#
C#/.NET/.NET Core优秀项目框架推荐榜单
C#/.NET/.NET Core优秀项目框架推荐榜单
|
14天前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
52 0
|
14天前
|
API 开发者 Java
API 版本控制不再难!Spring 框架带你玩转多样化的版本管理策略,轻松应对升级挑战!
【8月更文挑战第31天】在开发RESTful服务时,为解决向后兼容性问题,常需进行API版本控制。本文以Spring框架为例,探讨四种版本控制策略:URL版本控制、请求头版本控制、查询参数版本控制及媒体类型版本控制,并提供示例代码。此外,还介绍了通过自定义注解与过滤器实现更灵活的版本控制方案,帮助开发者根据项目需求选择最适合的方法,确保API演化的管理和客户端使用的稳定与兼容。
50 0
|
14天前
|
开发者 C# Android开发
Xamarin 与 .NET:解锁现代化移动应用开发的超级武器——深入探讨C#与.NET框架如何赋能跨平台应用,实现高效编码与卓越性能
【8月更文挑战第31天】Xamarin 与 .NET 的结合为开发者提供了强大的平台,用于构建现代化移动应用。通过 C# 和 .NET 框架,Xamarin 可以实现一次编写、多平台运行,覆盖 iOS、Android 和 Windows。这种方式不仅节省了开发时间和成本,还保证了应用的一致性和高质量。Xamarin 是一个开源框架,专为跨平台移动应用开发设计,允许使用 C# 语言和 .NET 核心库构建原生应用,并访问各平台特定功能。微软维护的 Xamarin 是 Visual Studio 生态系统的一部分,极大地提高了开发效率。
41 0
|
14天前
|
开发者 Windows Android开发
跨平台开发新选择:揭秘Uno Platform与.NET MAUI优劣对比,帮你找到最适合的框架,告别选择困难症!
【8月更文挑战第31天】本文对比了备受关注的跨平台开发框架Uno Platform与.NET MAUI的特点、优势及适用场景。Uno Platform基于WebAssembly和WebGL技术,支持Windows、iOS、Android及Web平台,而.NET MAUI由微软推出,旨在统一多种UI框架,支持Windows、iOS和Android。两者均采用C#和XAML进行开发,但在性能、平台支持及社区生态方面存在差异。Uno Platform在Web应用方面表现出色,但性能略逊于原生应用;.NET MAUI则接近原生性能,但不支持Web平台。开发者应根据具体需求选择合适的框架。
34 0