EF migration Seeding with large dataset - asp.net-mvc

I am using EF Code First Migration with ASP.NET MVC5 project. I want to seed the database with about 5000 records. The examples on the asp.net web site and blogs all have the seed function within the configuration method.
internal sealed class Configuration : DbMigrationsConfiguration<foo.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\ApplicationDbContext";
}
protected override void Seed(foo.ApplicationDbContext context)
{
SeedProducts(context);
SeedFoods(context);
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
What are some options to seed large data sets when using EF Migration?
Currently The configuration file is over 5000 lines long and is different to manage.
I would prefer to store them in another database or excel spreadsheet and then import them in using the seed function. I am not sure how to go about importing data from external sources within the Seed method.
I also tried to break up the data set into several files but when I try to call the function
SeedProducts(context);
SeedFoods(context);
outside of the Configuration Class I get a build error: "The name does not exists in the current context". (I am not sure what this means?

You can store the sql file in the base directory and use it. You can create multiple sql files. I used following code to execute all sql files stored on base directory.
protected override void Seed(CRM.Data.DbContexts.CRMContext context)
{
var sqlfiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory+"\\initialdata", "*.sql");
sqlfiles.ToList().ForEach(x=> context.Database.ExecuteSqlCommand(File.ReadAllText(x)));
}

Why we need to have a seed data for 5000 records. If you prefer this way it will take lot of manual work also. where as, its not required here.
Instantly you can Create Scripts and execute that into you db. via Code as well as Manually.
Db Scripts can be taken for entire db as well as each table, Store Procedure wise also. So, that you will get records particularly.
Follow the steps from this link OR MSDN
Note: After Creating the Database Script. You can read the file from Seed Function and Execute the query from function itself. Or Manually you can go and execute when ever you need it.

I ended up using a CSV (comma delimited file) and storing it as a domain resource. Then reading the CSV file and adding database records:
I am able to Seed the database using EF Migration Seed method and a CSV file as defined as follows in the Migration.cs file. Note: the CSV file in the project in Visual Studio are set to the Build Action to Embedded Resource.
public void SeedData(WebApp.Models.ApplicationDbContext Context)
{
Assembly assembly = Assembly.GetExecutingAssembly();
string resourceName = "WebApp.SeedData.Name.csv";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
CsvReader csvReader = new CsvReader(reader);
csvReader.Configuration.WillThrowOnMissingField = false;
var records = csvReader.GetRecords<Products>().ToArray();
foreach (Product record in records)
{
Context.Products.AddOrUpdate(record);
}
}
}
Context.SaveChanges();
}

Related

How can I push data written by a Serilog File Sink on the disk to another Serilog sink?

