之前写过一个合并字符串的CLR聚合函数,基本是照抄MS的示例,外加了一些处理,已经投入使用很长时间,没什么问题也就没怎么研究,近日想改造一下,遇到一些问题,遂捣鼓一番,有些心得,记录如下。
经打断点调试,聚合类是按如下顺序执行:
public void Accumulate(SqlString str)
{
s = str;
}
public SqlString Terminate()
{
return new SqlString(s);
}
完了?不是还有个Merge方法么,很抱歉,我也不知道这货什么时候才会用到。在我多次调试中,始终没遇到执行Merge的情况。根据MSDN文档所述,我的猜测是,CLR并不保证在一次聚合中都使用同一个聚合类实例,它随时有可能另开一个实例来工作,并利用新开实例的Merge方法将旧实例的数据并入新实例中,完了释放旧实例。不知道这个猜测对不对,撸过高手若清楚,还望指教,谢过先。如果这个猜测没错的话,显然Merge方法要做的就是把旧实例(other)的数据并入当前实例,具体应该怎么写读者应该已心中有数了。要注意的是,如果聚合类是设计为只处理非重复元素的话,那么可以保证在每个实例中存储的元素都是唯一的,但两个实例中的元素却有可能存在相同,在实现Merge时要留意这一点,要确保并入后的数据仍然是唯一的。
目前在我看来,聚合类它虽然在C#中是个类/结构,但处处透着古怪,比如没有执行构造函数,运行期间又要清空类字段并转而采用序列化和反序列化的方式传递状态,使它又不那么像一个正常的类,所以我建议在完全弄清楚它之前,不要使用一些OOP的手法去实现它,比如继承重写什么的,想都不要想,老老实实填空就好。另外,对于文中提出的疑惑,希望得到高手指教,再次谢过。
最后附上一枚改造好的字符串聚合(忽略null、空白、重复字串、移除首尾空白):
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
namespace AhDung.SqlClr
{
[SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
IsInvariantToOrder = true,
MaxByteSize = SqlUserDefinedAggregateAttribute.MaxByteSizeValue)
]
public class JoinString : IBinarySerialize
{
string sptr, result;
Dictionary<string, object> dic;
public void Init()
{
sptr = string.Empty;
dic = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);//忽略大小写
}
public void Accumulate(SqlString str, SqlString separater)
{
if (sptr.Length == 0 && !separater.IsNull && !string.IsNullOrEmpty(separater.Value)) { sptr = separater.Value; }
string s;
if (str.IsNull || (s = str.Value.Trim()).Length == 0 || dic.ContainsKey(s)) { return; }
dic.Add(s, null);
}
public void Merge(JoinString other)
{
foreach (string s in other.dic.Keys)
{
if (dic.ContainsKey(s)) { continue; }
dic.Add(s, null);
}
}
public SqlString Terminate()
{
return new SqlString(result);
}
public void Read(BinaryReader r)
{
result = r.ReadString();
}
public void Write(BinaryWriter w)
{
string[] ss = new string[dic.Count];
dic.Keys.CopyTo(ss, 0);
w.Write(string.Join(sptr, ss));
}
}
}
- 完 -