Imagine, we have test modules with large number of questions and we can create tests which will contain exactly 30 questions.
public class Module
{
public long Id { get; set; }
public List<Question> Questions { get; set; } // all questions
}
public class Test
{
public long Id { get; set; }
public List<Question> Questions { get; set; } // exactly 30 per attempt
}
That is what I would usually I do:
public class QuestionsRepository
{
public Question[] GetRandomQuestions(int count)
{
return context.Set<Question>()
.Where(x => x.Status == QuestionStatus.Active)
.OrderBy(x => Guid.NewGuid())
.Take(count)
.ToArray();
}
}
public class TestService
{
public Test StartNewTest()
{
// take random 30 and build a new test
return new Test
{
Questions = questionsRepository.GetRandomQuestions(30)
};
}
}
However, this means that we have anemic domain models and domain logic is leaking into repository, it knows what Status must be Active, that we take only limited number of questions etc.
That is what I expect DDD to look like:
public class Module
{
public long Id { get; set; }
public List<Question> Questions { get; set; } // all questions
public Test StartNewTest(int questionsCount)
{
return new Test
{
Questions = Questions
.OrderBy(x => Guid.NewGuid())
.Take(questionsCount)
.ToArray();
};
}
}
public class TestService
{
public Test StartNewTest()
{
var module = moduleRepository.GetDefaultModule();
return module.StartNewTest();
}
}
Now, domain logic is contained in Domain Models.
However, this means that all questions will be loaded into memory eagerly and then will be filtered as IEnumerable
which may be very inefficient if we have large questions number.
How do you implement persistence-ignorant Domain Model while making all SQL queries efficient and optimal? I cannot understand how to design DDD without leaking domain logic into repositories.