We are trying to load test our infrastructure of logstash/elastic. Since the actual logs are generated by a software that uses hardware, we are unable to simulate it at scale.
I am wondering if we can store the logs using file sink and later write a program that reads the log files and send data through the actual sink. Since, we are trying different setup, it would be great if we can swap different sinks for testing. Say http sink and elastic sink.
I thought of reading the json file one line at a time and then invoking Write method on the Logger. However I am not sure how to get the properties array from the json. Also, it would be great to hear if there are better alternatives in Serilog world for my needs.
Example parsing
var events= File.ReadAllLines(#"C:\20210520.json")
.Select(line => JsonConvert.DeserializeObject<dynamic>(line));
foreach (var o in objects)
{
DateTime timeStamp = o.Timestamp;
LogEventLevel level = o.Level;
string messageTemplate = o.MessageTemplate;
string exception = o.Exception;
var properties = (o.Properties as JObject);
List<object> parameters = new List<object>();
foreach (var property in properties)
{
if(messageTemplate.Contains(property.Key))
parameters.Add(property.Value.ToString());
}
logInstance.Write(level, messageTemplate, parameters.ToArray());
count++;
}
Example Json Event written to the file
{"Timestamp":"2021-05-20T13:15:49.5565372+10:00","Level":"Information","MessageTemplate":"Text dialog with {Title} and {Message} displayed, user selected {Selected}","Properties":{"Title":"Unload Device from Test","Message":"Please unload the tested device from test jig","Selected":"Methods.Option","SinkRepository":null,"SourceRepository":null,"TX":"TX2937-002 ","Host":"Host1","Session":"Host1-2021.05.20 13.12.44","Seq":87321,"ThreadId":3}}
UPDATE
Though this works for simple events,
it is not able to handle Context properties (there is a work around though using ForContext),
also it forces all the properties to be of type string and
not to mention that destucturing (#property) is not handled properly
If you can change the JSON format to Serilog.Formatting.Compact's CLEF format, then you can use Serilog.Formatting.Compact.Reader for this.
In the source app:
// dotnet add package Serilog.Formatting.Compact
Log.Logger = new LoggerConfiguration()
.WriteTo.File(new CompactJsonFormatter(), "./logs/myapp.clef")
.CreateLogger();
In the load tester:
// dotnet add package Serilog.Formatting.Compact.Reader
using (var target = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Console()
.CreateLogger())
{
using (var file = File.OpenText("./logs/myapp.clef"))
{
var reader = new LogEventReader(file);
while (reader.TryRead(out var evt))
target.Write(evt);
}
}
Be aware though that load testing results won't be accurate for many sinks if you use repeated timestamps. You should consider re-mapping the events you read in to use current timestamps.
E.g. once you've loaded up evt:
var current = new LogEvent(DateTimeOffset.Now,
evt.Level,
evt.Exception,
evt.MessageTemplate,
evt.Properties);
target.Write(current);

Cannot connect to my edmx with my data context

I've not used VS MVC for a while but I'm writing a project which requires connecting to a Sql database which I've installed as an edmx file SwitchDB.edmx in my DAL folder. In the past I've set up my data context file which I then use to reference the data in my controller, the model help me to order the data in the correct way.
This is how my data context file looks
namespace Switches.DAL
{
public class SwitchContext : DbContext
{
public SwitchContext()
: base("DefaultConnection")
{ }
public DbSet<Switch_List> SwitchList { get; set; }
}
}
I've set up the "DefaultConnection" in my Web.config under connectionStrings and my model Switch_List.cs has the file settings. When I declare the DB context in my controller as below
private SwitchContext db = new SwitchContext();
Then I would expect to reference the SwitchContext to get my data, like this
var switches= db.SwitchList .ToList();
However, when I run the project and reference db in debug I get the following error message 'the function evaluation requires all threads to run'. The DB context SwitchContext is clearly not getting access to the Switch.edmx so what am I forgetting?
I had a similar problem, but you should see the connection properties using an IDE button (to re-evaluate the expression).
However, when you get to the part of db.SwitchList.ToList() does it generate any exceptions?

How to update database programmatically from mvcArea

I'm using EF6 Code First Migrations for Multiple Models means working with a single database via multiple dbContext and Migrations, In MVC5!
Why?
Because i want to add new Entities to database from my Areas!..So each Area have their own dbContext and Migrations Files. i use Update-Database command in console package manager and my database will update without any problem.
As every body knows: You can update your database from each projects of your solution but if you set it as StartUpProject of solution.
and my challenge is about what i said in above Blockquote ! because in another step i want to update my database programmatically by this code:
//ActionResult of my Area:
public ActionResult Create()
{
var configuration = new Configuration();
var migrator = new DbMigrator(configuration);
migrator.Update(); //got Error in this line
return View();
}
i get
network-related or instance-specific error
in specified line and i know why!..because my Area Project is not set as StartUpProject of my solution and it shouldn't be.
So how can i handle this situation in your view?
I knew. i should give ConnectionString to my configuration instance, straightly like this:
public ActionResult Create()
{
var configuration = new Configuration();
configuration.TargetDatabase = new DbConnectionInfo(
"Server=.;Database=SegalFrameWork;Trusted_Connection=True;",
"System.Data.SqlClient");
configuration.ContextKey = "BlogDbContext";
var migrator = new DbMigrator(configuration);
migrator.Update();
return View();
}
now there is no need to read connection string from web.config so it doesn't need any startup project to find it.

db4o - how do I get a distinct list of classes contained in a .db4o DB file?

Say I open a .db4o file. What would be the Java code (psuedo) that would generate a list of unique Java CLASSES/TYPES contained in the database?
I am sure I could write the code to do it, but I am afraid it could be quite slow. Is there a good way to do this without querying for every object in the database? Could I use some sort of index?
I'd rather not rely on stored metadata about the database, I'd rather rely on the true information about what objects are actually stored within.
You can use something like (C# but it can be easily converted to Java :)
const string DatabaseFileName = "c:\\temp\\Learning.odb";
static void Main(string[] args)
{
using (var db = Db4oEmbedded.OpenFile(DatabaseFileName))
{
var classes = db.Ext().StoredClasses();
foreach (var #class in classes)
{
Console.WriteLine();
Console.WriteLine(#class.GetName());
foreach (var field in #class.GetStoredFields())
{
Console.WriteLine("\t{1} {0}", field.GetName(), field.GetStoredType().GetName());
}
}
}
}
Note that you have more interesting methods in ExtObjectContainer interface.
Hope this helps.

Code first migrations: read sql from file

I following a post from ADO.NET team Code First Migrations: Alpha 3 ‘No-Magic’ Walkthrough
I'm trying to read a file with sql for a migration in a asp.net mvc web application. I'm using sql method. The problem is that no matter what I do I can not get a root path to my project. I always get 'c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\'
Could someone point me a way to open my file?
Thanks.
Edited
public partial class AddMembership : DbMigration
{
public override void Up()
{
//var file = File.OpenText(System.IO.Path.GetDirectoryName() + "Model/Schema/membership-up.sql");
//var file = File.OpenText(AppDomain.CurrentDomain.BaseDirectory + "Model/Schema/membership-up.sql");
//var path = HttpContext.Current.Request.MapPath("/Models/Schema/membership-up.sql");
var path = HttpContext.Current.Server.MapPath("/Models/Schema/membership-up.sql");
Sql(file.ReadToEnd());
}
public override void Down()
{
// ....
}
}
What about using Server.MapPath
http://msdn.microsoft.com/en-us/library/ms524632(v=vs.90).aspx
To run the migration directly from the site you could add this code
var dbMigrator = new DbMigrator(new Settings());
dbMigrator.Update();
To run migrations from either process (IIS vs Package Manager Console) you could check first if Server object is created before using Server.MapPath, this way you'd recognize if you're under IIS or under Package Manager Console.
If Server object is null you're under Package Manager Console so you could use something more appropriate to get your current path from like
Directory.GetCurrentDirectory();
So I would replace this code
var path = HttpContext.Current.Server.MapPath("/Models/Schema/membership-up.sql");
with something like this
String path;
if (HttpContext.Current.Server != null) {
path = HttpContext.Current.Server.MapPath("/Models/Schema/membership-up.sql");
} else {
path = Path.Combine(Directory.GetCurrentDirectory(), "Models/Schema/membership-up.sql");
}

Resources