What is the best way to model multi-part questions - class

I am trying to design a subclass that will contain responses to multipart questions and some logic to evaluate/act on them. For example, FoodSurvey would be a subclass of BaseSurvey
BaseSurvey
Name
Date
Submit()
FoodSurvey <- BaseSurvey
DoYouLikeIcecream
IfSoWhatFlavour
WouldYouLikeAFreeSample
SendSample(flavour)
...
FoodSurvey could have several dozen or more questions, and I would need to valdate each answer based on others, as well as run some other processes specific to FoodSurvey (as opposed to CarSurvey) that may depend on multiple answers (ex: SendSample(rockyRoad)).
I have toyed with the idea of a Question class with a Questions collection in each Survey but this quickly started to look like a Survey 'engine' which seemed like it 1.) was overkill, 2.) was error prone and 3.) limited the logic I could use to validate answers.
Are there any accepted best practices regarding designing this type of class?
If it matters, the classes will eventually be used in an ASP.NET website or web application.

I like your approach of having a 'Question' class. In more detail, this model could use a type/object patter - sort of like the relationship between a type and an object. The code could look like this:
class Question
{
public string Text { get; set; }
}
class QuestionAnswer
{
public Question Question { get; set; }
public string Answer { get; set; }
}
interface ISurveyValidator
{
bool Validate(SurveyType type, IEnumerable<QuestionAnswer> answers);
}
class SurveyType
{
public string Name { get; set; }
public IList<Question> Questions { get; set; }
public ISurveyValidator Validator { get; set; }
public Survey CreateSurvey(IEnumerable<QuestionAnswer> answers)
{
if (!this.Validator.Validate(this, answers))
throw new Exception();
return new Survey
{
Type = this,
Date = DateTime.Now,
Answers = answers.ToList()
};
}
}
class Survey
{
public SurveyType Type { get; set; }
public DateTime Date { get; set; }
public IList<QuestionAnswer> Answers { get; set; }
}
This would allow you to provide custom validation for each survey type.

