我正在用SqlDataReader读取非规范化数据,数据有以下形式:
SELECT
Objects.ObjectName, Objects.OwnerId, Owners.Name
FROM
Objects
INNER JOIN Owners ON Objects.OwnerId = Owners.OwnerId
ORDER BY
Objects.OwnerId其中有以下输出:
OjectName OwnerId OwnerName
Foo 1 Mr. Fu
Bar 1 Mr. Fu
Baz 2 Mrs. Daz我的阅读循环是:
using( SqlDataReader rdr = cmd.ExecuteReader() )
{
Int64 lastOwnerId = -1;
List<String> objectNames = new List<String>();
while( rdr.Read() )
{
String objName = rdr.GetString( 0 );
Int64 ownerId = rdr.GetInt64 ( 1 );
String ownerName = rdr.GetString( 2 );
if( ownerId != lastOwnerId && objectNames.Count > 0 )
{
// logic to populate and yield-return new Owner w/ ObjectNames
objectNames.Clear();
lastOwnerId = ownerId;
}
else
{
objectNames.Add( objName );
}
}
if( ownerId != lastOwnerId && objectNames.Count > 0 )
{
// logic to populate and yield-return new Owner w/ ObjectNames
}
}填充和返回新Owner w/ObjectNames的逻辑存在两次。除了将它移动到它自己的功能之外,还有另一个循环模式是干的吗?
发布于 2016-02-29 03:10:04
实际上,您的代码当前是:
while (rdr.Read()) {
if (new owner) {
// do duplicated logic yield stuff
// Prepare for new owner
} else {
// Add owner names
}
}
if (new owner) {
// do duplicated logic yield stuff
}为了避免重复逻辑,最好的解决方案是使用一个额外的函数,但也可以将循环逻辑转换为一个永恒的循环,并在到达终点时将其断开。
换句话说,类似于以下几点:
while (True) {
if (!rdr.read()) {
last_record == true;
}
if (new owner || last_record ) {
// do duplicated logic yield stuff
if (!last_record) {
// Prepare for new owner
} else {
break; // Break out of loop
}
} else {
// Add owner names
}
}通过这种方式,您可以调用复制的逻辑块,如果有数据,并且您有一个新的所有者,如果您已经读取了最后一条记录。请注意,!rdr.read()将读取记录,即使之后if条件被否定。
你是否觉得这是一个更好的方法,由你来决定,但它确实避免了你所关心的逻辑的重复。
发布于 2016-02-29 02:30:26
从数据库读取数据的方式是相当标准的。最好将您的所有者逻辑放在一个新函数中。如果您由于某种原因不能这样做,您可以在函数开始时将逻辑放在lambda中,并在两个位置调用它,但是这将比拥有单独的函数更难读。
还请注意,可以像数组一样访问SqlDataReader对象。
String objName = (string)rdr.Item["OjectName"];
Int64 ownerId = (Int64)rdr.Item["OwnerId"];
String ownerName = (string)rdr.Item["OwnerName"];发布于 2016-02-29 15:41:24
如果我正确理解了您试图实现的目标(为所有者连接对象),我认为一种方法是实际处理Server上的所有数据。
-- drop table #ObjectOwner
create table #ObjectOwner
(
ObjectName VARCHAR(64),
OwnerId INT,
OwnerName VARCHAR(64)
)
insert into #ObjectOwner values ('Foo', 1, 'Mr. Fu'), ('Bar', 1, 'Mr. Fu'), ('Baz', 2, 'Mrs. Daz'), ('Other', 3, 'Anonymous')
GO
select * from #ObjectOwner
GO-- get all owners and a concatenation of all their objects
SELECT OwnerId, OwnerName,
STUFF((
SELECT ', ' + ObjectName
FROM #ObjectOwner
WHERE (OwnerId = Results.OwnerId)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #ObjectOwner Results
GROUP BY OwnerId, OwnerName
ORDER BY OwnerId其优点是避免从Server获取大量VARCHARs。但是,查询更复杂,不允许轻松更改它。而且,结果是作为连接而不是对象列表获得的,因此如果确实需要一个列表,则必须将其拆分。
我的观点是坚持holroy的S方法,但我想分享这一选择。
https://codereview.stackexchange.com/questions/121404
复制相似问题