首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用有状态循环体读取非规范化数据

使用有状态循环体读取非规范化数据
EN

Code Review用户
提问于 2016-02-29 02:20:12
回答 3查看 95关注 0票数 1

我正在用SqlDataReader读取非规范化数据,数据有以下形式:

代码语言:javascript
复制
SELECT
    Objects.ObjectName, Objects.OwnerId, Owners.Name
FROM
    Objects
    INNER JOIN Owners ON Objects.OwnerId = Owners.OwnerId
ORDER BY
    Objects.OwnerId

其中有以下输出:

代码语言:javascript
复制
OjectName      OwnerId    OwnerName
Foo            1          Mr. Fu
Bar            1          Mr. Fu
Baz            2          Mrs. Daz

我的阅读循环是:

代码语言:javascript
复制
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的逻辑存在两次。除了将它移动到它自己的功能之外,还有另一个循环模式是干的吗?

EN

回答 3

Code Review用户

回答已采纳

发布于 2016-02-29 03:10:04

实际上,您的代码当前是:

代码语言:javascript
复制
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
}

为了避免重复逻辑,最好的解决方案是使用一个额外的函数,但也可以将循环逻辑转换为一个永恒的循环,并在到达终点时将其断开。

换句话说,类似于以下几点:

代码语言:javascript
复制
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条件被否定。

你是否觉得这是一个更好的方法,由你来决定,但它确实避免了你所关心的逻辑的重复。

票数 2
EN

Code Review用户

发布于 2016-02-29 02:30:26

从数据库读取数据的方式是相当标准的。最好将您的所有者逻辑放在一个新函数中。如果您由于某种原因不能这样做,您可以在函数开始时将逻辑放在lambda中,并在两个位置调用它,但是这将比拥有单独的函数更难读。

还请注意,可以像数组一样访问SqlDataReader对象。

代码语言:javascript
复制
String objName   = (string)rdr.Item["OjectName"];
Int64  ownerId   = (Int64)rdr.Item["OwnerId"];
String ownerName = (string)rdr.Item["OwnerName"];
票数 0
EN

Code Review用户

发布于 2016-02-29 15:41:24

如果我正确理解了您试图实现的目标(为所有者连接对象),我认为一种方法是实际处理Server上的所有数据。

设置:

代码语言:javascript
复制
-- 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

查询:

代码语言:javascript
复制
-- 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方法,但我想分享这一选择。

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/121404

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档