如何为可编辑OData数据源创建RIA Service包

Categories: LightSwitch
Tags: No Tags
Comments: No Comments
Published on: 2011 年 12 月 15 日

[原文发表地址] How to Create a RIA Service Wrapper for an Editable OData Source

[原文发表时间] 2011-10-11 10:39

简介

LightSwitch内置支持SQL服务器和SharePoint数据源。要访问其他数据源,你要自行编写WCF RIA DomainService。这篇博文会教你如何通过将访问OData Service的方法封装到DomainService的方式来读写OData数据源。

对于那些能用于RIA Services和LightSwitch的OData Services有一些限制条件。

复杂类型

虽然OData和RIA Services都在实体上支持复杂类型,但是LightSwitch并不支持。如果实体上出现复杂类型属性,LightSwitch将会在导入实体时,忽略那个属性。有一些变通的方法可以用来处理这种情况,我们会在其他博文中详细讲这个问题。

无外键的导航属性

OData Service可以包含与外键无关联的导航属性。这差不多就是多对多关系,不过也可能出现0.1到多或者1到多的关系。比如,Netflix OData Catalog在Title和Genre间包含一个多对多关系。不幸的是,RIA Service的关联是基于外键的。如果一个OData的关联不是基于外键的话,那么通过RIA Service就没有很好的诠释方法了。

如果一个OData Service包含了这类关联,那么在LightSwitch中就会没有现存的方法来表示。不过,你可以在RIA Service上添加带参数的查询,它可以被LightSwitch调用。使用这个功能,查询就能代表这些不被支持的关联能被实现了。对Netflix来说,例如,你可以在RIA Service上定义查询GetGenresByTitle和GetTitlesByGenre,它可以调用特定的OData导航属性。

为LightSwitch创建OData DomainService包的基本步骤如下:

  1. 创建一个类库项目
  2. 添加与OData Service相关的服务
  3. 为项目添加WCF DomainService
  4. 添加一个metadata类为LightSwitch提供关于引用的Service所实现的类的特定信息。
  5. 为你的DomainService添加查询函数,去显示OData Service上的每个实体类
  6. 为你的DomainService添加函数来实现创建,更新,删除每一个实体类

步骤1-5在如何为OData数据源创建RIA Service包博文中都涉及到了。这篇博文会继续详细介绍并更新在那个博文中所创建的DomainService。

允许LightSwitch指定连接信息

第一篇博文假定OData Service的地址在你的DomainService中是硬编码的。我们现在将修改我们的类来实现在LightSwitch中使用RIA Service时可以指定地址。

LightSwitch中的Add Data Source向导会提示开发者在添加DomainService数据源时需要一个连接字符串。这个连接字符串会以DomainService的类名储存于web.config文件中为项目所用。我们将会修改我们的DomainService使它在初始化时从web.config文件中获取连接信息。

首先添加引用到System.Web和System.Configuration。

clip_image001[4]

为DomainService类添加描述属性。这个描述会在Add Data Source向导中显示,当需要用户输入连接字符串时。

<Description("Specify the address to the ProductCatalog Service")> _

    Public Class ProductService

Inherits DomainService

修改初始化函数来检测使用LightSwitch所指定地址。

Public Overrides Sub Initialize(ByVal context As System.ServiceModel.DomainServices.Server.DomainServiceContext)

MyBase.Initialize(context)

‘Get connection information from the web.config

If Web.Configuration.WebConfigurationManager.ConnectionStrings(GetType(ProductService).FullName) Is Nothing OrElse String.IsNullOrWhiteSpace(Web.Configuration.WebConfigurationManager.ConnectionStrings(GetType(ProductService).FullName).ConnectionString) Then

Throw New Exception("The address to RIA Service must be provided when attaching to this data source from LightSwitch.")

Else

Dim url As String = Web.Configuration.WebConfigurationManager.ConnectionStrings(GetType(ProductService).FullName).ConnectionString

_context = New ProductCatalog.ProductCatalogEntities(New Uri(url))

End If

    End Sub

RIA Service提供Submit 函数

DomainService的Submit函数会在LightSwitch每次要保存和修改数据源时被调用。Submit函数需要处理每一个变更的实体,然后把改动保存到OData Service。

