Using PowerShell to get the values of a SQL job schedule - sql

Currently, I am getting the job schedule for an existing SQL job and I want to get the values of how frequently it runs i.e. Daily, Weekly, Monthly, etc then I want to get when it should run next, and if the job runs on the weekends. I understand how to get all that information by doing
Get-SqlAgent -ServerInstance "$SERVER" | Get-SqlAgentJob $job | Get-SqlAgentJobSchedule | Format-List -Property *
This shows me all the relative information I need
Parent : Test_Job
ActiveEndDate : 12/31/9999 12:00:00 AM
ActiveEndTimeOfDay : 23:59:59
ActiveStartDate : 3/4/2020 12:00:00 AM
ActiveStartTimeOfDay : 00:00:00
DateCreated : 3/4/2020 2:08:00 PM
FrequencyInterval : 1
FrequencyRecurrenceFactor : 0
FrequencyRelativeIntervals : First
FrequencySubDayInterval : 2
FrequencySubDayTypes : Hour
FrequencyTypes : Daily
IsEnabled : True
JobCount : 1
I am looking at microsofts page on how to understand all the frequency information, but so far it seems like the only option is to have a bunch of nested IF statements that determine how often it runs. I can do it this way, but I figured there has to be a cleaner way to get the information I need. This is how I am currently parsing the information
if($frequency -eq "DAILY")
{
$MINUTES_LATEST_RUN_SUCCESS = "1500"
#Code here to see how often it runs in a day
}
elseif($frequency -eq "WEEKLY")
{
$MINUTES_LATEST_RUN_SUCCESS = "11520"
#Code here to see how how many days a week it runs
}
elseif($frequency -eq "MONTHLY")
{
$MINUTES_LATEST_RUN_SUCCESS = "50400"
#Code here to see how which day it runs a month
}
else
{
$MINUTES_LATEST_RUN_SUCCESS = "1500"
}
I figured this can't be the best approach.

Anytime you get into many if/then statements, it's time to use a switch. There are sample code blocks in the PowerShell ISE (CRTL+J) and VSCode (CRTl+ALT+J) for this idea.
$a = 5
switch ($a)
{
1 {"The color is red."}
2 {"The color is blue."}
3 {"The color is green."}
4 {"The color is yellow."}
5 {"The color is orange."}
6 {"The color is purple."}
7 {"The color is pink."}
8 {"The color is brown."}
default {"The color could not be determined."}
}
Yours, but of course add your other code as needed in the block.
$frequency = 'DAILY'
switch ($frequency)
{
DAILY {"The job is run $frequency"}
WEEKLY {"The job is run $frequency"}
MONTHLY {"The job is run $frequency"}
default {$MINUTES_LATEST_RUN_SUCCESS = "1500"}
}

I'm a bit late to the party, but I was also looking for documentation on the frequency interval, as there is no proper documentation on the Powershell pages, but came across this https://learn.microsoft.com/en-us/sql/relational-databases/system-tables/dbo-sysschedules-transact-sql?view=sql-server-ver15

Related

How to filter a date-field with a swift vapor-fluent query

