RIA Service中对于递归实体类型处理的问题及解决方案
来源:互联网 发布:brew install node 6 编辑:程序博客网 时间:2024/06/07 02:00
故事是这样开始的:
我们在开发一个Silverlight应用程序的时候使用到了RIA Service,我们需要通过该服务公开一个对文件夹的查询操作。
为此,我们建立了如下的一个实体类型
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Runtime.Serialization;using System.ComponentModel.DataAnnotations;using System.ServiceModel.DomainServices.Server;namespace DomainServiceSample.Web{ [DataContract]//必须声明类别为DataContract public class Folder { [DataMember]//必须声明属性为DataMember [Key]//一个用于DomainService的Entity必须有一个Key public Guid ID { get; set; } [DataMember] public string Name { get; set; } [DataMember]
public Folder[] SubFolder { get; set; } }}
【注意】上面其实是有一个递归的类型,也就是Folder里面又包含Folder
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
然后,我们创建了一个DomainService
namespace DomainServiceSample.Web{ using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.ServiceModel.DomainServices.Hosting; using System.ServiceModel.DomainServices.Server; // TODO: Create methods containing your application logic. [EnableClientAccess()] public class SampleDomainService : DomainService { [Query] public IQueryableGetFolder() { var folder = new Folder() { ID = Guid.NewGuid(), Name = "Level 1 Folder" }; var subFolders = new[]{ new Folder(){ID=Guid.NewGuid(),Name="Level 2 Folder"}, new Folder(){ID=Guid.NewGuid(),Name="Level 2 Folder 2"} }; folder.SubFolder = subFolders; return new[] { folder }.AsQueryable(); } }}
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }这个代码没有什么特别的,我们计划向客户端发送的结果是一个Folder,但同时它包含了两个子Folder。
编写上面两个类型很顺利,然后我们生成项目,因为使用了Domain Service,所以在Silverlight应用程序中会得到一个自动生成的类型
我们打开那个文件,确实里面是有一个Folder的类型
////// The 'Folder' entity class. /// [DataContract(Namespace="http://schemas.datacontract.org/2004/07/DomainServiceSample.Web")] public sealed partial class Folder : Entity { private Guid _id; private string _name; #region Extensibility Method Definitions /// /// This method is invoked from the constructor once initialization is complete and /// can be used for further object setup. /// partial void OnCreated(); partial void OnIDChanging(Guid value); partial void OnIDChanged(); partial void OnNameChanging(string value); partial void OnNameChanged(); #endregion /// /// Initializes a new instance of the class. /// public Folder() { this.OnCreated(); } /// /// Gets or sets the 'ID' value. /// [DataMember()] [Editable(false, AllowInitialValue=true)] [Key()] [RoundtripOriginal()] public Guid ID { get { return this._id; } set { if ((this._id != value)) { this.OnIDChanging(value); this.ValidateProperty("ID", value); this._id = value; this.RaisePropertyChanged("ID"); this.OnIDChanged(); } } } /// /// Gets or sets the 'Name' value. /// [DataMember()] public string Name { get { return this._name; } set { if ((this._name != value)) { this.OnNameChanging(value); this.RaiseDataMemberChanging("Name"); this.ValidateProperty("Name", value); this._name = value; this.RaiseDataMemberChanged("Name"); this.OnNameChanged(); } } } /// /// Computes a value from the key fields that uniquely identifies this entity instance. /// /// An object instance that uniquely identifies this entity instance. public override object GetIdentity() { return this._id; } }
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }但是,让人疑惑的是,这个类型里面并没有包含SubFolder这个属性
这是什么情况呢?难道RIA Service不允许传递这种包含递归类型引用的实体?确实如此。
我目前的解决方法是:
1. 为Folder类型添加一个ParentID属性
2. 为SubFolder设置关联,即子Folder的ParentID设置到父Folder的ID。并且定义他们的关联
3. 使用Include属性标记SubFolder是要包含进来的
所以,这个类型修改为下面这样
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Runtime.Serialization;using System.ComponentModel.DataAnnotations;using System.ServiceModel.DomainServices.Server;namespace DomainServiceSample.Web{ [DataContract]//必须声明类别为DataContract public class Folder { [DataMember]//必须声明属性为DataMember [Key]//一个用于DomainService的Entity必须有一个Key public Guid ID { get; set; } [DataMember] public string Name { get; set; } [DataMember] [Association("Test","ID","ParentID")] [Include] public Folder[] SubFolder { get; set; } [DataMember] public Guid ParentID { get; set; } }}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
然后,我们再来看在Silverlight中生成的那个类型
////// The 'Folder' entity class. /// [DataContract(Namespace="http://schemas.datacontract.org/2004/07/DomainServiceSample.Web")] public sealed partial class Folder : Entity { private Guid _id; private string _name; private Guid _parentID; private EntityCollection _subFolder; #region Extensibility Method Definitions /// /// This method is invoked from the constructor once initialization is complete and /// can be used for further object setup. /// partial void OnCreated(); partial void OnIDChanging(Guid value); partial void OnIDChanged(); partial void OnNameChanging(string value); partial void OnNameChanged(); partial void OnParentIDChanging(Guid value); partial void OnParentIDChanged(); #endregion /// /// Initializes a new instance of the class. /// public Folder() { this.OnCreated(); } /// /// Gets or sets the 'ID' value. /// [DataMember()] [Editable(false, AllowInitialValue=true)] [Key()] [RoundtripOriginal()] public Guid ID { get { return this._id; } set { if ((this._id != value)) { this.OnIDChanging(value); this.ValidateProperty("ID", value); this._id = value; this.RaisePropertyChanged("ID"); this.OnIDChanged(); } } } /// /// Gets or sets the 'Name' value. /// [DataMember()] public string Name { get { return this._name; } set { if ((this._name != value)) { this.OnNameChanging(value); this.RaiseDataMemberChanging("Name"); this.ValidateProperty("Name", value); this._name = value; this.RaiseDataMemberChanged("Name"); this.OnNameChanged(); } } } /// /// Gets or sets the 'ParentID' value. /// [DataMember()] public Guid ParentID { get { return this._parentID; } set { if ((this._parentID != value)) { this.OnParentIDChanging(value); this.RaiseDataMemberChanging("ParentID"); this.ValidateProperty("ParentID", value); this._parentID = value; this.RaiseDataMemberChanged("ParentID"); this.OnParentIDChanged(); } } } /// /// Gets the collection of associated entity instances. /// [Association("Test", "ID", "ParentID")] public EntityCollection SubFolder { get { if ((this._subFolder == null)) { this._subFolder = new EntityCollection (this, "SubFolder", this.FilterSubFolder); } return this._subFolder; } } private bool FilterSubFolder(Folder entity) { return (entity.ParentID == this.ID); } /// /// Computes a value from the key fields that uniquely identifies this entity instance. /// /// An object instance that uniquely identifies this entity instance. public override object GetIdentity() { return this._id; } }
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
这时就看到SubFolder了,而且还包含了很多其他的属性。
最后,我做了一个界面来显示给大家看看效果
MainPage.xaml的内容如下
<UserControl x:Class="DomainServiceSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"> <Grid x:Name="LayoutRoot" Background="White"> <sdk:DataGrid AutoGenerateColumns="True" Margin="16,13,12,12" Name="dataGrid1" ItemsSource="{Binding}" RowDetailsVisibilityMode="Visible"> <sdk:DataGrid.RowDetailsTemplate> <DataTemplate> <sdk:DataGrid AutoGenerateColumns="True" Margin="20,20,20,20" Height="300" ItemsSource="{Binding SubFolder}" /> DataTemplate> sdk:DataGrid.RowDetailsTemplate> sdk:DataGrid> Grid>UserControl>.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
MainPage.xaml.cs的内容如下
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;using DomainServiceSample.Web;namespace DomainServiceSample{ public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { var ctx = new SampleDomainContext(); var op = ctx.Load(ctx.GetFolderQuery()); dataGrid1.DataContext = op.Entities; } }}
同时,服务端的代码我也稍作了修改
namespace DomainServiceSample.Web{ using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.ServiceModel.DomainServices.Hosting; using System.ServiceModel.DomainServices.Server; // TODO: Create methods containing your application logic. [EnableClientAccess()] public class SampleDomainService : DomainService { [Query] public IQueryable.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }GetFolder() { var folder = new Folder() { ID = Guid.NewGuid(), Name = "Level 1 Folder" }; var subFolders = new[]{ new Folder(){ID=Guid.NewGuid(),Name="Level 2 Folder",ParentID=folder.ID}, new Folder(){ID=Guid.NewGuid(),Name="Level 2 Folder 2",ParentID=folder.ID} }; folder.SubFolder = subFolders; return new[] { folder }.AsQueryable(); } }}
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
调试起来看到的效果如下
虽然解决了问题,但个人感觉Domain Service这个设计值得商榷。如果各位有更好的见解和解决方案,请不吝赐教
- RIA Service中对于递归实体类型处理的问题及解决方案
- WCF RIA Service实体嵌套问题(更正一下前面的动态数据集模拟)
- RIA Service 的外键问题搜集
- ria +prism 难解问题之 "返回类型必须是实体或复杂类型、复杂类型的集合或预定义的可序列化类型之一"
- Silverlight中RIA Domain Service处理Relational Data
- Java中对于unsigned byte类型的转换处理
- Java中对于unsigned byte类型的转换处理
- 对于python中出现UnicodeDecodeError问题的解决方案
- Silverlight应用框架雏形:MVVM+WCF RIA Service + 业务逻辑层+自写的实体框架
- 如何创建使用 POCO 定义的实体域服务 WCF RIA Service
- Domain Service,RIA Services使用的几个注意问题
- Ria Service DomainDataSource + datagrid 的新增数据问题
- Javascript中递归造成的堆栈溢出及解决方案
- Javascript中递归造成的堆栈溢出及解决方案
- fastjson:对于Exception中复杂类型(enum,...以及自定义类型)成员的处理
- RIA Service 的 SOAP EndPoint
- 对于Intel汇编语言程序设计中程序编译出现问题及解决方案汇总
- 对于汉诺塔问题的递归解决
- sed直接替换文件内容
- 常见SQL Server导入导出数据的几个工具
- 谈EXPORT_SYMBOL使用
- linux更改用户名
- 【SSAS】Model-First Cube 设计的最佳实践
- RIA Service中对于递归实体类型处理的问题及解决方案
- Linux的五个查找命令
- Linux操作系统挂载U盘和硬盘光驱的问题
- 积分啊,积分啊
- 再谈谈ADO.NET Data Service 数据格式(xml和json)
- 在jquery中处理带有命名空间的XML数据
- Lsnrctl 没反应
- RIA Service 的 SOAP EndPoint
- Linux邮件命令用法