.Net 中的反射可以通过查看用户定义的类型名称来帮助动态构造表值参数/SqlMetaData[] 对象吗?
我已经开始在 Sql Server 2k8 中使用表值参数进行批处理操作。我非常喜欢这个功能,感觉是经过漫长的等待才来的。
然而,为了从 .Net 代码传递 TVP,需要花费太多精力来构建 SQLMetaData[],然后在循环中填充值。
如何避免在同步中维护 .Net 代码中的 Sql Server 中的用户定义类型和 SQLMetaData[] 对象? 当我更改 SQL 中的类型定义时,没有简单的方法可以知道我在 .Net 的大量代码中在哪里使用了该类型。
.Net Reflection 能否通过给出用户定义类型的名称来拯救程序员构建 SQLMetadata,并通过提供对象数组来帮助填充数据。
考虑这个例子:
SqlMetaData[] tvp_TradingAllocationRule = new SqlMetaData[13];
try
{
tvp_TradingAllocationRule[0] = new SqlMetaData("ID", SqlDbType.UniqueIdentifier);
tvp_TradingAllocationRule[1] = new SqlMetaData("Name", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[2] = new SqlMetaData("Description", SqlDbType.VarChar, -1);
tvp_TradingAllocationRule[3] = new SqlMetaData("Enabled", SqlDbType.Bit);
tvp_TradingAllocationRule[4] = new SqlMetaData("Category", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[5] = new SqlMetaData("Custom1", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[6] = new SqlMetaData("Custom2", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[7] = new SqlMetaData("Custom3", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[8] = new SqlMetaData("CreatedBy", SqlDbType.VarChar, 20);
tvp_TradingAllocationRule[9] = new SqlMetaData("CreatedTS", SqlDbType.DateTime);
tvp_TradingAllocationRule[10] = new SqlMetaData("ModifiedBy", SqlDbType.VarChar, 20);
tvp_TradingAllocationRule[11] = new SqlMetaData("ModifiedTS", SqlDbType.DateTime);
tvp_TradingAllocationRule[12] = new SqlMetaData("IsFactory", SqlDbType.Bit);
}
catch (Exception ex)
{
throw new Exception("Error Defining the tvp_TradingActionCondition in .Net" + ex.Message);
}
foreach (TradingRuleMetadata ruleMetadata in updatedRules)
{
SqlDataRecord tradingAllocationRule = new SqlDataRecord(tvp_TradingAllocationRule);
try
{
tradingAllocationRule.SetGuid(0, ruleMetadata.ID);
tradingAllocationRule.SetString(1, ruleMetadata.Name);
tradingAllocationRule.SetString(2, ruleMetadata.Description);
tradingAllocationRule.SetBoolean(3, ruleMetadata.Enabled);
tradingAllocationRule.SetString(4, ruleMetadata.Category);
tradingAllocationRule.SetString(5, ruleMetadata.Custom1);
tradingAllocationRule.SetString(6, ruleMetadata.Custom2);
tradingAllocationRule.SetString(7, ruleMetadata.Custom3);
tradingAllocationRule.SetString(8, ruleMetadata.CreatedBy);
tradingAllocationRule.SetDateTime(9, ruleMetadata.CreatedDate);
tradingAllocationRule.SetString(10, ruleMetadata.ModifiedBy);
tradingAllocationRule.SetDateTime(11, ruleMetadata.ModifiedDate);
tradingAllocationRule.SetBoolean(12, ruleMetadata.IsFactory);
tvp_TradingAllocationRuleRecords.Add(tradingAllocationRule);
}
catch (Exception ex)
{
}
}
现在,如果您的表有 100 列,想象一下您的代码。
I have started using Table Valued Parameters in Sql Server 2k8 for batch operations. I liked this feature a lot and feel it came after a long wait.
However, inorder to pass a TVP from .Net code there is too much of hardwork involved to construct the SQLMetaData[] and then filling up values in a loop.
How do you avoid the maintenance of keeping the User Defined Types in Sql Server and SQLMetaData[] objects in your .Net code in Synchronization?
When i change a type definition in SQL, there is no easy way of knowing where all did I use that type in huge code of .Net.
Can .Net Reflection rescue a programmer to construct SQLMetadata by giving the name of User Defined Type and help in filling the data by providing object arrays.
Consider This Example:
SqlMetaData[] tvp_TradingAllocationRule = new SqlMetaData[13];
try
{
tvp_TradingAllocationRule[0] = new SqlMetaData("ID", SqlDbType.UniqueIdentifier);
tvp_TradingAllocationRule[1] = new SqlMetaData("Name", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[2] = new SqlMetaData("Description", SqlDbType.VarChar, -1);
tvp_TradingAllocationRule[3] = new SqlMetaData("Enabled", SqlDbType.Bit);
tvp_TradingAllocationRule[4] = new SqlMetaData("Category", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[5] = new SqlMetaData("Custom1", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[6] = new SqlMetaData("Custom2", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[7] = new SqlMetaData("Custom3", SqlDbType.VarChar, 255);
tvp_TradingAllocationRule[8] = new SqlMetaData("CreatedBy", SqlDbType.VarChar, 20);
tvp_TradingAllocationRule[9] = new SqlMetaData("CreatedTS", SqlDbType.DateTime);
tvp_TradingAllocationRule[10] = new SqlMetaData("ModifiedBy", SqlDbType.VarChar, 20);
tvp_TradingAllocationRule[11] = new SqlMetaData("ModifiedTS", SqlDbType.DateTime);
tvp_TradingAllocationRule[12] = new SqlMetaData("IsFactory", SqlDbType.Bit);
}
catch (Exception ex)
{
throw new Exception("Error Defining the tvp_TradingActionCondition in .Net" + ex.Message);
}
foreach (TradingRuleMetadata ruleMetadata in updatedRules)
{
SqlDataRecord tradingAllocationRule = new SqlDataRecord(tvp_TradingAllocationRule);
try
{
tradingAllocationRule.SetGuid(0, ruleMetadata.ID);
tradingAllocationRule.SetString(1, ruleMetadata.Name);
tradingAllocationRule.SetString(2, ruleMetadata.Description);
tradingAllocationRule.SetBoolean(3, ruleMetadata.Enabled);
tradingAllocationRule.SetString(4, ruleMetadata.Category);
tradingAllocationRule.SetString(5, ruleMetadata.Custom1);
tradingAllocationRule.SetString(6, ruleMetadata.Custom2);
tradingAllocationRule.SetString(7, ruleMetadata.Custom3);
tradingAllocationRule.SetString(8, ruleMetadata.CreatedBy);
tradingAllocationRule.SetDateTime(9, ruleMetadata.CreatedDate);
tradingAllocationRule.SetString(10, ruleMetadata.ModifiedBy);
tradingAllocationRule.SetDateTime(11, ruleMetadata.ModifiedDate);
tradingAllocationRule.SetBoolean(12, ruleMetadata.IsFactory);
tvp_TradingAllocationRuleRecords.Add(tradingAllocationRule);
}
catch (Exception ex)
{
}
}
Now if your table has 100 columns, imagine your code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用反射来做到这一点。首先,必须有一种方法来覆盖名称和长度的默认值。为此,请定义
Attribute
:并在您的类型上使用它们:
然后您可以创建一个方法,将该类型的集合映射到
SqlDataRecord
集合:此代码是使用了相当多的反射,所以它对你来说可能太慢了。如果是这种情况,您将需要实施某种缓存。一种方法是创建一个执行所有这些工作的
Expression
,然后将其编译为委托(仅限.Net 4,因为您需要BlockExpression
)。另外,您的实际要求可能更复杂,因为您可能需要忽略某些属性或类似的东西。但这应该很容易添加。
You can do that using reflection. First, there has to be a way to override the default values for names and lengths. To do that, define
Attribute
s:And use them on your type:
Then you can create a method that maps a collection of this type to collection of
SqlDataRecord
:This code is uses quite a lot of reflection, so it can be too slow for you. If that's the case, you would need to implement some kind of caching. One way of doing that would be creating an
Expression
that does all this work and then compiling it into a delegate (.Net 4 only, because you would needBlockExpression
).Also, your actual requirements may be more complicated, because you may need to ignore some properties, or something similar. But that should be easy to add.
问题中没有足够的代码示例,但对于类似的事情,我会做一些事情,比如编写一个单独的 .NET 可执行文件来读取 SQL 元数据并为每个 UDT 生成帮助器类(看起来很像您的示例)。代码生成的优点是运行时速度更快,更重要的是,您可以像手写一样阅读和单步执行源代码。这也不是特别难——尤其是现在partial 关键字存在。
There isn't enough in the question to give a code sample, but for something like this I would do something like write a separate .NET executable to read the SQL metadata and generate helper classes (looking much like your example) for each UDT. The advantage of code generation is that it's a little faster at run time, and, more importantly, that you can read and step through the source code just as if it were hand-written. It's also not especially hard to do - especially now that the partial keyword exists.