To avoid multiple inserts of the same person in a database, I wrote the following function:
func anzahlDoubletten(_ req: Request, nname: String, vname: String, gebTag: Date)
async throws -> Int {
try await
Teilnehmer.query(on: req.db)
.filter(\.$nname == nname)
.filter(\.$vname == vname)
.filter(\.$gebTag == gebTag)
.count()
}
The function always returns 0, even if there are multiple records with the same surname, prename and birthday in the database.
Here is the resulting sql-query:
[ DEBUG ] SELECT COUNT("teilnehmer"."id") AS "aggregate" FROM "teilnehmer" WHERE "teilnehmer"."nname" = $1 AND "teilnehmer"."vname" = $2 AND "teilnehmer"."geburtstag" = $3 ["neumann", "alfred e.", 1999-09-09 00:00:00 +0000] [database-id: psql, request-id: 1AC70C41-EADE-43C2-A12A-99C19462EDE3] (FluentPostgresDriver/FluentPostgresDatabase.swift:29)
[ INFO ] anzahlDoubletten=0 [request-id: 1AC70C41-EADE-43C2-A12A-99C19462EDE3] (App/Controllers/TeilnehmerController.swift:49)
if I query directly I obtain:
lwm=# select nname, vname, geburtstag from teilnehmer;
nname | vname | geburtstag
---------+-----------+------------
neumann | alfred e. | 1999-09-09
neumann | alfred e. | 1999-09-09
neumann | alfred e. | 1999-09-09
neumann | alfred e. | 1999-09-09
so count() should return 4 not 0:
lwm=# select count(*) from teilnehmer where nname = 'neumann' and vname = 'alfred e.' and geburtstag = '1999-09-09';
count
-------
4
My DateFormatter is defined like so:
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withFullDate, .withDashSeparatorInDate]
And finally the attribute "birthday" in my model:
...
#Field(key: "geburtstag")
var gebTag: Date
...
I inserted the 4 alfreds in my database using the model and fluent, passing the birthday "1999-09-09" as a String and fluent inserted all records correctly.
But .filter(\.$gebTag == gebTag) seems to return constantly 'false'.
Is it at all possible to use .filter() with data types other than String?
And if so, what am I doing wrong?
Many thanks for your help
Michael
The problem you've hit is that you're storing only dates whereas you're filtering on dates with times. Unfortunately there's no native way to store just a date. However there are a few options.
The easiest way is to change the date field to a String and then use your date formatter (make sure you remove the time part) to convert the query option to a String.
I am guessing slightly here, but I suspect that your table was not created by a Migration? If it had been, your geburtstag field would include a time component as this is the default and you would have spotted the problem quickly.
In any event, the filter is actually filtering on the time component of gebTag as well as the date. This is why it is returning zero.
I suggest converting the geburtstag to a type that includes the time and ensuring that the time component is set to 0:00:00 when you store it. You can reset the time component to 'midnight' using something like this:
extension Date {
var midnight: Date { return Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: self)! }
}
Then change your filter to:
.filter(\.$gebTag == gebTag.midnight)
Alternatively, just use the static method in Calendar:
.filter(\.$gebTag == Calendar.startOfDay(for:gebTag))
I think this is the most straightforward way of doing it.

NextgenSplunk: Need help forming a splunk query which takes sessionId from a particular set of logs, use it to form next query

