愿你出走半生,归来仍是少年!
环境:.NET FrameWork4.5、ObjectArx 2016 64bit、Entity Framework 6.
在10.扩展数据(XData)中我们讲到每个DbObject有一个XData对象可以存储数据,除此之外每个DbObject对象还有一个ExtensionDictionary(扩展字典)可以进行数据存储。
在使用XData时为方便存取数据在一个实体上需要使用多个RegApplication进行区分,这个就要求在开发时进行提前的RegApp注册,这个比较麻烦;除此之外,据公司在CAD绘图的同事说,以前会有CAD中病毒导致扩展数据丢失的情况,所以可能扩展字典是一个更好的数据存储方式。
除此之外XData数据存储是有上限的(16kb),然而扩展字典通过使用Xrecord(数据扩展记录)可达到2GB的数据存储量。
1.字典
扩展字典继承于DBDictionary 对象,DBDictionary 是CAD中存储非图形对象的容器。字典以两种方式存在,一种是存储在数据库中用来保存整个图纸的数据叫 NameDictionaries(命名对象字典),一种是储存在对象中用于保存对象的信息数据叫 ExtensionDictionary(对象扩展字典)。
2.扩展字典
扩展字典通常以键值对的方式存储数据,其键为文本格式,值为Xrecord(数据扩展记录)。每个DbObject对象在初始状态是并未拥有扩展字典的,需用通过CreateExtensionDictionary方法进行创建,创建后的字典可存储独属于该对象的数据。
通过DBDictionary 对象的SetAt方法,可以将键以及值数据放入到字典中进场存储。下面以String类型的数据进行示例展示。
3.示例
3.1.DbObject扩展字典创建
通过对自身扩展字典的性质进行判断,当为空时进行创建。
/// <summary>
/// 初始化扩展字典,有则跳过,没有创建
/// </summary>
/// <param name="dBObject"></param>
private static void InitExtensionDictionary(this DBObject dBObject)
{
if (dBObject.ExtensionDictionary.IsNull)
{
dBObject.UpgradeOpen();
dBObject.CreateExtensionDictionary();
dBObject.DowngradeOpen();
}
}
3.2.新增键值对
通过构建Xrecord(数据扩展记录)达到数据设置的效果。
/// <summary>
/// 向扩展字典内添加新的数据
/// </summary>
/// <param name="dBObject"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool AddDictionaryItem(this DBObject dBObject, string key, string value)
{
try
{
dBObject.InitExtensionDictionary();
//写模式打开
DBDictionary dic = dBObject.ExtensionDictionary.GetObject(OpenMode.ForWrite) as DBDictionary;
//包含这个key就直接退出
if (dic.Contains(key))
{
return false;
}
//创建记录
Xrecord xrec = new Xrecord();
List<TypedValue> tempData = new List<TypedValue>();
tempData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, value));
using (var rb = new ResultBuffer(tempData.ToArray()))
{
xrec.Data = rb;
}
//添加到字典内
dic.SetAt(key, xrec);
//创建到库
dBObject.Database.TransactionManager.AddNewlyCreatedDBObject(xrec, true);
//关闭
dic.DowngradeOpen();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
3.3.修改/更新键值对
修改字典中已有的键值对数据时,也是通过SetAt方法进行。但是由于数据为Xrecord(数据扩展记录)对象,其链式存在的情况,所以最好使用新的数据进行覆盖并移除原有的数据,不然容易出问题(类似数据保存失败、键直接丢掉等等)。
在修改前还需要进行判断是否存在该键,为保证操作逻辑的正确,不存在的键也不可进行编辑。
/// <summary>
/// 设置字典中的指定Key的所有值
/// </summary>
/// <param name="dBObject"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool SetDictionaryItem(this DBObject dBObject, string key, bool value)
{
try
{
//不存在字典
if (dBObject.ExtensionDictionary.IsNull)
{
return false;
}
//写模式打开
DBDictionary dic = dBObject.ExtensionDictionary.GetObject(OpenMode.ForWrite) as DBDictionary;
//不包含这个key就直接退出
if (!dic.Contains(key))
{
return false;
}
ObjectId xrecordId = dic.GetAt(key);
//创建记录
Xrecord oldXrec = xrecordId.GetObject(OpenMode.ForWrite) as Xrecord;
oldXrec.Erase(true);
Xrecord xrec = new Xrecord();
List<TypedValue> tempData = new List<TypedValue>();
tempData.Add(new TypedValue((int)DxfCode.Bool, value));
using (var rb = new ResultBuffer(tempData.ToArray()))
{
xrec.Data = rb;
}
//添加到字典内
dic.SetAt(key, xrec);
//创建到库
dBObject.Database.TransactionManager.AddNewlyCreatedDBObject(xrec, true);
//关闭
dic.DowngradeOpen();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
3.4.获取指定键的数据
通过GetAt方法可以获取到指定键的数据。
/// <summary>
/// 获取字典中的指定key的第一个值
/// </summary>
/// <param name="dBObject"></param>
/// <param name="key">键</param>
/// <returns></returns>
public static string GetDictionaryFirstString(this DBObject dBObject, string key)
{
try
{
//不存在字典
if (dBObject.ExtensionDictionary.IsNull)
{
return null;
}
DBDictionary dic = dBObject.ExtensionDictionary.GetObject(OpenMode.ForRead) as DBDictionary;
//不包含键
if (!dic.Contains(key))
{
return null;
}
ObjectId xrecordId = dic.GetAt(key);
Xrecord xrec = xrecordId.GetObject(OpenMode.ForRead) as Xrecord;
string result = string.Empty;
if (xrec != null && xrec.Data.AsArray().Length > 0)
{
result = xrec.Data.AsArray()[0].Value.ToString();
}
return result;
}
catch (Exception ex)
{
throw ex;
}
}
4.总结
扩展字典通常以键值对的方式存储数据。由于Xrecord(数据扩展记录)对象的特殊性,使得扩展字典可以存储任意类型的数据。