在我们的OData Service中,每个Product都有与之相关的Category。要确保Product和Category之间的关系正确,我们的RIA Service需要优先处理Categories。通过按优先级重新排列变更实体集,然后去处理它们就可以实现了。这个重新排序需要基于每个OData Service的结构来自定义。下列类会处理变更集的排序。

Public Class ProductEntitiesComparer

Inherits Comparer(Of Object)

     Public Overrides Function Compare(x As Object, y As Object) As Integer

If TypeOf x Is ProductCatalog.Product AndAlso TypeOf y Is ProductCatalog.Category Then

Return 1

ElseIf TypeOf x Is ProductCatalog.Category AndAlso TypeOf y Is ProductCatalog.Product Then

Return -1

Else

Return 0

End If

End Function

    End Class

一旦变更集被重新排序,我们就要对变更集中的每一条记录进行处理。通过调用Submit的基类,就能实现这点。Submit的基类简单地针对每一个实体类型分别调用Update,Create和Delete函数。我们会在之后提供这些函数。

在每个记录都处理之后,我们需要在OData Service中保存这些更改。介于一个特定保存可以包括多个记录,这些记录都互相联系,因此我们要用批量模式进行保存。

Public Overrides Function Submit(changeSet As ChangeSet) As Boolean

‘Reorder the change set to ensure that categories are processed before products. Products are dependent on categories.

Dim c As New ChangeSet(changeSet.ChangeSetEntries.OrderBy(Function(entry) entry.Entity, New ProductEntitiesComparer()))

Dim baseResult As Boolean = MyBase.Submit(c)

_context.SaveChanges(Services.Client.SaveChangesOptions.Batch)

Return True

End Function

Category提供CreateUpdateDelete函数

对每一个函数,我们首先要把Category添加到DataServiceContext对象上。对Update和Delete函数,我们还要指定附加对象所发生的操作是什么。函数如下所列:

Public Sub CreateCategory(ByVal c As ProductCatalog.Category)

‘Add the new category to the service reference context

_context.AddObject("Categories", c)

End Sub

Public Sub UpdateCategory(ByVal c As ProductCatalog.Category)

‘Attach the object to the context and specify that it has been updated

_context.AttachTo("Categories", c)

_context.UpdateObject(c)

End Sub

Public Sub DeleteCategory(ByVal c As ProductCatalog.Category)

‘Attach the object to the context and specify that it has been deleted

_context.AttachTo("Categories", c)

_context.DeleteObject(c)

End Sub

Product提供CreateUpdateDelete函数

这些函数和为Category而设的函数很相似。不过,对CreateProduct函数来说,我们需要告知DataServiceContext,在Product和Category之间有一定的关系(连接)。这样就能保证新添加的Product可以正确地与Category相关连。在单边关系中,这个步骤是必要的。

Public Sub CreateProduct(ByVal p As ProductCatalog.Product)

‘Add the new product to the service reference context

_context.AddToProducts(p)

‘Need to set link between Product and Category (to ensure that inserts to the database are ordered correctly)

‘For existing categories, get the category first

If p.Category Is Nothing Then

p.Category = _context.Categories.Where(Function(c) c.ID = p.CategoryID).FirstOrDefault()

End If

‘Set the link between the product and category

_context.SetLink(p, "Category", p.Category)

End Sub

Public Sub UpdateProduct(ByVal p As ProductCatalog.Product)

‘Attach the object to the context and specify that it has been updated

_context.AttachTo("Products", p)

_context.UpdateObject(p)

End Sub

Public Sub DeleteProduct(ByVal p As ProductCatalog.Product)

‘Attach the object to the context and specify that it has been deleted

_context.AttachTo("Products", p)

_context.DeleteObject(p)

End Sub

总结

这个函数可以扩展到OData Service中,任意多种实体类型都可以。唯一需要做的修改就是Submit和Create <Entity>函数。在Submit函数中,变更集需要重新排序,来保证父类在子类前被处理。在Create <Entity>函数中,实体类型间的连接需要指定单边,或子边的关系。

希望你们喜欢!

No Comments - Leave a comment

Leave a comment


Welcome , today is 星期一, 2017 年 03 月 27 日