I need to form a Splunk query to find a particular sessionId for which log a is available but log b is not. Both are part of the same transaction but code breaking in between somewhere.
LOGGER.info("Log a:: setting some details in session");
Response response = handler.transactionMethod(token); //throws some exception
LOGGER.info("Log b:: getting details in session");
So in the success scenario, both Log a and Log b will be printed. But when transactionMethod throws an exception, only Log a will be printed for that sessionId and not Log b.
The requirement is I need to find any of the sessionId for which only Log a is present, not Log b.
Assuming that you have 2 fields TEXT and SessionID already defined, we will use the following test data:
SessionID=1001 TEXT="setting
SessionID=1001 TEXT="getting
SessionID=1002 TEXT="setting
SessionID=1003 TEXT="getting"
Splunk query:
| makeresults count=4
| streamstats count
| eval TEXT=case(count=1 OR count=3, "setting", count=2 OR count=4, "getting")
| eval SessionID=case(count=1 OR count=2, 1001, count=3, 1002, count=4, 1003)
``` The above is just setting of the test data ```
``` Below is the actual SPL for the task ```
| stats count(eval(TEXT=setting")) as LogA count(eval(TEXT="getting") as Logb by SessionID
| search LogA > 0 and LogB = 0
As you can see I specifically excluded the case when only "LogB" record is present (SessionID=3)

Using OptaPlanner to solve a Vehicle Routing Problem with Time Windows

Hello OptaPlanner community.
I am developing a Rest API to plan the routes of a fleet of vehicles. Looking for a tool that would help me I found Optaplanner, and I have seen that it has several success stories. In a first stage I made a planning taking into account the fastest distance and the capacity of the vehicle to cover all its visits. And I got the results I expected. Now I'm planning for time windows of visits and deposits, but I'm not successful yet.
Requirements
R1- I have a fleet of vehicles. Each vehicle has a capacity and its deposit and this deposit has a window of time. From the example of OptaPlanner for VRP I have only made a variation on the capacity that I handle as a float. As I understand it, all the vehicles in the OptaPlanner example are moved for a single depot. In my case, each vehicle has its own depot, each vehicle has its own fixed depot, and it is possible that several vehicles have the same depot.
R2- I have the visits (delivery services). Each visit has a demand and a window of time. From the example of OptaPlanner for VRP I have only made one modification regarding the demand that I handle it as a type "float".
In this process of adding this variant with TW to my routing problem I have some doubts and problems since I have not obtained a viable solution to my problem by applying TW:
1- I understand that I do not need to make modifications to the OptaPlanner example so that each vehicle cannot transport more items than its capacity. I only need to adjust the constrint provider so that the calculation is on float. I would like to know if I am right ? and on the other hand How I can manage the capacities and demands with dimensions?, in OptaPlanner it is a number but I need to manage it as volume and weight.
In the OptaPlanner domain I modified the variables "capacity" from vehicle and "demand" from visit, both to type "float".
Constraint vehicleCapacity(ConstraintFactory constraintFactory) {
return constraintFactory.from(PlanningVisit.class)
.groupBy(PlanningVisit::getVehicle, sumBigDecimal(PlanningVisit::getDemand))
.filter((vehicle, demand) -> demand.compareTo(vehicle.getCapacity()) > 0)
.penalizeLong(
"vehicle capacity",
HardSoftLongScore.ONE_HARD,
(vehicle, demand) -> demand.subtract(vehicle.getCapacity()).longValue());
}
2- In the OptaPlanner example I understand that the TW is a long that multiplies by a thousand, but I do not know if this long expresses an hour or date, or if it is just the hour converted into minutes and multiplied by a thousand.
What I am doing is converting the TW to minutes and multiplied by a thousand, for example if it is 8am, the ready time is a log equal to '480000'.
In the case of the service duration, I do not multiply it by 1000, I always treat it as 10 minutes. Am I doing the conversion correctly? , is this the long that OptaPlanner expects?
3- I understand that using the example of OptaPlanner for time windows I can solve this requirement (R2), without making variations, however for some reason that I can not find is not giving me back a feasible solution. It returns me for example: time spent (5000), best score (-3313987hard/-4156887soft).
I have thought that the error could be in the conversion of the dates of the time window or maybe some hard constraint that I lack, because the arrival times of the visits do not adapt to the time windows defined for visits nor for deposits.
For example:
I have 4 visits with time windows, 2 in the morning (visit 2 and visit 4) and 2 in the afternoon (visit 1 and visit 3).
I have two vehicles, vehicle 1 leaves a depot 1 that has a time window in a morning schedule and the other vehicle leaves a depot 2 that has a time window in an afternoon schedule.
So I expect vehicle 1 to conduct the visits that have a time window in the morning and vehicle 2 to conduct the visits that have a time window in the afternoon: [vehicle 1: {visit 2, visit 4}, vehicle 2: {visit 1, visit 3}]
I must be doing something very wrong, but I can't find where, not only does it not meet the TW of the deposit, but the arrival times of each visit exceed the defined TW. I don't understand why I get such big arrival times, that even exceed the defined limit for 1 day (all arrival times are over 1440000 = 1400min = 24 = 12am), that is, they arrived after this time.
This is the result I have obtained: score (-3313987hard/-4156887soft)
Route 1 referring to the route followed by vehicle 1
Vehicle 1
Depot 1 with TW (8:00 a 13:00)
ready_time: 480000
due_time: 780000
Visit 2 (8:30 a 12:30)
ready_time: 510000
due_time: 750000
service_duraration 10 = 10
arrival_time: 1823943
departure_time: 1833943
Visit 4 (9:30 a 12:30)
ready_time: 570000
due_time: 750000
service_duraration 10
arrival_time: 1739284
departure_time: 1739294
Visit 3 (14:40 a 15:30)
ready_time: 880000
due_time: 930000
service_duraration 10
arrival_time: 1150398
departure_time: 1150408
Route 2 referring to the route followed by vehicle 2
Vehicle 2
Depot 2 with TW (12:00 a 17:00)
ready_time: 720000
due_time: 1020000
Visit 1 (14:00 a 16:30)
ready_time: 840000
due_time: 990000
service_duraration 10 = 10
arrival_time: 2523243
departure_time: 2523253
This is my code, it can give you a better context.
This is my VariableListerner for updating the shadow variable 'arrival time'. I have not made any modifications, however the arrival times returned to me for each visit do not comply with the TW.
public class ArrivalTimeUpdatingVariableListener implements VariableListener<PlanningVisit> {
...
protected void updateArrivalTime(ScoreDirector scoreDirector, TimeWindowedVisit sourceCustomer) {
Standstill previousStandstill = sourceCustomer.getPreviousStandstill();
Long departureTime = previousStandstill == null ? null
: (previousStandstill instanceof TimeWindowedVisit)
? ((TimeWindowedVisit) previousStandstill).getDepartureTime()
: ((TimeWindowedDepot) ((PlanningVehicle)
previousStandstill).getDepot()).getReadyTime();
TimeWindowedVisit shadowCustomer = sourceCustomer;
Long arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
while (shadowCustomer != null && !Objects.equals(shadowCustomer.getArrivalTime(),
arrivalTime)) {
scoreDirector.beforeVariableChanged(shadowCustomer, "arrivalTime");
shadowCustomer.setArrivalTime(arrivalTime);
scoreDirector.afterVariableChanged(shadowCustomer, "arrivalTime");
departureTime = shadowCustomer.getDepartureTime();
shadowCustomer = shadowCustomer.getNextVisit();
arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
}
}
private Long calculateArrivalTime(TimeWindowedVisit customer, Long previousDepartureTime) {
if (customer == null || customer.getPreviousStandstill() == null) {
return null;
}
if (customer.getPreviousStandstill() instanceof PlanningVehicle) {
// PreviousStandstill is the Vehicle, so we leave from the Depot at the best suitable time
return Math.max(customer.getReadyTime(),
previousDepartureTime + customer.distanceFromPreviousStandstill());
}
return previousDepartureTime + customer.distanceFromPreviousStandstill();
}
}
And this service is where I build the domain entities from the data stored in the database (find). This TimeWindowedVehicleRoutingSolution is the one I use in the solver.
public TimeWindowedVehicleRoutingSolution find(UUID jobId) {
//load VRP from DB
RoutingProblem byJobId = routingProblemRepository.findVRP(jobId);
Set<Vehicle> vehicles = byJobId.getVehicles();
Set<Visit> visits = byJobId.getVisits();
//building solution
List<PlanningDepot> planningDepots = new ArrayList<>();
List<PlanningVehicle> planningVehicles = new ArrayList<>();
List<PlanningVisit> planningVisits = new ArrayList<>();
vehicles.forEach(vehicle -> {
//submit to planner location of the deposit, add to matrix for calculating distance
PlanningLocation planningLocation =
optimizer.submitToPlanner(vehicle.getDepot().getLocation());
//Depot, Vehicle and Visit are my persistence JPA entities, they are not the OptaPlanner
domain entities.
//The OptaPlanner domain entities are: PlanningVehicle, PlanningDepot and PlanningVisit
//I build the entities of the optaplanner domain from my persistence entities
Depot depot = vehicle.getDepot();
TimeWindowedDepot timeWindowedDepot = new TimeWindowedDepot();
TimeWindowedDepot timeWindowedDepot = new TimeWindowedDepot(depot.getId(),
planningLocation, depot.getStart(), depot.getEnd());
PlanningVehicle planningVehicle = new PlanningVehicle();
planningVehicle.setId(vehicle.getId());
planningVehicle.setCapacity(vehicle.getCapacity());
// each vehicle has its deposit
planningVehicle.setDepot(timeWindowedDepot);
planningVehicles.add(planningVehicle);
});
visits.forEach(visit -> {
//submit to planner location of the visit, add to matrix for calculating distance
PlanningLocation planningLocation = optimizer.submitToPlanner(visit.getLocation());
TimeWindowedVisit timeWindowedVisit = new TimeWindowedVisit();
TimeWindowedVisit timeWindowedVisit = new TimeWindowedVisit(visit.getId(),
planningLocation, visit.getLoad(),visit.getStart(), visit.getEnd(),
visit.getServiceDuration());
planningVisits.add(timeWindowedVisit);
});
//create TWVRP
TimeWindowedVehicleRoutingSolution solution = new TimeWindowedVehicleRoutingSolution();
solution.setId(jobId);
solution.setDepotList(planningDepots);
solution.setVisitList(planningVisits);
solution.setVehicleList(planningVehicles);
return solution;
}
Then I create the solver, start the optimization and finally save the best:
public void solve(UUID jobId) {
if (!planRepository.isResolved(jobId)) {
logger.info("Starting solver");
TimeWindowedVehicleRoutingSolution solution = null;
TimeWindowedVehicleRoutingSolution timeWindowedVehicleRoutingSolution = find(jobId);
try {
SolverJob<TimeWindowedVehicleRoutingSolution, UUID> solverJob =
solverManager.solve(jobId, timeWindowedVehicleRoutingSolution);
solution = solverJob.getFinalBestSolution();
save(jobId, solution);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} else
logger.info("This job already has a solution");
}
Any help on where the error is will be welcome. I am starting with Optaplanner, please any comments will be very helpful. Thank you very much!
Sorry about the calligraphy, English is not my language.
Thank you very much Geoffrey, I applied your suggestions and found the source of my problem. Grateful for your help!
I will comment on what happened, in case it is useful to someone:
It happens that I was using for the calculation of the distance the example of OptaWeb, that uses GrahHopper for this end and by default it returns the minimum distance, reason why calculation is as far as time. And by introducing time windows, I was breaking the score in:
Math.max(customer.getReadyTime(),
previousDepartureTime + customer.distanceFromPreviousStandstill())
My score was broken because I did not use the same conversion for all variables, the TW: ready time and departure time was expressed in minutes and multiplied by a thousand, while the distance was in milliseconds.
Example:
ready_time: 480000 (8:00 * 60 * 1000)
due_time: 780000 (13:00 * 60 * 1000)
As the distance returned to me:
distance: 641263
And therefore my score was broken.
What I did was to convert all my time variables to milliseconds:
"HH:MM", HH * 3 600 000 and MM * 60 000
Example:
ready_time: 28 800 000
due_time: 46 800 000
service_duration: 60 000 (10min per visit)
Now ready! The arrival time of each vehicle to your visits is adjusted to the defined time windows.

Google Pub/Sub to Dataflow, avoid duplicates with Record ID

I'm trying to build a Streaming Dataflow Job which read events from Pub/Sub and write them into BigQuery.
According to the documentation, Dataflow can detect duplicate messages delivery if a Record ID is used (see: https://cloud.google.com/dataflow/model/pubsub-io#using-record-ids)
But even using this Record ID, I still have some duplicates
(around 0.0002%).
Did I miss something ?
EDIT:
I use Spotify Async PubSub Client to publish messages with the following snipplet:
Message
.builder()
.data(new String(Base64.encodeBase64(json.getBytes())))
.attributes("myid", id, "mytimestamp", timestamp.toString)
.build()
Then I use Spotify scio to read the message from pub/sub and save it to DataFlow:
val input = sc.withName("ReadFromSubscription")
.pubsubSubscription(subscriptionName, "myid", "mytimestamp")
input
.withName("FixedWindow")
.withFixedWindows(windowSize) // apply windowing logic
.toWindowed // convert to WindowedSCollection
//
.withName("ParseJson")
.map { wv =>
wv.copy(value = TableRow(
"message_id" -> (Json.parse(wv.value) \ "id").as[String],
"message" -> wv.value)
)
}
//
.toSCollection // convert back to normal SCollection
//
.withName("SaveToBigQuery")
.saveAsBigQuery(bigQueryTable(opts), BQ_SCHEMA, WriteDisposition.WRITE_APPEND)
The Window size is 1 minute.
After only few seconds injecting messages I already have duplicates in BigQuery.
I use this query to count duplicates:
SELECT
COUNT(message_id) AS TOTAL,
COUNT(DISTINCT message_id) AS DISTINCT_TOTAL
FROM my_dataset.my_table
//returning 273666 273564
And this one to look at them:
SELECT *
FROM my_dataset.my_table
WHERE message_id IN (
SELECT message_id
FROM my_dataset.my_table
GROUP BY message_id
HAVING COUNT(*) > 1
) ORDER BY message_id
//returning for instance:
row|id | processed_at | processed_at_epoch
1 00166a5c-9143-3b9e-92c6-aab52601b0be 2017-02-02 14:06:50 UTC 1486044410367 { ...json1... }
2 00166a5c-9143-3b9e-92c6-aab52601b0be 2017-02-02 14:06:50 UTC 1486044410368 { ...json1... }
3 00354cc4-4794-3878-8762-f8784187c843 2017-02-02 13:59:33 UTC 1486043973907 { ...json2... }
4 00354cc4-4794-3878-8762-f8784187c843 2017-02-02 13:59:33 UTC 1486043973741 { ...json2... }
5 0047284e-0e89-3d57-b04d-ebe4c673cc1a 2017-02-02 14:09:10 UTC 1486044550489 { ...json3... }
6 0047284e-0e89-3d57-b04d-ebe4c673cc1a 2017-02-02 14:08:52 UTC 1486044532680 { ...json3... }
The BigQuery documentation states that there may be rare cases where duplicates arrive:
"BigQuery remembers this ID for at least one minute" -- if Dataflow takes more than one minute before retrying the insert BigQuery may allow the duplicate in. You may be able to look at the logs from the pipeline to determine if this is the case.
"In the rare instance of a Google datacenter losing connectivity unexpectedly, automatic deduplication may not be possible."
You may want to try the instructions for manually removing duplicates. This will also allow you to see the insertID that was used with each row to determine if the problem was on the Dataflow side (generating different insertIDs for the same record) or on the BigQuery side (failing to deduplicate rows based on their insertID).

Generating seed code from existing database in ASP.NET MVC

I wondered if anyone has encountered a similar challenge:
I have a database with some data that was ETL'ed (imported and transformed) in there from an Excel file. In my ASP.NET MVC web application I'm using Code First approach and dropping/creating every time database changes:
#if DEBUG
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyDataContext>());
#endif
However, since the data in the Database is lost, I have to ETL it again, which is annoying.
Since, the DB will be dropped only on model change, I will have to tweak my ETL anyway, I know that. But I'd rather change my DB seed code.
Does anyone know how to take the contents of the database and generate seed code, assuming that both Models and SQL Tables are up to date?
EDIT 1:
I'm planning to use the auto-generated Configuration.cs, and its Seed method, and then use AddOrUpdate() method to add data into the database: Here is Microsoft's Tutorial on migrations (specifically the "Set up the Seed method" section).
Lets say we have a simple database table with 3750 records in it;
| Id | Age | FullName |
|------|-----|-----------------|
| 1 | 50 | Michael Jackson |
| 2 | 42 | Elvis Presley |
| 3 | 48 | Whitney Houston |
| ... | ... | ... |
| 3750 | 57 | Prince |
We want to create this table in our database with using auto-generated Configuration.cs file and its Seed() method.
protected override void Seed(OurDbContainer context)
{
context.GreatestSingers.AddOrUpdate(
p => p.Id,
new GreatestSinger { Id = 1, Age = 50, FullName = "Michael Jackson" },
new GreatestSinger { Id = 2, Age = 42, FullName = "Elvis Presley" },
new GreatestSinger { Id = 3, Age = 48, FullName = "Whitney Houston" }
);
}
This is what you should do. 3750 times!
But you already have this data in your existing database table. So we can use this existing data to create Seed() codes.
With the help of SQL String Concatenation;
SELECT
CONCAT('new GreatestSinger { Id = ', Id ,', Age = ', Age ,', FullName = "', FullName ,'" },')
FROM GreatestSinger
will give us all the code needed to create 3750 rows of data.
Just copy/paste it into Seed() method. And from Package Manager Console;
Add-Migration SeedDBwithSingersData
Update-Database
Another way of seeding data is to run it as sql in an Up migration.
I have code that will read a sql file and run it
using System;
using System.Data.Entity.Migrations;
using System.IO;
public partial class InsertStandingData : DbMigration
{
public override void Up()
{
var baseDir = AppDomain.CurrentDomain
.BaseDirectory
.Replace("\\bin", string.Empty) + "\\Data\\Sql Scripts";
Sql(File.ReadAllText(baseDir + "\\StandingData.sql"));
}
public override void Down()
{
//Add delete sql here
}
}
So if your ETL generates sql for you then you could use that technique.
The advantages of doing it in the Up method are
It will be quicker than doing it using AddOrUpdate because
AddOrUpdate queries the database each time it is called to get any
already existing entity.
You are normally going from a known state (e.g. empty tables) so you probably
don't need to check whether data exists already. NB to ensure this
then you should delete the data in the Down method so that you can
tear all the way down and back up again.
The Up method does not run every time the application starts.
The Seed method provides convenience - and it has the advantage (!?) that it runs every time the application starts
But if you prefer to run the sql from there use ExecuteSqlCommand instead of Sql:
string baseDir = AppDomain.CurrentDomain.BaseDirectory.Replace("\\bin", string.Empty)
+ "\\Data\\Sql Scripts";
string path = Path.Combine(baseDir, "StandingData");
foreach (string file in Directory.GetFiles(path, "*.sql"))
{
context.Database.ExecuteSqlCommand(File.ReadAllText(file));
}
References:
Best way to incrementally seed data
Preparing for database deployment
Database Initializer and Migrations Seed Methods