Reading denormalized data using a stateful loop body I'm reading denormalized data with a SqlDataReader, the data has this form:

SELECT
    Objects.ObjectName, Objects.OwnerId, Owners.Name
FROM
    Objects
    INNER JOIN Owners ON Objects.OwnerId = Owners.OwnerId
ORDER BY
    Objects.OwnerId


Which has this output:

OjectName      OwnerId    OwnerName
Foo            1          Mr. Fu
Bar            1          Mr. Fu
Baz            2          Mrs. Daz


My reading loop is this:

using( SqlDataReader rdr = cmd.ExecuteReader() )
{
    Int64 lastOwnerId = -1;
    List&lt;String&gt; objectNames = new List&lt;String&gt;();
    while( rdr.Read() )
    {
        String objName   = rdr.GetString( 0 );
        Int64  ownerId   = rdr.GetInt64 ( 1 );
        String ownerName = rdr.GetString( 2 );

        if( ownerId != lastOwnerId &amp;&amp; objectNames.Count &gt; 0 )
        {
            // logic to populate and yield-return new Owner w/ ObjectNames

            objectNames.Clear();
            lastOwnerId = ownerId;
        }
        else
        {
            objectNames.Add( objName );
        }
    }

    if( ownerId != lastOwnerId &amp;&amp; objectNames.Count &gt; 0 )
    {
        // logic to populate and yield-return new Owner w/ ObjectNames          
    }
}


The logic to populate and yield-return new Owner w/ObjectNames  exists twice. Short of moving it to its own function, is there another loop pattern that is DRY?
In essence your code is currently:

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
}


To avoid the duplicated logic, the nicest solution would be to use an extra function, but alternatively you could also change the loop logic into being an eternal loop, and breaking out of it when reaching the end.

In other words something similar to the following:

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
    }
}


In this way you call the duplicated logic block both if there are data and you have a new owner, and if you've read the last record. Note that the !rdr.read() will read records even though the if condition is negated afterwards.

Whether you feel this is a better approach or not, is left for you to decide, but it does avoid the duplication of logic you are concerned about.