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 IQueryable GetFolder()        {            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; }

image

然后,我们再来看在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 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; }

 

.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; }

调试起来看到的效果如下

image

 

虽然解决了问题,但个人感觉Domain Service这个设计值得商榷。如果各位有更好的见解和解决方案,请不吝赐教

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车祸死者家属不来协商赔偿怎么办 26岁想回去当老师了怎么办 面包车排量小空调带不凉快怎么办 科三包过不给退钱人跑了怎么办 护师职称考试成绩单丢了怎么办 河南二级建造师报名地址填错怎么办 山东以前的企业没有消防备案怎么办 重庆渝北初级审核时间过了怎么办 初级职称复核毕业证弄丢了怎么办 杭州公租房选房后变更单位的怎么办 契税交了贷款办不下来怎么办 天津公租房住满5年后怎么办 大江里钓鱼水流太急立不住漂怎么办 房子定金交了不想要了怎么办 房子付了首付不想要了怎么办 三国大时代4王越死了任务怎么办 红米2卡顿反应慢怎么办 国税和地税合并新进的公务员怎么办 买车合格证不给我们要怎么办 初级会计报名信息表填写错误怎么办 跨国快递需要收件人自行清关怎么办 腋下有异味怎么办邀约成都真愛 腋下有异味怎么办犀利成都真愛 腋下有异味怎么办有信成都真愛 成都车牌网上选号次数用完了怎么办 在志愿服务中遇到突发状况怎么办 商铺没有房产证不能办理消防怎么办 亳州办事大厅登录密码忘记了怎么办 户口已迁出结婚证丢了怎么办 户口已迁出多年结婚证丢了怎么办 芜湖长信正式工没转正怎么办辞职 买到9个月库存车怎么办 买到5个月库存车怎么办 把4s店新车撞了怎么办 网址导航已取消打不开网页是怎么办 如果邦华手机充电口有杂物怎么办? 当发生灾害或突发事故时怎么办 物流信息和和收货地址不一样怎么办 小孩手被电梯门夹了怎么办 车管所50选一没看中的号码怎么办 长沙芙蓉区电动车被交警扣了怎么办