转帖地址:http://www.cnblogs.com/sufei/articles/1719060.html
原文章地址:http://www.cnblogs.com/gexiaoliang/archive/2010/04/20/1715829.html
学习 SQL Server CLR 没有多久,就遇到了一个让我很郁闷的问题;如何处理当“用户定义类型”中因出现像 string 这样的引用类型而引发地一些问题?
下面是我经过查询相关资料而得出的解决方法(代码所示):用户定义类型
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize=)]
public struct AgeGroup : INullable, IBinarySerialize
{
public override string ToString()
{
return ageGroup;
}
#region 自动生成
public bool IsNull
{
get
{
return m_Null;
}
}
public static AgeGroup Null
{
get
{
AgeGroup h = new AgeGroup();
h.m_Null = true;
return h;
}
}
#endregion
public static AgeGroup Parse(SqlString s)
{
if (s.IsNull)
return Null;
AgeGroup u = new AgeGroup();
u.ageGroup = AgeGroup.ComputeAgeGroup(s.Value);
return u;
}
/// <summary>
/// 计算年龄段
/// </summary>
/// <param name="s">用户输入字串</param>
/// <returns></returns>
public static string ComputeAgeGroup(string s)
{
int tempInt = -;
if (int.TryParse(s, out tempInt))
{
if (tempInt >= )
{
if (tempInt <= )
{
return "童年";
}
else if (tempInt > && tempInt <= )
{
return "少年";
}
else if (tempInt > && tempInt <= )
{
return "青年";
}
else if (tempInt > && tempInt <= )
{
return "中年";
}
else
{
return "老年";
}
}
else
{
return string.Empty;
}
}
else
{
return string.Empty;
}
}
// 年龄段名称
public string ageGroup;
// 标示是否为空(自动生成)
private bool m_Null;
#region IBinarySerialize 成员
public void Read(System.IO.BinaryReader r)
{
this.ageGroup = r.ReadString();
}
public void Write(System.IO.BinaryWriter w)
{
w.Write(this.ageGroup);
}
#endregion
}
因为“用户定义类型”是以值类型对象的形式来实现的,所以当有像 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 自动给我们生成的特性:
修改为:
在这里,对于用户自定义的格式序列化,指定 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/
如有不妥之处,还望不吝赐教 。