Creating a DbSeeder class

Let’s start by adding a DbSeeder.cs static class to the /Data/ folder. This class will use the ApplicationDbContext to create some sample entities and save them to our Database; doing that will take a considerable amount of code, hence it might be useful to split the various class components into #region blocks so that we can better understand the various steps.

Let's start with the Public Methods region, which will contain the methods that we want to make available from external classes:

[...]

#region Public Methods
public static void Seed(ApplicationDbContext dbContext)
{
// Create default Users (if there are none)
if (!dbContext.Users.Any()) CreateUsers(dbContext);

// Create default Quizzes (if there are none) together with their
set of Q&A
if (!dbContext.Quizzes.Any()) CreateQuizzes(dbContext);
}
#endregion

[...]

As we can see, the region contains a single Seed() method that will accept an ApplicationDbContext parameter and launch a couple of private methods--CreateUsers() and CreateQuizzes()--which will actually get the job done. These will be addressed in the Seed Methods region below.

We implemented the Seed() method using a conservative approach, as it will be executed each and every time our Data Model changes. We don’t want any user or quiz to be added twice, so we ensure that all entities are not already present in the Database before adding them.

The Seed Methods region is quite long, so we'll split it into two parts, one for each method; let's start with CreateUsers():

[...]

#region Seed Methods
private static void CreateUsers(ApplicationDbContext dbContext)
{
// local variables
DateTime createdDate = new DateTime(2016, 03, 01, 12, 30, 00);
DateTime lastModifiedDate = DateTime.Now;

// Create the "Admin" ApplicationUser account (if it doesn't exist
already)
var user_Admin = new ApplicationUser()
{
Id = Guid.NewGuid().ToString(),
UserName = "Admin",
Email = "[email protected]",
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
};

// Insert the Admin user into the Database
dbContext.Users.Add(user_Admin);

#if DEBUG
// Create some sample registered user accounts (if they don't exist
already)
var user_Ryan = new ApplicationUser()
{
Id = Guid.NewGuid().ToString(),
UserName = "Ryan",
Email = "[email protected]",
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
};

var user_Solice = new ApplicationUser()
{
Id = Guid.NewGuid().ToString(),
UserName = "Solice",
Email = "[email protected]",
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
};

var user_Vodan = new ApplicationUser()
{
Id = Guid.NewGuid().ToString(),
UserName = "Vodan",
Email = "[email protected]",
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
};

// Insert sample registered users into the Database
dbContext.Users.AddRange(user_Ryan, user_Solice, user_Vodan);
#endif
dbContext.SaveChanges();
}

[...]

This method will create the Admin user, plus a set of sample registered users: Ryan, Solice, and Vodan. Each user comes with his own unique ID (in Guid format) and credentials set; these will definitely be useful for the login and authentication tests that will come in the future.

Before moving ahead, let's spend a moment looking at the #if... #endif conditional block that we used here, which is a C# pre-processor directive, also known as a conditional compilation directive. This means that the wrapped code will be compiled only if the given condition matches. The DEBUG switch will be True for release builds and False for debug builds, thus allowing us to use two different behaviors for our testing environment and for production. Since we don’t want to create the sample users in our production environment, we’ve put that part of code inside a conditional compilation block that is executed only when the application is running in Debug mode.

Here's the second part of the Seeds Method region:

[...]

private static void CreateQuizzes(ApplicationDbContext dbContext)
{
// local variables
DateTime createdDate = new DateTime(2016, 03, 01, 12, 30, 00);
DateTime lastModifiedDate = DateTime.Now;

// retrieve the admin user, which we'll use as default author.
var authorId = dbContext.Users
.Where(u => u.UserName == "Admin")
.FirstOrDefault()
.Id;

#if DEBUG
// create 47 sample quizzes with auto-generated data
// (including questions, answers & results)
var num = 47;
for (int i = 1; i <= num; i++)
{
CreateSampleQuiz(
dbContext,
i,
authorId,
num - i,
3,
3,
3,
createdDate.AddDays(-num));
}
#endif

// create 3 more quizzes with better descriptive data
// (we'll add the questions, answers & results later on)
EntityEntry<Quiz> e1 = DbContext.Quizzes.Add(new Quiz()
{
UserId = authorId,
Title = "Are you more Light or Dark side of the Force?",
Description = "Star Wars personality test",
Text = @"Choose wisely you must, young padawan: " +
"this test will prove if your will is strong enough " +
"to adhere to the principles of the light side of the
Force " +
"or if you're fated to embrace the dark side. " +
"No you want to become a true JEDI, you can't possibly
miss this!",
ViewCount = 2343,
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
});

EntityEntry<Quiz> e2 = DbContext.Quizzes.Add(new Quiz()
{
UserId = authorId,
Title = "GenX, GenY or Genz?",
Description = "Find out what decade most represents you",
Text = @"Do you feel confortable in your generation? "+
"What year should you have been born in?" +
"Here's a bunch of questions that will help you to find
out!",
ViewCount = 4180,
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
});

EntityEntry<Quiz> e3 = DbContext.Quizzes.Add(new Quiz()
{
UserId = authorId,
Title = "Which Shingeki No Kyojin character are you?",
Description = "Attack On Titan personality test",
Text = @"Do you relentlessly seek revenge like Eren? " +
"Are you willing to put your like on the stake to
protect your friends like Mikasa? " +
"Would you trust your fighting skills like Levi "+
"or rely on your strategies and tactics like Arwin? " +
"Unveil your true self with this Attack On Titan
personality test!",
ViewCount = 5203,
CreatedDate = createdDate,
LastModifiedDate = lastModifiedDate
});

// persist the changes on the Database
DbContext.SaveChanges();
}
#endregion

