diff --git a/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs b/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs index 469545e..759f986 100644 --- a/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs +++ b/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs @@ -34,7 +34,9 @@ private async Task GenerateTrips() var currentDateTime = DateTime.Now; var currentDayOfWeek = currentDateTime.DayOfWeek; - var isTripsScheduled = await dbContext.Trips.AnyAsync(t => t.DepartureTime.Value.Date == currentDateTime.Date); + var isTripsScheduled = await dbContext.Trips + .AnyAsync(t => t.DepartureTime != null && t.DepartureTime.Value.Date == currentDateTime.Date); + if (!isTripsScheduled) { // Query for bus schedule entries for the current day of the week diff --git a/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs b/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs index f08d3d2..b5a87b4 100644 --- a/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs +++ b/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs @@ -9,8 +9,10 @@ namespace BSMS.API.BackgroundJobs; /// Periodic job that handles start or stop of trips based on current time /// /// +/// public class TripStartOrStopPeriodicJob( - IServiceProvider serviceProvider) : BackgroundService + IServiceProvider serviceProvider, + ILogger logger) : BackgroundService { /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) @@ -29,13 +31,14 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) // Query for bus schedule entries where departure time has arrived var tripsToStart = await dbContext.Trips - .Where(t => t.Status != TripStatus.Canceled + .Where(t => t.Status != TripStatus.Canceled && t.Status != TripStatus.Delayed && t.BusScheduleEntry != null && t.BusScheduleEntry.Day == currentDay && t.BusScheduleEntry.DepartureTime.Minute == currentMinute && t.BusScheduleEntry.DepartureTime.Hour == currentHour) .ToListAsync(cancellationToken: stoppingToken); + var tripsToSetInTransit = new List(); foreach (var trip in tripsToStart) { if (trip is not null) @@ -50,12 +53,18 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) trip.Status = TripStatus.Delayed; } - dbContext.Trips.Update(trip); + tripsToSetInTransit.Add(trip); } } + if (tripsToSetInTransit.Count is not 0) + { + await dbContext.BulkUpdateAsync(tripsToSetInTransit); + logger.LogInformation("Some trips has started"); + } + // Query for bus schedule entries where arival time has come - await dbContext.Trips + var updatedRows = await dbContext.Trips .Where(t => t.Status == TripStatus.InTransit && t.BusScheduleEntry != null && t.BusScheduleEntry.Day == currentDay @@ -65,24 +74,36 @@ await dbContext.Trips t => t.SetProperty(e => e.Status, TripStatus.Completed) .SetProperty(e => e.ArrivalTime, DateTime.Now), cancellationToken: stoppingToken); + + if(updatedRows > 0) + { + logger.LogInformation("Some trips has completed"); + } // Double check delayed trips, try to start them var delayedTrips = await dbContext.Trips .Where(t => t.Status == TripStatus.Delayed - && t.DepartureTime.Value.Date == currentTime.Date) + && t.DepartureTime != null + && t.DepartureTime.Value.Date == currentTime.Date) .ToListAsync(cancellationToken: stoppingToken); + var tripsToRestart = new List(); foreach (var trip in delayedTrips) { if (await CanStart(dbContext, trip)) { - // Update trip status to "Scheduled" and set departure time to current time trip.Status = TripStatus.Scheduled; trip.DepartureTime = currentTime; + tripsToRestart.Add(trip); } } + if (tripsToRestart.Count is not 0) + { + await dbContext.BulkUpdateAsync(tripsToRestart); + } + await dbContext.SaveChangesAsync(stoppingToken); } diff --git a/src/BSMS.API/Controllers/TicketController.cs b/src/BSMS.API/Controllers/TicketController.cs index c2de13f..523fc6c 100644 --- a/src/BSMS.API/Controllers/TicketController.cs +++ b/src/BSMS.API/Controllers/TicketController.cs @@ -10,7 +10,7 @@ namespace BSMS.API.Controllers; /// [ApiController] [Route("api/[controller]")] -[Authorization(Role.Admin)] +[Authorization(Role.Admin, Role.Passenger)] public class TicketController(ISender sender) : ControllerBase { /// diff --git a/src/BSMS.API/Controllers/TripController.cs b/src/BSMS.API/Controllers/TripController.cs index 6fefd4f..15ba86a 100644 --- a/src/BSMS.API/Controllers/TripController.cs +++ b/src/BSMS.API/Controllers/TripController.cs @@ -1,6 +1,7 @@ using BSMS.API.Filters; using BSMS.Application.Features.Common; using BSMS.Application.Features.Trip.Queries.GetAll; +using BSMS.Core.Enums; using MediatR; using Microsoft.AspNetCore.Mvc; @@ -9,7 +10,7 @@ namespace BSMS.API.Controllers; /// [ApiController] [Route("/api/[controller]")] -[Authorization] +[Authorization(Role.Admin, Role.Driver, Role.Passenger)] public class TripController(ISender sender) : ControllerBase { /// diff --git a/src/BSMS.API/Program.cs b/src/BSMS.API/Program.cs index 8cd15ea..353ed71 100644 --- a/src/BSMS.API/Program.cs +++ b/src/BSMS.API/Program.cs @@ -44,9 +44,9 @@ .AddCustomIdentityServices(); builder.Services.AddHostedService(); -builder.Services.AddHostedService(); // comment if you have already filled DB -// builder.Services.AddHostedService(); -// builder.Services.AddHostedService(); +//builder.Services.AddHostedService(); // comment if you have already filled DB +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); builder.Services.AddCors(options => { diff --git a/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs b/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs index 484d194..c837a7d 100644 --- a/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs +++ b/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs @@ -36,7 +36,6 @@ public async Task> Handle( } var ticket = mapper.Map(request); - // 'Active' ticket status creation is handled by sql trigger await repository.InsertAsync(ticket); result.Data = new CreatedEntityResponse(ticket.TicketId); diff --git a/src/BSMS.Core/Entities/BusScheduleEntry.cs b/src/BSMS.Core/Entities/BusScheduleEntry.cs index 4114dbd..a7b2ed9 100644 --- a/src/BSMS.Core/Entities/BusScheduleEntry.cs +++ b/src/BSMS.Core/Entities/BusScheduleEntry.cs @@ -5,6 +5,8 @@ namespace BSMS.Core.Entities; [Index(nameof(Day))] +[Index(nameof(DepartureTime))] +[Index(nameof(ArrivalTime))] public class BusScheduleEntry { [Key] diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs index 5058e54..f8c6714 100644 --- a/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs +++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs @@ -40,8 +40,8 @@ create or alter view TripView WITH SCHEMABINDING AS select t.TripId, - bse.DepartureTime, - bse.ArrivalTime, + t.DepartureTime, + t.ArrivalTime, r.Origin + ' - ' + r.Destination as RouteName, b.Brand as BusBrand, b.CompanyName, diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs new file mode 100644 index 0000000..ce71509 --- /dev/null +++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs @@ -0,0 +1,791 @@ +// +using System; +using BSMS.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BSMS.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(BusStationContext))] + [Migration("20240502182731_AddIndexesForDepartureAndArrivalTime")] + partial class AddIndexesForDepartureAndArrivalTime + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("BSMS.Core.Entities.Bus", b => + { + b.Property("BusId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusId")); + + b.Property("Brand") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Capacity") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("BusId"); + + b.HasIndex("DriverId"); + + b.HasIndex("Number"); + + b.ToTable("Buses"); + + b.HasAnnotation("SqlServer:UseSqlOutputClause", false); + }); + + modelBuilder.Entity("BSMS.Core.Entities.BusReview", b => + { + b.Property("BusReviewId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusReviewId")); + + b.Property("BusId") + .HasColumnType("int"); + + b.Property("ComfortRating") + .HasColumnType("int"); + + b.Property("Comments") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("InternetConnectionRating") + .HasColumnType("int"); + + b.Property("PassengerId") + .HasColumnType("int"); + + b.Property("PriceQualityRatioRating") + .HasColumnType("int"); + + b.Property("PunctualityRating") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("SanitaryConditionsRating") + .HasColumnType("int"); + + b.HasKey("BusReviewId"); + + b.HasIndex("BusId"); + + b.HasIndex("PassengerId"); + + b.ToTable("BusReviews"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b => + { + b.Property("BusScheduleEntryId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusScheduleEntryId")); + + b.Property("ArrivalTime") + .HasColumnType("time"); + + b.Property("BusId") + .HasColumnType("int"); + + b.Property("Day") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("DepartureTime") + .HasColumnType("time"); + + b.Property("MoveDirection") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("RouteId") + .HasColumnType("int"); + + b.HasKey("BusScheduleEntryId"); + + b.HasIndex("ArrivalTime"); + + b.HasIndex("BusId"); + + b.HasIndex("Day"); + + b.HasIndex("DepartureTime"); + + b.HasIndex("RouteId"); + + b.ToTable("BusScheduleEntries"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Company", b => + { + b.Property("CompanyId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("CompanyId")); + + b.Property("City") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ContactEmail") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ContactPhone") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Country") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Street") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ZipCode") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("CompanyId"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Driver", b => + { + b.Property("DriverId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("DriverId")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("DriverLicense") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("DriverId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("FirstName"); + + b.HasIndex("LastName"); + + b.ToTable("Drivers"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Passenger", b => + { + b.Property("PassengerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("PassengerId")); + + b.Property("Email") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("PhoneNumber") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("PassengerId"); + + b.HasIndex("FirstName"); + + b.HasIndex("LastName"); + + b.ToTable("Passengers"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Route", b => + { + b.Property("RouteId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RouteId")); + + b.Property("Destination") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Origin") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("OverallDistance") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("int") + .HasComputedColumnSql("dbo.CalculateTotalDistanceForRoute([RouteId])"); + + b.HasKey("RouteId"); + + b.ToTable("Routes"); + + b.HasAnnotation("SqlServer:UseSqlOutputClause", false); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Seat", b => + { + b.Property("SeatId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("SeatId")); + + b.Property("BusId") + .HasColumnType("int"); + + b.Property("IsFree") + .HasColumnType("bit"); + + b.Property("SeatNumber") + .HasColumnType("int"); + + b.HasKey("SeatId"); + + b.HasIndex("BusId"); + + b.ToTable("Seats"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Stop", b => + { + b.Property("StopId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("StopId")); + + b.Property("DistanceToPrevious") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("PreviousStopId") + .HasColumnType("int"); + + b.Property("RouteId") + .HasColumnType("int"); + + b.HasKey("StopId"); + + b.HasIndex("PreviousStopId"); + + b.HasIndex("RouteId"); + + b.ToTable("Stops"); + + b.HasAnnotation("SqlServer:UseSqlOutputClause", false); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Ticket", b => + { + b.Property("TicketId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TicketId")); + + b.Property("EndStopId") + .HasColumnType("int"); + + b.Property("IsSold") + .HasColumnType("bit"); + + b.Property("Price") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("decimal(18,2)") + .HasComputedColumnSql("dbo.CalculateTicketPrice([EndStopId])"); + + b.Property("SeatId") + .HasColumnType("int"); + + b.Property("StartStopId") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("TicketId"); + + b.HasIndex("EndStopId"); + + b.HasIndex("SeatId"); + + b.HasIndex("StartStopId"); + + b.ToTable("Tickets"); + + b.HasAnnotation("SqlServer:UseSqlOutputClause", false); + }); + + modelBuilder.Entity("BSMS.Core.Entities.TicketPayment", b => + { + b.Property("TicketPaymentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TicketPaymentId")); + + b.Property("PassengerId") + .HasColumnType("int"); + + b.Property("PaymentDate") + .HasColumnType("datetime2"); + + b.Property("PaymentType") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("TicketId") + .HasColumnType("int"); + + b.Property("TripId") + .HasColumnType("int"); + + b.HasKey("TicketPaymentId"); + + b.HasIndex("PassengerId"); + + b.HasIndex("TicketId") + .IsUnique(); + + b.HasIndex("TripId"); + + b.ToTable("TicketPayments"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Trip", b => + { + b.Property("TripId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TripId")); + + b.Property("ArrivalTime") + .HasColumnType("datetime2"); + + b.Property("BusScheduleEntryId") + .HasColumnType("int"); + + b.Property("DepartureTime") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("TripId"); + + b.HasIndex("BusScheduleEntryId"); + + b.HasIndex("Status"); + + b.ToTable("Trips"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UserId")); + + b.Property("Email") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LastLoginDate") + .HasColumnType("datetime2"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("PasswordSalt") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("Role") + .HasColumnType("int"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("UserId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("BSMS.Core.Views.BusDetailsView", b => + { + b.Property("BusId") + .HasColumnType("int"); + + b.Property("Brand") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Capacity") + .HasColumnType("int"); + + b.Property("CompanyName") + .HasColumnType("nvarchar(max)"); + + b.Property("DriverName") + .HasColumnType("nvarchar(max)"); + + b.Property("Number") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Rating") + .HasColumnType("float"); + + b.HasKey("BusId"); + + b.ToTable((string)null); + + b.ToView("BusDetailsView", (string)null); + }); + + modelBuilder.Entity("BSMS.Core.Views.TripView", b => + { + b.Property("TripId") + .HasColumnType("int"); + + b.Property("ArrivalTime") + .HasColumnType("datetime2"); + + b.Property("BusBrand") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BusRating") + .HasColumnType("int"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DepartureTime") + .HasColumnType("datetime2"); + + b.Property("FreeSeatsCount") + .HasColumnType("int"); + + b.Property("RouteName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TripStatus") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("TripId"); + + b.ToTable((string)null); + + b.ToView("TripView", (string)null); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Bus", b => + { + b.HasOne("BSMS.Core.Entities.Driver", "Driver") + .WithMany("Buses") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.BusReview", b => + { + b.HasOne("BSMS.Core.Entities.Bus", "Bus") + .WithMany("BusReviews") + .HasForeignKey("BusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Passenger", "Passenger") + .WithMany("BusReviews") + .HasForeignKey("PassengerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bus"); + + b.Navigation("Passenger"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b => + { + b.HasOne("BSMS.Core.Entities.Bus", "Bus") + .WithMany("BusScheduleEntries") + .HasForeignKey("BusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Route", "Route") + .WithMany("BusScheduleEntries") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bus"); + + b.Navigation("Route"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Driver", b => + { + b.HasOne("BSMS.Core.Entities.Company", "Company") + .WithMany("Drivers") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Seat", b => + { + b.HasOne("BSMS.Core.Entities.Bus", "Bus") + .WithMany("Seats") + .HasForeignKey("BusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bus"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Stop", b => + { + b.HasOne("BSMS.Core.Entities.Stop", "PreviousStop") + .WithMany() + .HasForeignKey("PreviousStopId"); + + b.HasOne("BSMS.Core.Entities.Route", "Route") + .WithMany("Stops") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PreviousStop"); + + b.Navigation("Route"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Ticket", b => + { + b.HasOne("BSMS.Core.Entities.Stop", "EndStop") + .WithMany("TicketEndStops") + .HasForeignKey("EndStopId") + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Seat", "Seat") + .WithMany("Tickets") + .HasForeignKey("SeatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Stop", "StartStop") + .WithMany("TicketStartStops") + .HasForeignKey("StartStopId") + .IsRequired(); + + b.Navigation("EndStop"); + + b.Navigation("Seat"); + + b.Navigation("StartStop"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.TicketPayment", b => + { + b.HasOne("BSMS.Core.Entities.Passenger", "Passenger") + .WithMany("Payments") + .HasForeignKey("PassengerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Ticket", "Ticket") + .WithOne("Payment") + .HasForeignKey("BSMS.Core.Entities.TicketPayment", "TicketId") + .OnDelete(DeleteBehavior.ClientCascade) + .IsRequired(); + + b.HasOne("BSMS.Core.Entities.Trip", "Trip") + .WithMany("BoughtTickets") + .HasForeignKey("TripId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Passenger"); + + b.Navigation("Ticket"); + + b.Navigation("Trip"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Trip", b => + { + b.HasOne("BSMS.Core.Entities.BusScheduleEntry", "BusScheduleEntry") + .WithMany("Trips") + .HasForeignKey("BusScheduleEntryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusScheduleEntry"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Bus", b => + { + b.Navigation("BusReviews"); + + b.Navigation("BusScheduleEntries"); + + b.Navigation("Seats"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b => + { + b.Navigation("Trips"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Company", b => + { + b.Navigation("Drivers"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Driver", b => + { + b.Navigation("Buses"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Passenger", b => + { + b.Navigation("BusReviews"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Route", b => + { + b.Navigation("BusScheduleEntries"); + + b.Navigation("Stops"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Seat", b => + { + b.Navigation("Tickets"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Stop", b => + { + b.Navigation("TicketEndStops"); + + b.Navigation("TicketStartStops"); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Ticket", b => + { + b.Navigation("Payment") + .IsRequired(); + }); + + modelBuilder.Entity("BSMS.Core.Entities.Trip", b => + { + b.Navigation("BoughtTickets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs new file mode 100644 index 0000000..c9a0977 --- /dev/null +++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BSMS.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddIndexesForDepartureAndArrivalTime : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_BusScheduleEntries_ArrivalTime", + table: "BusScheduleEntries", + column: "ArrivalTime"); + + migrationBuilder.CreateIndex( + name: "IX_BusScheduleEntries_DepartureTime", + table: "BusScheduleEntries", + column: "DepartureTime"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_BusScheduleEntries_ArrivalTime", + table: "BusScheduleEntries"); + + migrationBuilder.DropIndex( + name: "IX_BusScheduleEntries_DepartureTime", + table: "BusScheduleEntries"); + } + } +} diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs b/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs index ff3adea..21e7ce1 100644 --- a/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs +++ b/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs @@ -134,10 +134,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("BusScheduleEntryId"); + b.HasIndex("ArrivalTime"); + b.HasIndex("BusId"); b.HasIndex("Day"); + b.HasIndex("DepartureTime"); + b.HasIndex("RouteId"); b.ToTable("BusScheduleEntries"); @@ -527,6 +531,46 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToView("BusDetailsView", (string)null); }); + modelBuilder.Entity("BSMS.Core.Views.TripView", b => + { + b.Property("TripId") + .HasColumnType("int"); + + b.Property("ArrivalTime") + .HasColumnType("datetime2"); + + b.Property("BusBrand") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BusRating") + .HasColumnType("int"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DepartureTime") + .HasColumnType("datetime2"); + + b.Property("FreeSeatsCount") + .HasColumnType("int"); + + b.Property("RouteName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TripStatus") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("TripId"); + + b.ToTable((string)null); + + b.ToView("TripView", (string)null); + }); + modelBuilder.Entity("BSMS.Core.Entities.Bus", b => { b.HasOne("BSMS.Core.Entities.Driver", "Driver")