Having written this question out, and created a MCVE, it sounds a bit like homework, but really it isn't... I'm unfortunately too old to be set homework.
I'm trying to write a small app to populate a database I'm working on with a 'pyramid' structure. There's one original member, who refers 10 members. Each of these referrals can have 10 referrals. Each of those, has 10 referrals. And so on...
I'm trying to fill the database with a maximum number of members (which is supplied)
If I set the maximum number of members to 100,000 - this works. 200,000 however, throws a StackOverflow exception.
I'm pretty sure it's down to me not terminating the 'fanning out' early enough. But I can't for the life of me figure out where.
Note, my MCVE below is using Dapper for simplicity sake, hence the simple INSERT INTO
statement
public class MemberPopulator
{
private readonly SqlConnection connection;
private const string MemberSql = @"
INSERT INTO Members (FirstName, LastName, ReferralId, Active, Created)
VALUES (@FirstName, @LastName, @ReferralId, @Active, @Created);
SELECT CAST(SCOPE_IDENTITY() as int)";
private int TotalMemberCount;
private const int MaxMemberCount = 200000;
public MemberPopulator()
{
connection = new SqlConnection("Data Source=localhost;Initial Catalog=MyTestDb;Integrated Security=True");
}
public void CreateMembers()
{
//clear members
connection.Execute("TRUNCATE TABLE Members");
//create the 'original' member (top of pyramid)
var originalMemberId = connection.Query<int>(MemberSql, new Member
{
FirstName = "FirstName Goes Here",
ReferralId = 0
}).Single();
//now we have 1 total members
TotalMemberCount = 1;
//recursively create members, starting with original member,
RecursiveCreate(new[] { originalMemberId });
}
private void RecursiveCreate(IEnumerable<int> referralMemberIds)
{
//don't recurse if we've already got enough members
if (TotalMemberCount >= MaxMemberCount)
return;
foreach (var referralId in referralMemberIds)
{
//Create 10 members
var refs = CreateReferredMembers(referralId, 10);
RecursiveCreate(refs);
}
}
private IEnumerable<int> CreateReferredMembers(int referralId, int numberOfReferrals)
{
var referredMemberIds = new List<int>();
for (var i = 0; i < numberOfReferrals; i++)
{
if (TotalMemberCount >= MaxMemberCount)
break;
var member = new Member
{
FirstName = "FirstName Goes Here",
ReferralId = referralId
};
var memberId = connection.Query<int>(MemberSql, member).Single();
referredMemberIds.Add(memberId);
TotalMemberCount++;
}
return referredMemberIds;
}
}