[...]

The preceding CreateQuizzes() method adds a total of 50 sample quizzes to the Database. As we can see, 47 of them come with questions, answers, and results, thanks to the CreateSampleQuiz() utility method (which we'll see in a bit), while the other three feature a more realistic title and text contents, yet they come out empty. We did that on purpose, as we plan to manually add their questions, answers, and results with our Angular app in the subsequent chapters.

Last but not least comes the Utility Methods region:

[...]

#region Utility Methods
/// <summary>
/// Creates a sample quiz and add it to the Database
/// together with a sample set of questions, answers & results.
/// </summary>
/// <param name="userId">the author ID</param>
/// <param name="id">the quiz ID</param>
/// <param name="createdDate">the quiz CreatedDate</param>
private static void CreateSampleQuiz(
ApplicationDbContext dbContext,
int num,
string authorId,
int viewCount,
int numberOfQuestions,
int numberOfAnswersPerQuestion,
int numberOfResults,
DateTime createdDate)
{
var quiz = new Quiz()
{
UserId = authorId,
Title = String.Format("Quiz {0} Title", num),
Description = String.Format("This is a sample description for
quiz {0}.", num),
Text = "This is a sample quiz created by the DbSeeder class for
testing purposes. " +
"All the questions, answers & results are auto-
generated as well.",
ViewCount = viewCount,
CreatedDate = createdDate,
LastModifiedDate = createdDate
};
dbContext.Quizzes.Add(quiz);
dbContext.SaveChanges();

for (int i = 0; i < numberOfQuestions; i++)
{
var question = new Question()
{
QuizId = quiz.Id,
Text = "This is a sample question created by the DbSeeder
class for testing purposes. " +
"All the child answers are auto-generated as well.",
CreatedDate = createdDate,
LastModifiedDate = createdDate
};
dbContext.Questions.Add(question);
dbContext.SaveChanges();

for (int i2 = 0; i2 < numberOfAnswersPerQuestion; i2++)
{
var e2 = dbContext.Answers.Add(new Answer()
{
QuestionId = question.Id,
Text = "This is a sample answer created by the DbSeeder
class for testing purposes. ",
Value = i2,
CreatedDate = createdDate,
LastModifiedDate = createdDate
});
}
}

for (int i = 0; i < numberOfResults; i++)
{
dbContext.Results.Add(new Result()
{
QuizId = quiz.Id,
Text = "This is a sample result created by the DbSeeder
class for testing purposes. ",
MinValue = 0,
// max value should be equal to answers number * max answer
value
MaxValue = numberOfAnswersPerQuestion * 2,
CreatedDate = createdDate,
LastModifiedDate = createdDate
});
}
dbContext.SaveChanges();
}
#endregion

[...]

Here lies the CreateSampleQuiz() method implementation, which adds a new quiz to the Database, along with a configurable tree of questions, answers, and results for the quiz itself.

Before going further, it's important to note how this method, which is called no less than 47 times by CreateQuizzes(), makes a good use of the dbContext.SaveChanges() command. This is how we tell our ApplicationDbContext instance to persist all the pending changes to the Database. This is quite resource intensive; however, we need to do that to retrieve the Id key of the quizzes and questions we add, which we need to properly create the Quiz > Questions > Answers and Quiz > Results relationships. The dbContext.SaveChanges() method performs actual INSERT queries under the Entity Framework hood, so it can be resource-intensive if we run it multiple times. Luckily enough, the whole data-seed process will happen only once, so it won't impact the overall performance of our application.

The DbSeeder.cs class features an impressive amount of code, yet there's nothing to worry about as it's full of repeating tasks. However, it does make good use of the various features made available by our ApplicationDbContext class and its DbContext base class.

If you want to know more about DbContext, you can check out the official API at
https://docs.microsoft.com/en-US/ef/core/api/microsoft.entityframeworkcore.dbcontext.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.27.74