I think you're being too hard on yourself when you say 'overkill'. Thinking about scalability and modularity from the start is good design practice in my books, regardless of project size.
I like the idea of a Question class. You could potentially have a member array of Pattern/RegEx objects (whatever they're called in ASP.NET) and a method that takes a String answer, and walks the array trying to match it. You could include final members for point value, topic, hint, etc. Sounds like a perfect candidate for its own class.
In terms of 'linking questions' based on the response to a previous question, perhaps this could be done as simply as maintaining a list of answers ยป next_question pairings, with a default case for those that 'don't like ice cream". This might be a good use case for a hash table, or even an array of objects of a new class - NextQuestionPair, which includes members for 'answer selected' and 'next question'.
EDIT: Think trees, choosing branches based on answers (or lack thereof)

Related

Why create a method within a model that creates a list object

I found this example in another question. I was wonder wat purpose was served by the method Question(). It seems like when the Question object is created the Answer property is created as a List object of Answer[s].
This is the first time I have seen this technique, as a new programmer, what is the benefit from this pattern?
public class Question
{
public Question()
{
this.Answers = new List<Answer>();
}
public int QuestionId { get; set; }
public string Title { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
public class Answer
{
public int AnswerId { get; set; }
public string Text { get; set; }
}
I find this pattern useful to make consumption of the object easier. I.e., by creating the Answers list in the constructor, it is ensured that Answers is never null. It just makes it easier to work with the Question object. So, in code that consumes a question object, you can do this
foreach (Answer in question.Answers)
{
...
}
without having to first check if questions.Answers is null:
if (question.Answers != null)
{
foreach (Answer in question.Answers)
{
...
}
}
I assume that this technique is used when you for some reason don't want to use lazy loading. When lazy loading is enabled and POCO classes are properly configured, you do not have to initialize you collection navigation property, it will be automatically populated after you 'touch' it for the first time.

Creating a domain model without circular references in Entity Framework

I have found a solution that works (using DTOs and AutoMapper), which is reproduced below, but I would prefer an answer that lists the different approaches to the problem with examples and this will be marked as the answer if received.
In my entity model I have a navigation property that goes from a child entity to the parent entity. My project was working swimmingly. Then I began to use AutoFixture for unit testing, and testing failed, AutoFixture saying I had a circular reference.
Now, I realise that circular reference navigation properties like this are OK within Entity Framework, but I found this post (Use value of a parent property when creating a complex child in AutoFixture), where Mark Seemann, the creator of AutoFixture states:
"For the record, I haven't written an API with a circular reference for years, so it's quite possible to avoid those Parent/Child relations."
So, I want to understand HOW a domain model can be refactored to avoid child/parent relations.
Below are the entity classes in question, the repository method, and how I use the property causing the circular reference in my View. The perfect answer would explain the different options I could choose from with examples, and the basic pros/cons of each approach.
Note: The property causing the circular reference is User, in the UserTeam model.
Models:
public class UserProfile
{
public UserProfile()
{
UserTeams = new HashSet<UserTeam>();
Games = new HashSet<Game>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<UserTeam> UserTeams { get; set; }
public virtual ICollection<Game> Games { get; set; }
}
public class Game
{
public Game()
{
UserTeams = new HashSet<UserTeam>();
}
public int Id { get; set; }
public int CreatorId { get; set; }
public virtual ICollection<UserTeam> UserTeams { get; set; }
}
public class UserTeam
{
public UserTeam()
{
UserTeam_Players = new HashSet<UserTeam_Player>();
}
public int Id { get; set; }
public int UserId { get; set; }
public int GameId { get; set; }
public virtual UserProfile User { get; set; }
public virtual ICollection<UserTeam_Player> UserTeam_Players { get; set; }
}
Repository Method
public IEnumerable<Game> GetAllGames()
{
using (DataContext)
{
var _games = DataContext.Games
.Include(x => x.UserTeams)
.Include(x => x.UserTeams.Select(y => y.User))
.ToList();
if (_games == null)
{
// log error
return null;
}
return _games;
}
}
View
#model IEnumerable<Game>
#foreach (var item in Model){
foreach (var userteam in item.UserTeams){
<p>#userteam.User.UserName</p>
}
}
Now, if I remove the 'User' navigation property, I wouldn't be able to do '#userteam.User.UserName'
So, how do I refactor the domain model to remove the circular reference, whilst being able to easily loop through Games, and do something like
UserTeam.User.Username?
I had a similar problem with AutoFixture and EntityFramework a while ago. My solution was to add an extension to AutoFixture, that allows you to build a SUT with a few recursions. That extension has recently been adopted in AutoFixture.
But I understand that your question was not about how to make AutoFixture construct recursive data structures, which is indeed possible, but how to create domain models without recursion.
First, you have tree or graph structures. Here anything but recursion would mean indirection through loose coupled node ids. Instead of defining an association, you would have to traverse the tree query-by-query or cache the whole thing and traverse by node-key lookup, which may be impractical depending on the tree-size. Here it is very convenient to make EF do the work for you.
The other common structure is a two-way navigational structure similar to your user / game scenario. Here it is often not that inconvenient to prune the navigation flow to a single direction. If you omit one direction, say from game to team, you can still easily query all teams for a given game. So: User has a list of games and a list of teams. Team has a list of games. Games have no navigational reference to either. To get all users for a specific game you could write something like:
var users = (from user in DataContext.Users
from game in user.Games
where game.Name == 'Chess'
select user).Distinct()
I have found a solution that works (using DTOs and AutoMapper), which is reproduced below, but I would still prefer an answer that lists the different approaches to the problem with examples, in particular whether this is a desirable solution, or whether I should stick with the navigation properties as they were, get rid of AutoFixture, and when it comes to serializing for json just utilise other work arounds (attributes etc)...
So, in my View Model, I added a couple of classes:
public class GameDTO
{
public int Id { get; set; }
public int CreatorId { get; set; }
public ICollection<UserTeamDTO> UserTeamsDTO { get; set; }
}
public class UserTeamDTO : UserTeam
{
public UserProfile User { get; set; }
}
And in my controller, I use AutoMapper to map the Game / UserTeam objects from the repository to my DTO objects, and return the IList _gamesDto to the View.
var _games = _gameRepository.GetAllGames();
IList<GameDTO> _gamesDto = new List<GameDTO>();
IList<UserTeamDTO> _userteamsDto = new List<UserTeamDTO>();
GameDTO _gameDto = new GameDTO();
UserTeamDTO _userteamDto = new UserTeamDTO();
Mapper.CreateMap<Game, GameDTO>();
Mapper.CreateMap<UserTeam, UserTeamDTO>();
foreach (Game _game in _games)
{
foreach (UserTeam _userteam in _game.UserTeams)
{
_userteamDto = Mapper.Map<UserTeamDTO>(_userteam);
_userteamDto.User = _userRepository.GetUser(_userteam.UserId);
_userteamsDto.Add(_userteamDto);
}
_gameDto = Mapper.Map<GameDTO>(_game);
_gameDto.UserTeamsDTO = _userteamsDto;
_gamesDto.Add(_gameDto);
}
I had a similar problem recently which also impacted serializing JSON objects. I decided to remove the circular references from my data model.
I first removed the redundant navigation properties which were creating the circular references. I made sure that my resulting tree of data made sense. This allowed me to make it clear which objects own which relationships.
This also made EF unable to automatically reason about my relationships. I had to specify the One-to-Many and Many-to-Many relationships using the FluentAPI. I found a solution here: https://stackoverflow.com/a/16719203/1887885
Hope this is helpful.

How to have a different name for entries of a mongodb document in C#?

I'm trying to do CRUD operations on documents in MongoDB and C#. I would like to have fixed structured domain entities in C# with long meaningful property names but since the name of each property will be saved in MongoDB for each document, that's not a good idea. That's because property names will be redundantly saved in database and affect the total storage and performance.
The solution I can think of to overcome this problem, is to use different names for properties in C# than in MongoDB which means a mapping between them is needed. One elegant way of doing this is to incorporate C#'s attributes, something like this:
class Book
{
[BsonProperty("n")]
public string Name { get; set; }
[BsonProperty("a")]
public string Author { get; set; }
}
In this case documents would be saved in database like this:
{ n: "...", a: "..." }
I'm not sure if this is support in MongoDB's C# Driver or not!? I can not find it myself but I was hoping I'm looking in wrong places!
I found it at last.
class Book
{
[BsonElement("n")]
public string Name { get; set; }
[BsonElement("a")]
public string Author { get; set; }
}
And this is the page with details.

Should I provide different views on the same REST entity?

I've seen this that suggest I can build different views based on user:
different json views for the same entity
However in asp web api, one uses a Model class, I can't just add new properties willy-nilly.
So, for example I may have uri:
http://host/api/products/id
Returning the model:
public class Product{
public string Code { get; set; }
public string Description { get; set; }
}
But for another purpose I want to add more information, suppose this is expensive because it joins other data to build the model, or formats the data in a very specific way:
http://host/api/productsspecial/id
Returning the model:
public class ProductSpecial{
public string Code { get; set; }
public string Description { get; set; }
public decimal Price { get; set; } //assume expensive to look up
}
So obviously I have a way to do this, two different controllers, returning different views on the data. My question is, is this OK or is there a better way?
Anyway I could do this for example: http://host/api/products/id?includeprice=true and use that to return the alternative model? And is that a good idea?
I would suggest
GET /host/api/products/{id}?fields=code,description,price
You should avoid complicating your resource URL in the manner you describe. Every possible configuration of values would need a new name: "productsReallySpecial", etc.
The problem with ?includePrice=true is you then have a parameter for every variable you might want to make optional. Your documentation can list the default return values and the available return values.

Including Hierarchy in Entity Framework Query

I have an object hierarchy that looks something like this:
public class Book
{
public virtual List<Page> Pages { get; set; }
public virtual List<Paragraph> Paragraphs { get; set; }
}
public class Page
{
public virtual List<Paragraph> Paragraphs { get; set; }
}
I want to load the complete object hierarchy and am going about that like this:
Book book = (from b in context.Books.Include("Pages").Include("Paragraphs")
.Include("Pages.Paragraphs") where CONDITION).SingleOrDefault();
I find that book.Pages and book.Paragraphs are loaded, but book.Pages[i].Paragraphs is null.
Examining the database, the data looks correct (association columns are all correctly populated).
I also tried the lamda syntax, but do not see how that could work when the parameter is a collection rather than an entity, e.g. one can do something like this:
.Include(s => s.Paragraphs.Select(p => p.Id == 1)
but I do not see how one could use the lamda syntax to specify that the Paragraphs collection for each Page in book.Pages should be loaded.
Am I missing something, or is this a limitation of Entity Framework? If it's a limitation, how can I work around it?
In the actual code (not the code boiled down for the purpose of asking a targeted question, I was missing a virtual keyword. EF didn't complain about an inability to load the additional data requested through .Include("Pages.Paragraphs"), it just silently ignored that request.
public class Page
{
public /* was missing: virtual*/ List<Paragraph> Paragraphs { get; set; }
}