Esempio n. 1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            // AutoMapper setup using profiles.
            Mapper.Initialize(cfg =>
            {
                cfg.AddProfile <DeploymentProfile>();
                cfg.AddProfile <TripProfile>();
                cfg.AddProfile <CollisionProfile>();
                cfg.AddProfile <ComplaintProfile>();
            });

            // database table options
            var storeOptions = new VehicleStoreOptions();

            services.AddSingleton(storeOptions);

            // transient so I can create multiple services for each company
            services
            .AddEntityFrameworkNpgsql()
            .AddDbContext <ScootertownDbContext>(options =>
            {
                options.UseNpgsql(
                    Configuration.GetConnectionString("postgres"),
                    o =>
                {
                    o.UseNetTopologySuite();
                }
                    );
            }, ServiceLifetime.Transient);

            services.AddMemoryCache(options =>
            {
            });

            // smaller dimension repositories get singletons to get better performance?
            services.AddTransient <ICompanyRepository, CompanyRepository>();
            services.AddTransient <IPaymentTypeRepository, PaymentTypeRepository>();
            services.AddTransient <IPlacementReasonRepository, PlacementReasonRepository>();
            services.AddTransient <IRemovalReasonRepository, RemovalReasonRepository>();
            services.AddTransient <IVehicleTypeRepository, VehicleTypeRepository>();

            // larger dimension repositories don't to save memory
            services.AddTransient <ICalendarRepository, CalendarRepository>();
            services.AddTransient <IVehicleRepository, VehicleRepository>();

            // fact repositories
            services.AddTransient <ITripRepository, TripRepository>();
            services.AddTransient <IDeploymentRepository, DeploymentRepository>();
            services.AddTransient <ICollisionRepository, CollisionRepository>();
            services.AddTransient <IComplaintRepository, ComplaintRepository>();

            services.AddSingleton <ILoggerFactory, LoggerFactory>();
        }
 public ScootertownDbContext(
     DbContextOptions <ScootertownDbContext> options,
     VehicleStoreOptions storeOptions) : base(options)
 {
     this.StoreOptions = storeOptions ?? throw new ArgumentNullException(nameof(storeOptions));
 }
        public static void ConfigureContext(this ModelBuilder modelBuilder, VehicleStoreOptions storeOptions)
        {
            if (!string.IsNullOrWhiteSpace(storeOptions.DefaultSchema))
            {
                modelBuilder.HasDefaultSchema(storeOptions.DefaultSchema);
            }

            modelBuilder.HasPostgresExtension("postgis");

            modelBuilder.Entity <Models.Bridges.StreetSegmentGroup>(group =>
            {
                group.ToTable(storeOptions.BridgeStreetSegmentGroup);

                group.HasKey(x => new { x.StreetSegmentGroupKey, x.StreetSegmentKey });

                group.HasOne(x => x.StreetSegment).WithMany(x => x.Bridges).HasForeignKey(x => x.StreetSegmentKey);
                group.HasOne(x => x.SegmentGroup).WithMany(x => x.Bridges).HasForeignKey(x => x.StreetSegmentGroupKey);
            });

            modelBuilder.Entity <Models.Bridges.BicyclePathGroup>(group =>
            {
                group.ToTable(storeOptions.BridgeBicyclePathGroup);

                group.HasKey(x => new { x.BicyclePathGroupKey, x.BicyclePathKey });

                group.HasOne(x => x.BicyclePath).WithMany(x => x.Bridges).HasForeignKey(x => x.BicyclePathKey);
                group.HasOne(x => x.PathGroup).WithMany(x => x.Bridges).HasForeignKey(x => x.BicyclePathGroupKey);
            });

            modelBuilder.Entity <BicyclePath>(path =>
            {
                path.ToTable(storeOptions.BicyclePath);

                path.HasKey(x => x.Key);

                path.Property(x => x.Name).HasMaxLength(200);
                path.Property(x => x.AlternateKey).HasMaxLength(32).IsRequired();
                path.Property(x => x.Status);
                path.Property(x => x.Type);
                path.Property(x => x.Geometry);
                path.Property(x => x.X);
                path.Property(x => x.Y);
                path.Property(x => x.Buffer);

                path.HasIndex(x => x.AlternateKey).IsUnique();
                path.HasIndex(x => x.Geometry).ForNpgsqlHasMethod("gist");

                path.HasMany(x => x.Bridges).WithOne(x => x.BicyclePath).HasForeignKey(x => x.BicyclePathKey);
            });

            modelBuilder.Entity <Models.Dimensions.BicyclePathGroup>(group =>
            {
                group.ToTable(storeOptions.DimBicyclePathGroup);

                group.HasKey(x => x.Key);

                group.HasMany(x => x.Bridges).WithOne(x => x.PathGroup).HasForeignKey(x => x.BicyclePathGroupKey);
                group.HasOne(x => x.Trip).WithOne(x => x.BicyclePathGroup).HasForeignKey <Trip>(x => x.BicyclePathGroupKey);
            });

            modelBuilder.Entity <Calendar>(calendar =>
            {
                calendar.ToTable(storeOptions.Calendar);

                calendar.HasKey(x => x.Key);

                calendar.Property(x => x.Date).IsRequired().HasColumnType("Date");
                calendar.Property(x => x.Day);
                calendar.Property(x => x.WeekDayName);
                calendar.Property(x => x.IsWeekend);
                calendar.Property(x => x.IsHoliday);
                calendar.Property(x => x.HolidayText);
                calendar.Property(x => x.DayOfYear);
                calendar.Property(x => x.WeekOfMonth);
                calendar.Property(x => x.WeekOfYear);
                calendar.Property(x => x.Month);
                calendar.Property(x => x.MonthName);
                calendar.Property(x => x.Year);
                calendar.Property(x => x.MMYYYY);
                calendar.Property(x => x.MonthYear);

                calendar.HasIndex(x => x.Date).IsUnique();

                calendar.HasMany(x => x.TripsStarted).WithOne(x => x.StartDate);
                calendar.HasMany(x => x.TripsEnded).WithOne(x => x.EndDate);
            });

            modelBuilder.Entity <Company>(company =>
            {
                company.ToTable(storeOptions.Company);

                company.HasKey(x => x.Key);

                company.Property(x => x.Name).HasMaxLength(200).IsRequired();

                company.HasIndex(x => x.Name).IsUnique();

                company.HasMany(x => x.Vehicles).WithOne(x => x.Company);
                company.HasMany(x => x.Trips).WithOne(x => x.Company);
                company.HasMany(x => x.Deployments).WithOne(x => x.Company);
            });

            modelBuilder.Entity <ComplaintType>(type =>
            {
                type.ToTable(storeOptions.ComplaintType);

                type.HasKey(x => x.Key);

                type.Property(x => x.Name).HasMaxLength(200).IsRequired();

                type.HasIndex(x => x.Name).IsUnique();

                type.HasMany(x => x.Complaints).WithOne(x => x.ComplaintType).HasForeignKey(x => x.ComplaintTypeKey);
            });

            modelBuilder.Entity <Neighborhood>(neighborhood =>
            {
                neighborhood.ToTable(storeOptions.Neighborhood);

                neighborhood.HasKey(x => x.Key);

                neighborhood.Property(x => x.Name).HasMaxLength(200).IsRequired();
                neighborhood.Property(x => x.AlternateKey).IsRequired();
                neighborhood.Property(x => x.Geometry);

                neighborhood.HasIndex(x => x.AlternateKey).IsUnique();
                neighborhood.HasIndex(x => x.Geometry).ForNpgsqlHasMethod("gist");

                neighborhood.HasMany(x => x.Deployments).WithOne(x => x.Neighborhood).HasForeignKey(x => x.NeighborhoodKey);
                neighborhood.HasMany(x => x.TripsStarted).WithOne(x => x.NeighborhoodStart).HasForeignKey(x => x.NeighborhoodStartKey);
                neighborhood.HasMany(x => x.TripsEnded).WithOne(x => x.NeighborhoodEnd).HasForeignKey(x => x.NeighborhoodEndKey);
            });

            modelBuilder.Entity <PatternArea>(patternArea =>
            {
                patternArea.ToTable(storeOptions.PatternArea);

                patternArea.HasKey(x => x.Key);

                patternArea.Property(x => x.Name).HasMaxLength(200).IsRequired();
                patternArea.Property(x => x.Geometry);

                patternArea.HasIndex(x => x.Geometry).ForNpgsqlHasMethod("gist");

                patternArea.HasMany(x => x.Deployments).WithOne(x => x.PatternArea).HasForeignKey(x => x.PatternAreaKey);
                patternArea.HasMany(x => x.TripsStarted).WithOne(x => x.PatternAreaStart).HasForeignKey(x => x.PatternAreaStartKey);
                patternArea.HasMany(x => x.TripsEnded).WithOne(x => x.PatternAreaEnd).HasForeignKey(x => x.PatternAreaEndKey);
            });

            modelBuilder.Entity <PaymentType>(type =>
            {
                type.ToTable(storeOptions.PaymentType);

                type.HasKey(x => x.Key);

                type.Property(x => x.Name).HasMaxLength(200).IsRequired();

                type.HasIndex(x => x.Name).IsUnique();

                type.HasMany(x => x.TripsPayType).WithOne(x => x.PaymentType);
                type.HasMany(x => x.TripsPayAccess).WithOne(x => x.PaymentAccess);
            });

            modelBuilder.Entity <PlacementReason>(reason =>
            {
                reason.ToTable(storeOptions.PlacementReason);

                reason.HasKey(x => x.Key);

                reason.Property(x => x.Name).HasMaxLength(200).IsRequired();

                reason.HasIndex(x => x.Name).IsUnique();

                reason.HasMany(x => x.Deployments).WithOne(x => x.PlacementReason);
            });

            modelBuilder.Entity <RemovalReason>(reason =>
            {
                reason.ToTable(storeOptions.RemovalReason);

                reason.HasKey(x => x.Key);

                reason.Property(x => x.Name).HasMaxLength(200).IsRequired();

                reason.HasIndex(x => x.Name).IsUnique();

                reason.HasMany(x => x.Deployments).WithOne(x => x.PickupReason);
            });

            modelBuilder.Entity <Status>(status =>
            {
                status.ToTable(storeOptions.Status);

                status.HasKey(x => x.Key);

                status.Property(x => x.Name).HasMaxLength(50).IsRequired();

                status.HasIndex(x => x.Name).IsUnique();

                status.HasMany(x => x.Collisions).WithOne(x => x.ClaimStatus).HasForeignKey(x => x.ClaimStatusKey);
            });

            modelBuilder.Entity <StreetSegment>(segment =>
            {
                segment.ToTable(storeOptions.StreetSegment);

                segment.HasKey(x => x.Key);

                segment.Property(x => x.Name).HasMaxLength(200).IsRequired();
                segment.Property(x => x.AlternateKey).HasMaxLength(32).IsRequired();
                segment.Property(x => x.Geometry);
                segment.Property(x => x.X);
                segment.Property(x => x.Y);
                segment.Property(x => x.Buffer);

                segment.HasIndex(x => x.AlternateKey).IsUnique();
                segment.HasIndex(x => x.Geometry).ForNpgsqlHasMethod("gist");

                segment.HasMany(x => x.Bridges).WithOne(x => x.StreetSegment).HasForeignKey(x => x.StreetSegmentKey);
            });

            modelBuilder.Entity <Models.Dimensions.StreetSegmentGroup>(group =>
            {
                group.ToTable(storeOptions.DimStreetSegmentGroup);

                group.HasKey(x => x.Key);

                group.HasMany(x => x.Bridges).WithOne(x => x.SegmentGroup).HasForeignKey(x => x.StreetSegmentGroupKey);
                group.HasOne(x => x.Trip).WithOne(x => x.StreetSegmentGroup).HasForeignKey <Trip>(x => x.StreetSegmentGroupKey);
            });

            modelBuilder.Entity <Vehicle>(vehicle =>
            {
                vehicle.ToTable(storeOptions.Vehicle);

                vehicle.HasKey(x => x.Key);

                vehicle.Property(x => x.Name).HasMaxLength(200).IsRequired();
                vehicle.Property(x => x.Registered);

                vehicle.HasIndex(x => x.Name).IsUnique();
            });

            modelBuilder.Entity <VehicleType>(type =>
            {
                type.ToTable(storeOptions.VehicleType);

                type.HasKey(x => x.Key);

                type.Property(x => x.Name).HasMaxLength(200).IsRequired();

                type.HasIndex(x => x.Name).IsUnique();

                type.HasMany(x => x.Trips).WithOne(x => x.VehicleType);
                type.HasMany(x => x.Deployments).WithOne(x => x.VehicleType);
            });

            modelBuilder.Entity <Collision>(collision =>
            {
                collision.ToTable(storeOptions.Collision);

                collision.HasKey(x => x.Key);

                collision.Property(x => x.Time).IsRequired();
                collision.Property(x => x.FirstSeen);
                collision.Property(x => x.LastSeen);
                collision.Property(x => x.OtherUser);
                collision.Property(x => x.Helmet);
                collision.Property(x => x.Location);
                collision.Property(x => x.X);
                collision.Property(x => x.Y);
                collision.Property(x => x.Citation);
                collision.Property(x => x.CitationDetails);
                collision.Property(x => x.Injury);
                collision.Property(x => x.StateReport);
                collision.Property(x => x.InternalReports).HasColumnName("reports");

                // reference properties
                collision.Property(x => x.DateKey).IsRequired();
                collision.Property(x => x.TripKey);
                collision.Property(x => x.OtherVehicleTypeKey);
                collision.Property(x => x.ClaimStatusKey);

                collision.HasIndex(x => new { x.DateKey, x.Time }).IsUnique();
                collision.HasIndex(x => x.Location);

                collision.HasOne(x => x.Date).WithMany(x => x.Collisions).HasForeignKey(x => x.DateKey);
                collision.HasOne(x => x.Trip).WithMany(x => x.Collisions).HasForeignKey(x => x.TripKey);
                collision.HasOne(x => x.OtherVehicleType).WithMany(x => x.Collisions).HasForeignKey(x => x.OtherVehicleTypeKey);
                collision.HasOne(x => x.ClaimStatus).WithMany(x => x.Collisions).HasForeignKey(x => x.ClaimStatusKey);
            });

            modelBuilder.Entity <Complaint>(complaint =>
            {
                complaint.ToTable(storeOptions.Complaint);

                complaint.HasKey(x => x.Key);

                complaint.Property(x => x.SubmittedTime).IsRequired();
                complaint.Property(x => x.FirstSeen);
                complaint.Property(x => x.LastSeen);
                complaint.Property(x => x.Location);
                complaint.Property(x => x.X);
                complaint.Property(x => x.Y);
                complaint.Property(x => x.ComplaintDetails);
                complaint.Property(x => x.InternalComplaints).HasColumnName("complaints");

                // references
                complaint.Property(x => x.SubmittedDateKey).IsRequired();
                complaint.Property(x => x.VehicleKey);
                complaint.Property(x => x.CompanyKey).IsRequired();
                complaint.Property(x => x.VehicleTypeKey);
                complaint.Property(x => x.ComplaintTypeKey);

                complaint.HasIndex(x => x.Location);
                complaint.HasIndex(x => new { x.SubmittedDateKey, x.SubmittedTime, x.ComplaintDetails });

                complaint.HasOne(x => x.SubmittedDate).WithMany(x => x.Complaints).HasForeignKey(x => x.SubmittedDateKey);
                complaint.HasOne(x => x.Vehicle).WithMany(x => x.Complaints).HasForeignKey(x => x.VehicleKey);
                complaint.HasOne(x => x.Company).WithMany(x => x.Complaints).HasForeignKey(x => x.CompanyKey);
                complaint.HasOne(x => x.VehicleType).WithMany(x => x.Complaints).HasForeignKey(x => x.VehicleTypeKey);
                complaint.HasOne(x => x.ComplaintType).WithMany(x => x.Complaints).HasForeignKey(x => x.ComplaintTypeKey);
            });

            modelBuilder.Entity <Deployment>(deployment =>
            {
                deployment.ToTable(storeOptions.Deployment);

                deployment.HasKey(x => x.Key);

                deployment.Property(x => x.StartTime);
                deployment.Property(x => x.EndTime);
                deployment.Property(x => x.FirstSeen);
                deployment.Property(x => x.LastSeen);
                deployment.Property(x => x.Location);
                deployment.Property(x => x.X);
                deployment.Property(x => x.Y);
                deployment.Property(x => x.BatteryLevel);
                deployment.Property(x => x.AllowedPlacement);
                deployment.Property(x => x.Reserved);
                deployment.Property(x => x.Disabled);

                // Foreign keys
                deployment.Property(x => x.VehicleKey);
                deployment.Property(x => x.CompanyKey);
                deployment.Property(x => x.VehicleTypeKey);
                deployment.Property(x => x.StartDateKey);
                deployment.Property(x => x.EndDateKey);
                deployment.Property(x => x.PlacementReasonKey);
                deployment.Property(x => x.PickupReasonKey);
                deployment.Property(x => x.NeighborhoodKey);

                // Indicies
                deployment.HasIndex(x => new { x.VehicleKey, x.StartDateKey, x.StartTime }).IsUnique();
                deployment.HasIndex(x => x.Location);

                // Relationships
                deployment.HasOne(x => x.Vehicle).WithMany(x => x.Deployments).HasForeignKey(x => x.VehicleKey);
                deployment.HasOne(x => x.Company).WithMany(x => x.Deployments).HasForeignKey(x => x.CompanyKey);
                deployment.HasOne(x => x.VehicleType).WithMany(x => x.Deployments).HasForeignKey(x => x.VehicleTypeKey);
                deployment.HasOne(x => x.StartDate).WithMany(x => x.DeploymentsStarted).HasForeignKey(x => x.StartDateKey);
                deployment.HasOne(x => x.EndDate).WithMany(x => x.DeploymentsEnded).HasForeignKey(x => x.EndDateKey);
                deployment.HasOne(x => x.PlacementReason).WithMany(x => x.Deployments).HasForeignKey(x => x.PlacementReasonKey);
                deployment.HasOne(x => x.PickupReason).WithMany(x => x.Deployments).HasForeignKey(x => x.PickupReasonKey);
                deployment.HasOne(x => x.Neighborhood).WithMany(x => x.Deployments).HasForeignKey(x => x.NeighborhoodKey);
            });

            modelBuilder.Entity <Trip>(trip =>
            {
                trip.ToTable(storeOptions.Trip);

                trip.HasKey(x => x.Key);

                // Original properties
                trip.Property(x => x.AlternateKey).HasMaxLength(50).IsRequired();
                trip.Property(x => x.StartTime);
                trip.Property(x => x.EndTime);
                trip.Property(x => x.FirstSeen);
                trip.Property(x => x.LastSeen);
                trip.Property(x => x.StartPoint);
                trip.Property(x => x.StartX);
                trip.Property(x => x.StartY);
                trip.Property(x => x.EndPoint);
                trip.Property(x => x.EndX);
                trip.Property(x => x.EndY);
                trip.Property(x => x.Route);
                trip.Property(x => x.Duration);
                trip.Property(x => x.Distance);
                trip.Property(x => x.Accuracy);
                trip.Property(x => x.SampleRate);
                trip.Property(x => x.MaxSpeed);
                trip.Property(x => x.AverageSpeed);
                trip.Property(x => x.StandardCost);
                trip.Property(x => x.ActualCost);
                trip.Property(x => x.ParkingVerification);

                // Foreign keys
                trip.Property(x => x.VehicleKey);
                trip.Property(x => x.CompanyKey);
                trip.Property(x => x.VehicleTypeKey);
                trip.Property(x => x.StartDateKey);
                trip.Property(x => x.EndDateKey);
                trip.Property(x => x.PaymentTypeKey);
                trip.Property(x => x.PaymentAccessKey);
                trip.Property(x => x.NeighborhoodStartKey);
                trip.Property(x => x.NeighborhoodEndKey);
                trip.Property(x => x.StreetSegmentGroupKey);
                trip.Property(x => x.BicyclePathGroupKey);

                // Indicies
                trip.HasIndex(x => x.AlternateKey).IsUnique();
                trip.HasIndex(x => new { x.VehicleKey, x.StartDateKey, x.StartTime }).IsUnique();
                trip.HasIndex(x => x.StartPoint);
                trip.HasIndex(x => x.EndPoint);
                // // gist is a bounding box index
                trip.HasIndex(x => x.Route).ForNpgsqlHasMethod("gist");

                // Relationships
                trip.HasOne(x => x.Company).WithMany(x => x.Trips).HasForeignKey(x => x.CompanyKey);
                trip.HasOne(x => x.StartDate).WithMany(x => x.TripsStarted).HasForeignKey(x => x.StartDateKey);
                trip.HasOne(x => x.EndDate).WithMany(x => x.TripsEnded).HasForeignKey(x => x.EndDateKey);
                trip.HasOne(x => x.PaymentType).WithMany(x => x.TripsPayType).HasForeignKey(x => x.PaymentTypeKey);
                trip.HasOne(x => x.PaymentAccess).WithMany(x => x.TripsPayAccess).HasForeignKey(x => x.PaymentAccessKey);
                trip.HasOne(x => x.Vehicle).WithMany(x => x.Trips).HasForeignKey(x => x.VehicleKey);
                trip.HasOne(x => x.VehicleType).WithMany(x => x.Trips).HasForeignKey(x => x.VehicleTypeKey);
                trip.HasOne(x => x.NeighborhoodStart).WithMany(x => x.TripsStarted).HasForeignKey(x => x.NeighborhoodStartKey);
                trip.HasOne(x => x.NeighborhoodEnd).WithMany(x => x.TripsEnded).HasForeignKey(x => x.NeighborhoodEndKey);
                trip.HasOne(x => x.StreetSegmentGroup).WithOne(x => x.Trip).HasForeignKey <Trip>(x => x.StreetSegmentGroupKey);
                trip.HasOne(x => x.BicyclePathGroup).WithOne(x => x.Trip).HasForeignKey <Trip>(x => x.BicyclePathGroupKey);
            });

            // transform everything to lowercase
            // PostgreSQL prefers everything lowercase by default
            modelBuilder.Model.GetEntityTypes()
            .SelectMany(e => e.GetProperties())
            .ToList()
            .ForEach(p => p.Relational().ColumnName = p.Name.ToLower());
        }