使用LINQ to SQL在N层架构中的应用与问题解决

在现代软件开发中,数据驱动的应用非常普遍,无论是Web应用、Windows应用、Web服务还是网络应用,它们都离不开数据访问层。在设计数据访问层时,一个常见的挑战是决定使用“连接”模式还是“断开连接”模式。选择哪种模式取决于应用需求。如果应用是2层架构,并且对性能有较高要求,那么“连接”模式可能是更合适的选择。然而,对于3层架构,选择“断开连接”模式则更为合理。在3层架构中,业务对象(Business Objects)从中间层传输到客户端层,并且这种通信是双向的,意味着对象会在客户端和服务器之间来回传输。

“连接”模式意味着对象与数据层保持连接,当需要检索详细信息或子对象时,会使用这个连接。而“断开连接”模式则意味着对象被序列化/反序列化,并且与业务对象(BOs)不保持连接。LINQ to SQL在“连接”模式下提供了一个很好的解决方案。生成的ORM使用DataContext来检索信息或子对象。然而,将LINQ to SQL适配到N层架构并不是开箱即用的,需要额外的工作。本文将解释这种方法中遇到的问题以及最佳实践。

使用WCF的LINQ to SQL

.NET 3.0引入了Windows Communication Foundation(WCF),这是一个非常强大的Web服务增强功能。它允许编写更加健壮和可扩展的Web服务。如果使用普通的Web服务与LINQ to SQL生成的对象一起工作,这将不起作用,因为生成的类没有[ISerializable]属性。然而,它们仍然可以使用DataContractSerializer进行序列化,因为它们具有DataContract属性。这使得WCF成为在不同层之间传输对象的便捷方式。

单向与双向序列化

LINQ to SQL生成的对象默认不支持序列化。要改变这一点,需要在LINQ to SQL设计器中将序列化模式更改为“单向”。那么,单向序列化是什么意思呢?首先,让看一下以下数据模型。Category可以有多个Material,Material可以有多个Price。如果使用单向模式,只会生成子关系;Material类将有一个属性Prices,如下所示:

[DataMember(Order=20, EmitDefaultValue=false)] public EntitySet<Price> Prices;

然而,父关系不会被生成,所以不会有指向Category类的关系。这实际上是个问题,因为将错过编写如下代码的机会:

string name = material.Category.Name;

双向序列化的问题是什么?假设使用双向序列化;在这种情况下,Material类将包含对Category类的引用,Category类将包含对Material类的引用。这是一个循环依赖。如果序列化器不够智能以处理这种情况,它将陷入这种循环依赖中。.NET 3.5 SP1中有一个部分解决方案。

使用(IsReference=true)属性在DataContract序列化中

在.NET Framework 3.5 SP1中,对DataContract进行了新的增强,可以使用(IsReference=true)属性进行标记。这将告诉序列化器(DataContractSerializer)这个合约是一个引用,因此它将将其作为引用处理,在这种情况下,它将能够检测循环依赖。现在的问题是,没有人更新LINQ to SQL设计器以添加“双向”序列化的新模式。嗯...这确实是个问题。相信他们会在下一版本的Visual Studio中修复它,但目前,偶像damieng在CodePlex上提供了另一个解决方案:

要在项目中使用该模板,请按照以下步骤操作:

  1. 从上述链接下载它。
  2. 将模板包含在项目中。
  3. 将tt文件重命名为与DBML文件相同的名称。
  4. 打开tt文件,并将SerializeDataContractSP1设置为true。正如之前讨论的,这将生成双向可序列化的对象。
  5. 点击tt文件并选择“运行自定义工具”。
  6. 必须更改原始designer.cs文件的编译选项。将构建操作设置为None,而不是Compile,以避免生成具有相同名称的重复类。

使用加载选项预加载子/相关对象

在LINQ中,类仅在需要时从数据库加载。然而,在断开连接的环境中,可能需要预加载子对象,并一次性将它们全部发送到客户端。需要节省多次访问服务器的往返时间,并在一次访问中加载所有需要的内容。为此,需要使用数据上下文的加载选项。以下代码是一个示例:

DataClasses1DataContext dc1 = new DataClasses1DataContext(); DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Material>(m => m.Category); dlo.LoadWith<Material>(m => m.Prices); dc1.LoadOptions = dlo; return dc1.Materials.ToList();
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485