初探 SQL Server CLR —— 用户定义类型

     学习 SQL Server CLR 没有多久,就遇到了一个让我很郁闷的问题;如何处理当“用户定义类型”中因出现像 string 这样的引用类型而引发地一些问题?

下面是我经过查询相关资料而得出的解决方法(代码所示):

ExpandedBlockStart.gif 用户定义类型
  1  using  System;
  2  using  System.Data;
  3  using  System.Data.SqlClient;
  4  using  System.Data.SqlTypes;
  5  using  Microsoft.SqlServer.Server;
  6 
  7  [Serializable]
  8  [Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = 10 )]
  9  public   struct  AgeGroup : INullable, IBinarySerialize
 10  {
 11       public   override   string  ToString()
 12      {
 13           return  ageGroup;
 14      }
 15 
 16       #region  自动生成
 17 
 18       public   bool  IsNull
 19      {
 20           get
 21          {
 22               return  m_Null;
 23          }
 24      }
 25 
 26       public   static  AgeGroup Null
 27      {
 28           get
 29          {
 30              AgeGroup h  =   new  AgeGroup();
 31              h.m_Null  =   true ;
 32               return  h;
 33          }
 34      }
 35 
 36       #endregion
 37 
 38       public   static  AgeGroup Parse(SqlString s)
 39      {
 40           if  (s.IsNull)
 41               return  Null;
 42          AgeGroup u  =   new  AgeGroup();
 43          u.ageGroup  =  AgeGroup.ComputeAgeGroup(s.Value);
 44           return  u;
 45      }
 46 
 47       ///   <summary>
 48       ///  计算年龄段
 49       ///   </summary>
 50       ///   <param name="s"> 用户输入字串 </param>
 51       ///   <returns></returns>
 52       public   static   string  ComputeAgeGroup( string  s)
 53      {
 54           int  tempInt  =   - 1 ;
 55 
 56           if  ( int .TryParse(s,  out  tempInt))
 57          {
 58               if  (tempInt  >=   0 )
 59              {
 60                   if  (tempInt  <=   6 )
 61                  {
 62                       return   " 童年 " ;
 63                  }
 64                   else   if  (tempInt  >   6   &&  tempInt  <=   17 )
 65                  {
 66                       return   " 少年 " ;
 67                  }
 68                   else   if  (tempInt  >   17   &&  tempInt  <=   40 )
 69                  {
 70                       return   " 青年 " ;
 71                  }
 72                   else   if  (tempInt  >   40   &&  tempInt  <=   65 )
 73                  {
 74                       return   " 中年 " ;
 75                  }
 76                   else
 77                  {
 78                       return   " 老年 " ;
 79                  }
 80              }
 81               else
 82              {
 83                   return   string .Empty;
 84              }
 85          }
 86           else
 87          {
 88               return   string .Empty;
 89          }
 90      }
 91 
 92       //  年龄段名称
 93       public   string  ageGroup;
 94       //  标示是否为空(自动生成)
 95       private   bool  m_Null;
 96 
 97       #region  IBinarySerialize 成员
 98 
 99       public   void  Read(System.IO.BinaryReader r)
100      {
101           this .ageGroup  =  r.ReadString();
102      }
103 
104       public   void  Write(System.IO.BinaryWriter w)
105      {
106          w.Write( this .ageGroup);
107      }
108 
109       #endregion
110  }
111 
112 
113 


 因为“用户定义类型”是以值类型对象的形式来实现的,所以当有像 string 这样的引用类型的时候就会有

     对类型 "Demo_SQLSERVER.AgeGroup" 做标记以进行本机序列化,但是类型 "Demo_SQLSERVER.AgeGroup" 的字段
"ageGroup" 为 string 类型(它是非值类型)...

类似这样的错误信息提示 。

     出现这个错误的原因是,对于int、double等类型的数据,它们直接对应操作系统使用的本机数据类型,例如int和double在C++中都有相应的 类型,实际上在C#和C++中它们的结构都是一样的,因此在序列化的时候可以将这些类型的字段当作本机类型来处理。而对于类类型的字段,例如 string,在操作系统中没有对应的数据类型,因此这些字段不能直接序列化。用户必须手动添加序列化代码,告诉SQL Server如何去序列化这些类型的字段。 

因此,需要实现 IBinarySerialize 接口以告诉 SQL Server 如何去实例化指定的字段。
然而问题又来了:

     对类型 "Demo_SQLSERVER.AgeGroup" 做标记以进行本机序列化,但是类型 "Demo_SQLSERVER.AgeGroup" 的字段 "ageGroup" 对于本机序列化无效。

我们还需要修改 VS 自动给我们生成的特性:

[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]

修改为:

[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = 10 )]

在这里,对于用户自定义的格式序列化,指定 MaxByteSize 属性(表示聚合实例的最大大小的 Int32 值)是必须的;另外,此属性的最大允许值 (8000) 由 MaxByteSizeValue 字段指定。
  需要注意的是,对于指定了用户定义的序列化的聚合,MaxByteSize 是指序列化的数据的总大小。以一个序列化包含 10 个字符 (Char) 的字符串的聚合为例。当使用 BinaryWriter  序列化该字符串时,序列化后的字符串的总大小为 22 个字节:每个 Unicode UTF-16 字符占据的字节数 2 乘以最大字符数 10,再加上序列化二进制流所引入的开销占用的 2 个控制字节。因此,在确定 MaxByteSize 的值时,必须考虑序列化的数据的总大小:二进制形式的序列化数据的大小加上序列化引入的开销。


  到这里,就可以“生成”一下,“部署”到SQL Server 实例里使用自己定义的类型了。


参考资料:
http://technet.microsoft.com/zh-cn/library/ms131069.aspx
http://msdn.microsoft.com/zh-cn/library/microsoft.sqlserver.server.sqluserdefinedaggregateattribute.maxbytesize%28VS.80%29.aspx
http://kb.cnblogs.com/a/1546876/


转载于:https://www.cnblogs.com/gexiaoliang/archive/2010/04/20/1715829.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值