using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using gehGassi.Core.Interfaces; using gehGassi.Domain.Advertisements; using gehGassi.Domain.Coins; using gehGassi.Domain.Common; using gehGassi.Domain.Customers; using gehGassi.Domain.Devices; using gehGassi.Domain.Dogs; using gehGassi.Domain.Favourites; using gehGassi.Domain.Feedback; using gehGassi.Domain.Messages; using gehGassi.Domain.News; using gehGassi.Domain.Pages; using gehGassi.Domain.Payment; using gehGassi.Domain.Ratings; using gehGassi.Domain.Reporting; using gehGassi.Domain.Roles; using gehGassi.Domain.Shop; using gehGassi.Domain.Subscriptions; using gehGassi.Domain.Users; using gehGassi.Domain.Vouchers; using gehGassi.Domain.Walks; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.Extensions.Options; using Newtonsoft.Json; namespace gehGassi.Persistence { /// /// Basis Datenbank Kontext für SQL-Server. Implementiert IUnitOfWork. /// public class SqlDbContext : IdentityDbContext, IAuditDbContext { private readonly AuditOptions _auditOptions; /// /// Erstellt eine Instanz /// /// Optionen /// Audit-Optionen public SqlDbContext(DbContextOptions options, IOptions auditOptions) : base(options) { _auditOptions = auditOptions.Value; } public DbSet Audits { get; set; } public DbSet FidoStoredCredentials { get; set; } public DbSet RefreshTokens { get; set; } public DbSet PersistedTickets { get; set; } public DbSet Customers { get; set; } public DbSet CustomerTypes { get; set; } public DbSet AppUsers { get; set; } public DbSet DogWalkerProfiles { get; set; } public DbSet Certificates { get; set; } public DbSet AppUserBlocks { get; set; } public DbSet Dogs { get; set; } public DbSet TaxRates { get; set; } public DbSet AdvertisementCategories { get; set; } public DbSet Advertisements { get; set; } public DbSet Listings { get; set; } public DbSet Branches { get; set; } public DbSet Banners { get; set; } public DbSet BannerStatistics { get; set; } public DbSet Pins { get; set; } public DbSet ShopSettings { get; set; } public DbSet ShipmentCosts { get; set; } public DbSet Carts { get; set; } public DbSet CartItems { get; set; } public DbSet Orders { get; set; } public DbSet OrderItems { get; set; } public DbSet Invoices { get; set; } public DbSet CreditNotes { get; set; } public DbSet DeliveryNotes { get; set; } public DbSet ProductCategories { get; set; } public DbSet Products { get; set; } public DbSet ProductCountries { get; set; } public DbSet DogRaces { get; set; } public DbSet NewsCategories { get; set; } public DbSet News { get; set; } public DbSet Pages { get; set; } public DbSet Faqs { get; set; } public DbSet EntityRelations { get; set; } public DbSet Conversations { get; set; } public DbSet Messages { get; set; } public DbSet MessageCopies { get; set; } public DbSet PublicWalkRequests { get; set; } public DbSet PublicWalkResponses { get; set; } public DbSet PublicWalkRequestNotifications { get; set; } public DbSet Walks { get; set; } public DbSet WalkingTimes { get; set; } public DbSet WalkComplaints { get; set; } public DbSet Ratings { get; set; } public DbSet AppFeedbacks { get; set; } public DbSet Favourites { get; set; } public DbSet SystemMessages { get; set; } public DbSet SystemMessagesToSend { get; set; } public DbSet Devices { get; set; } public DbSet Wallets { get; set; } public DbSet TransactionFees { get; set; } public DbSet GehGassiFees { get; set; } public DbSet PaymentTransactions { get; set; } public DbSet IdentityDocuments { get; set; } public DbSet Payouts { get; set; } public DbSet Cards { get; set; } public DbSet AppUserReports { get; set; } public DbSet CoinsAccounts { get; set; } public DbSet CoinsTransactions { get; set; } public DbSet CoinsPerMonths { get; set; } public DbSet CoinsPerYears { get; set; } public DbSet AppVersions { get; set; } public DbSet VoucherCampaigns { get; set; } public DbSet Vouchers { get; set; } public DbSet VoucherUsages { get; set; } public DbSet Subscriptions { get; set; } public DbSet AppUserSubscriptions { get; set; } //Views public DbSet AuditsWithNames { get; set; } public DbSet ApplicationUsersWithNames { get; set; } public DbSet CustomerWithNames { get; set; } public DbSet OrdersPhysical { get; set; } public DbSet DogWalkers { get; set; } public DbSet RatingsWithNames { get; set; } public DbSet AppUserReportsWithNames { get; set; } public DbSet ConversationsWithNames { get; set; } public DbSet CoinsPerMonthWithNames { get; set; } public DbSet CoinsPerYearWithNames { get; set; } //Table-Value Functions public DbSet AdvertisementCategoriesWithNames { get; set; } public DbSet ProductCategoriesWithNames { get; set; } public DbSet TaxRatesWithNames { get; set; } public DbSet ProductsWithNames { get; set; } public DbSet ProductsWithNamesCountry { get; set; } public DbSet CartItemsWithNames { get; set; } public DbSet CartsWithNames { get; set; } public DbSet BranchesWithNames { get; set; } public DbSet ListingsWithNames { get; set; } public DbSet AdvertisementsWithNames { get; set; } public DbSet BannersWithNames { get; set; } public DbSet PinsWithNames { get; set; } public DbSet DogRacesWithNames { get; set; } public DbSet DogWithNames { get; set; } public DbSet NewsCategoriesWithNames { get; set; } public DbSet NewsWithNames { get; set; } public DbSet ConversationsWithTarget { get; set; } public DbSet PagesWithNames { get; set; } public DbSet FaqsWithNames { get; set; } public DbSet PublicWalkRequestWithNames { get; set; } public DbSet PublicWalkRequestsWithNamesAndResponseStatus { get; set; } public DbSet PublicWalkResponsesWithNames { get; set; } public DbSet WalksWithNames { get; set; } public DbSet WalkComplaintsWithNames { get; set; } public DbSet AppUserBlocksWithNames { get; set; } public DbSet RatingsWithNamesEx { get; set; } public DbSet AppVersionsWithNames { get; set; } public DbSet VoucherCampaignsWithNames { get; set; } public DbSet SubscriptionWithNames { get; set; } public DbSet AppUserSubscriptionWithNames { get; set; } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // Customize the ASP.NET Identity model and override the defaults if needed. // For example, you can rename the ASP.NET Identity table names and more. // Add your customizations after calling base.OnModelCreating(builder); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().OwnsOne(p => p.Address); builder.Entity().OwnsOne(p => p.Contact); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.TypeId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.BranchId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.MarkupListing).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupAdvertisement).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupPin).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupBanner).HasColumnType("decimal(18,2)"); builder.Entity().OwnsOne(c => c.MangopayAddress, d => d.ToJson()); builder.Entity().Property(c => c.Value).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.WeightFrom).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.WeightTo).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.SubtotalFrom).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.SubtotalTo).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.FixedPrice).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.SubtotalPercent).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Shipment).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.ShipmentGross).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CartId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ProductId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Price2Gross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TaxRate).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TaxRateValue).HasColumnType("decimal(18,2)"); builder.Entity().OwnsOne(p => p.DeliveryAddress); builder.Entity().OwnsOne(p => p.BillingAddress); builder.Entity().Property(c => c.Subtotal).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.SubtotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Shipment).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.ShipmentGross).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ProductId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ProductCategoryId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.TaxRateId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.AdditionalShippingCharge).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2Gross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Weight).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Length).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Width).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Height).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().OwnsOne(p => p.Address); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AdvertisementCategoryId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderItemId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.Discount).HasColumnType("decimal(18,2)"); builder.Entity().HasIndex(c => c.Index); builder.Entity().OwnsOne(p => p.Address); builder.Entity().OwnsOne(p => p.ListingAddress); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.BranchId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderItemId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasIndex(c => c.Index); builder.Entity().OwnsOne(p => p.Address); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderItemId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.Budget).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.BudgetUsed).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceView).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceClick).HasColumnType("decimal(18,4)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.BannerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ListingId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.OrderItemId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ProductCategoryId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.TaxRateId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.AdditionalShippingCharge).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Weight).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Length).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Width).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Height).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PinPercentPerKm).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ProductId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice2).HasColumnType("decimal(18,4)"); builder.Entity().OwnsOne(p => p.Address); builder.Entity().OwnsOne(p => p.Contact); builder.Entity().OwnsOne(p => p.SocialMedia); builder.Entity().OwnsOne(p => p.RatingStatistics, n => { n.Property(m => m.AverageRating).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalPoints).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalRatings).HasDefaultValue(0); }); builder.Entity().OwnsOne(p => p.RatingStatisticsWalker, n => { n.Property(m => m.AverageRating).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalPoints).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalRatings).HasDefaultValue(0); }); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().Property(c => c.PriceWalk).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceDay).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceSitting).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.BlockingAppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.BlockedAppUserId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.DogRaceId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().OwnsOne(p => p.RatingStatistics, n => { n.Property(m => m.AverageRating).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalPoints).HasColumnType("decimal(18,2)").HasDefaultValue(0); n.Property(m => m.TotalRatings).HasDefaultValue(0); }); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CategoryId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ConversationId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.ConversationId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().OwnsOne(p => p.PickupAddress); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().HasIndex(c => c.Index); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().OwnsOne(p => p.PickupAddress); builder.Entity().HasIndex(c => c.Index); builder.Entity().OwnsOne(p => p.PickupAddress); builder.Entity().OwnsOne(p => p.ReturnAddress); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,2)"); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.WalkId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().Property(c => c.Points).HasColumnType("decimal(18,2)"); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Percent).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Fixed).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Percent).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Fixed).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.StartAmmount).HasColumnType("decimal(18,2)"); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasIndex(c => c.Index); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Balance).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AccountId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Ammount).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Balance).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.Balance).HasColumnType("decimal(18,2)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.CustomerId).OnDelete(DeleteBehavior.Cascade); builder.Entity().OwnsOne(p => p.Address); builder.Entity().Property(c => c.Budget).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.BudgetUsed).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,4)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.VoucherCampaignId).OnDelete(DeleteBehavior.Cascade); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,4)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.VoucherId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.WalkId).OnDelete(DeleteBehavior.ClientSetNull); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.VoucherAmmountUsed).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.AppUserId).OnDelete(DeleteBehavior.Cascade); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.SubscriptionId).OnDelete(DeleteBehavior.Cascade); //Views builder.Entity().HasNoKey().ToView("vw_AuditsWithNames"); builder.Entity().HasNoKey().ToView("vw_ApplicationUsersWithNames"); builder.Entity().HasNoKey().ToView("vw_OrdersPhysical"); builder.Entity().HasNoKey().ToView("vw_DogWalkers"); builder.Entity().Property(c => c.RatingStatistics_TotalPoints).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.RatingStatistics_AverageRating).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.RatingStatisticsWalker_TotalPoints).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.RatingStatisticsWalker_AverageRating).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceWalk).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceDay).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceSitting).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView("vw_RatingsWithNames"); builder.Entity().Property(c => c.Points).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView("vw_AppUserReportsWithNames"); builder.Entity().HasNoKey().ToView("vw_ConversationsWithNames"); builder.Entity().HasNoKey().ToView("vw_CoinsPerMonthWithNames"); builder.Entity().Property(c => c.Balance).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView("vw_CoinsPerYearWithNames"); builder.Entity().Property(c => c.Balance).HasColumnType("decimal(18,2)"); //Stored Procedures //Table-Value functions builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().Property("CountryCode").HasColumnName("Address_CountryCode"); builder.Entity().Property(c => c.MarkupListing).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupAdvertisement).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupPin).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.MarkupBanner).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.AdditionalShippingCharge).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Weight).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Length).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Width).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Height).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PinPercentPerKm).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.AdditionalShippingCharge).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Weight).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Length).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Width).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Height).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PinPercentPerKm).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.PriceCountry).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPriceCountry).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2Country).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.OldPrice2Country).HasColumnType("decimal(18,4)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Value).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.Price2).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Price2Gross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TaxRate).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TaxRateValue).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Total).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.TotalGross).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.Shipment).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.ShipmentGross).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Discount).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Budget).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.BudgetUsed).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceView).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.PriceClick).HasColumnType("decimal(18,4)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.RatingStatistics_AverageRating).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.RatingStatistics_TotalPoints).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,2)"); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.WalkPrice).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Points).HasColumnType("decimal(18,2)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Budget).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.BudgetUsed).HasColumnType("decimal(18,4)"); builder.Entity().Property(c => c.VoucherAmmount).HasColumnType("decimal(18,4)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.Price).HasColumnType("decimal(18,4)"); builder.Entity().HasNoKey().ToView(null); builder.Entity().Property(c => c.SubscriptionPrice).HasColumnType("decimal(18,4)"); } /// /// Speichern der Änderungen mit Auditing (wenn aktiviert) und Benutzername /// /// Benutzer der die Änderungen vorgenommen hat /// Gibt an, dass kein Audit-Eintrag erstellt werden soll, auch wenn Audit aktiviert ist /// Anzahl betroffener Datensätze public int SaveChanges(string userName, bool noAudit) { if (_auditOptions.IsEnabled && !noAudit) { var auditEntries = OnBeforeSaveChanges(userName); var result = base.SaveChanges(); OnAfterSaveChanges(auditEntries, userName).GetAwaiter().GetResult(); return result; } return base.SaveChanges(); } /// /// Speichern der Änderungen mit Auditing (wenn aktiviert) und Benutzername /// /// Benutzer der die Änderungen vorgenommen hat /// Gibt an, dass kein Audit-Eintrag erstellt werden soll, auch wenn Audit aktiviert ist /// Anzahl betroffener Datensätze public async Task SaveChangesAsync(string userName, bool noAudit) { if (_auditOptions.IsEnabled && !noAudit) { var auditEntries = OnBeforeSaveChanges(userName); var result = await base.SaveChangesAsync(); await OnAfterSaveChanges(auditEntries, userName); return result; } return await base.SaveChangesAsync(); } /// /// Hilfsmethode die, wenn Auditing aktiviert ist, die Änderungen erfasst. /// Wird so implementiert, da es Änderungne gibt die erst nach dem Speichern gültig werden /// /// Benutzername /// Liste von audit-Einträgen private List OnBeforeSaveChanges(string userName) { ChangeTracker.DetectChanges(); var auditEntries = new List(); foreach (var entry in ChangeTracker.Entries()) { if (entry.Entity is IAuditable == false || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged) continue; var entity = entry.Entity as IAuditable; var auditEntry = new AuditEntry(entry); auditEntry.Action = entry.State switch { EntityState.Added => AuditAction.Create, EntityState.Modified => AuditAction.Edit, EntityState.Deleted => AuditAction.Delete, _ => auditEntry.Action }; //Reagieren auf die individuellen Einstellungen der Entitäten - was soll geloggt werden switch (auditEntry.Action) { case AuditAction.Create when !entity.Options().HasFlag(AuditableOptions.Create): case AuditAction.Edit when !entity.Options().HasFlag(AuditableOptions.Edit): case AuditAction.Delete when !entity.Options().HasFlag(AuditableOptions.Delete): continue; } auditEntries.Add(auditEntry); HandleProperties(entry, auditEntry); foreach (var entryReference in entry.References) { var internalEntry = entryReference.TargetEntry; HandleProperties(internalEntry, auditEntry, entryReference.Metadata.Name); } } // Save audit entities that have all the modifications foreach (var auditEntry in auditEntries.Where(_ => !_.HasTemporaryProperties)) { Audits.Add(auditEntry.ToAudit(userName)); } // keep a list of entries where the value of some properties are unknown at this step return auditEntries.Where(_ => _.HasTemporaryProperties).ToList(); } /// /// Erfassen der einzelnen Properties für den AuditEntry /// /// EntityEntry /// AuditEntry /// Optional: Prefix wenn nested private static void HandleProperties(EntityEntry entry, AuditEntry auditEntry, string prefix = "") { if(entry == null || !entry.Properties.Any()) return; foreach (var property in entry.Properties) { if (property.IsTemporary) { // value will be generated by the database, get the value after saving auditEntry.TemporaryProperties.Add(property); continue; } var propertyName = property.Metadata.Name; if (!string.IsNullOrWhiteSpace(prefix)) propertyName = $"{prefix}.{propertyName}"; if (string.IsNullOrWhiteSpace(prefix)) { //Den Key nicht doppelt erfassen wenn es sich um eine nested property handelt if (property.Metadata.IsPrimaryKey()) { auditEntry.KeyValues[propertyName] = property.CurrentValue; continue; } } switch (entry.State) { case EntityState.Added: auditEntry.NewValues[propertyName] = property.CurrentValue; //auditEntry.Action = 1; break; case EntityState.Deleted: auditEntry.OldValues[propertyName] = property.OriginalValue; //auditEntry.Action = 3; break; case EntityState.Modified: if (property.IsModified) { auditEntry.OldValues[propertyName] = property.OriginalValue; auditEntry.NewValues[propertyName] = property.CurrentValue; //auditEntry.Action = 2; if (propertyName.ToLowerInvariant() == "deleted") { if (auditEntry.NewValues[propertyName] is bool) { var deleted = (bool)auditEntry.NewValues[propertyName]; if (deleted) auditEntry.Action = AuditAction.DeleteSoft; } } } break; } } } /// /// Behandelt von noch nicht gespeicherten Audit-Objekten. /// Hier wegen dem Umstand, dass nicht alle DB-Änderungen vor dem Speichern verfügbar ist /// /// /// /// private async Task OnAfterSaveChanges(List auditEntries, string userName) { if (auditEntries == null || auditEntries.Count == 0) return; foreach (var auditEntry in auditEntries) { // Get the final value of the temporary properties foreach (var prop in auditEntry.TemporaryProperties) { if (prop.Metadata.IsPrimaryKey()) { auditEntry.KeyValues[prop.Metadata.Name] = prop.CurrentValue; } else { auditEntry.NewValues[prop.Metadata.Name] = prop.CurrentValue; } } // Save the Audit entry Audits.Add(auditEntry.ToAudit(userName)); } await SaveChangesAsync(); } } /// /// Hilfsklasse für das Erfassen von Audits /// internal class AuditEntry { /// /// Erstellt eine Instanz /// /// Entity Entry public AuditEntry(EntityEntry entry) { Entry = entry; } public EntityEntry Entry { get; } /// /// Durchgeführte Aktion /// public AuditAction Action { get; set; } public Dictionary KeyValues { get; } = new Dictionary(); public Dictionary OldValues { get; } = new Dictionary(); public Dictionary NewValues { get; } = new Dictionary(); public List TemporaryProperties { get; } = new List(); public bool HasTemporaryProperties => TemporaryProperties.Any(); /// /// Konvertiert den Eintrag in die Audit-Klasse zum Speichern /// /// Benutzername /// public Audit ToAudit(string userName) { var jsonOptions = new JsonSerializerSettings() { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore, DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat, ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; jsonOptions.Converters.Add(new NetTopologySuite.IO.Converters.GeometryConverter()); var audit = new Audit { Key = ((IAuditable)this.Entry.Entity).AuditKey(), Table = ((IAuditable)this.Entry.Entity).AuditTable(), UserName = userName, Action = this.Action, DateTime = DateTimeOffset.UtcNow, KeyValues = KeyValues.Count == 0 ? null : JsonConvert.SerializeObject(KeyValues, jsonOptions), OldValues = OldValues.Count == 0 ? null : JsonConvert.SerializeObject(OldValues, jsonOptions), NewValues = NewValues.Count == 0 ? null : JsonConvert.SerializeObject(NewValues, jsonOptions) }; return audit; } } }