diff --git a/PhonebookService.Infrastructure/ModelConfigurations/PhonebookRecordEntityTypeConfiguration.cs b/PhonebookService.Infrastructure/ModelConfigurations/PhonebookRecordEntityTypeConfiguration.cs new file mode 100644 index 0000000..f5a3437 --- /dev/null +++ b/PhonebookService.Infrastructure/ModelConfigurations/PhonebookRecordEntityTypeConfiguration.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using PhonebookService.Domain.Models; + +namespace PhonebookService.Infrastructure.ModelConfigurations; + +/// +/// EF entity model configuration class for +/// +public class PhonebookRecordEntityTypeConfiguration + : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(i => i.Id); + builder.Property(i => i.FirstName).IsRequired(); + builder.Property(i => i.LastName).IsRequired(); + builder.Property(i => i.Email).IsRequired(); + builder.Property(i => i.PhoneNumber).IsRequired(); + builder.Property(i => i.StreetAddress).IsRequired(); + builder.Property(i => i.City).IsRequired(); + builder.Property(i => i.ZipCode).IsRequired(); + } +} diff --git a/PhonebookService.Infrastructure/PhonebookContext.cs b/PhonebookService.Infrastructure/PhonebookContext.cs new file mode 100644 index 0000000..0817f04 --- /dev/null +++ b/PhonebookService.Infrastructure/PhonebookContext.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore; +using PhonebookService.Domain.Models; +using PhonebookService.Infrastructure.ModelConfigurations; + +namespace PhonebookService.Infrastructure; + +/// +/// Phonebook EF database context +/// +public class PhonebookContext : DbContext +{ + public DbSet Records { get; set; } + +#pragma warning disable CS8618 // Non-nullable property must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + + public PhonebookContext(DbContextOptions options) : base(options) {} + +#pragma warning restore CS8618 // Non-nullable property must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + + protected override void OnModelCreating(ModelBuilder builder) + { + builder.ApplyConfiguration(new PhonebookRecordEntityTypeConfiguration()); + } +} diff --git a/PhonebookService.Infrastructure/PhonebookInfrastructureExtensions.cs b/PhonebookService.Infrastructure/PhonebookInfrastructureExtensions.cs new file mode 100644 index 0000000..476ee42 --- /dev/null +++ b/PhonebookService.Infrastructure/PhonebookInfrastructureExtensions.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.EntityFrameworkCore; +using PhonebookService.Domain.Repositories; +using PhonebookService.Infrastructure.Repositories; + +namespace PhonebookService.Infrastructure; + +/// +/// Extension class that helps to setup infrastructure layer +/// +public static class PhonebookInfrastructureExtensions +{ + /// + /// Configure infrastructure layer + /// + /// Collection of webapp services + /// Webapp configuration entity + /// If set true, EF will not hide personal data (e.g. passwords) when logging. Use only on debug! + public static IServiceCollection ConfigureInfrastructure(this IServiceCollection services, IConfiguration configuration, bool enableSensitiveDataLogging = false) + { + services.AddDbContext(options => + { + options.UseInMemoryDatabase("PhonebookDatabase"); + // options.UseSqlServer(configuration.GetConnectionString("PhonebookDatabase")); + + if (enableSensitiveDataLogging) + options.EnableSensitiveDataLogging(); + }); + + services.AddScoped(); + + return services; + } +} diff --git a/PhonebookService.Infrastructure/PhonebookService.Infrastructure.csproj b/PhonebookService.Infrastructure/PhonebookService.Infrastructure.csproj index c56912c..3d9d015 100644 --- a/PhonebookService.Infrastructure/PhonebookService.Infrastructure.csproj +++ b/PhonebookService.Infrastructure/PhonebookService.Infrastructure.csproj @@ -6,6 +6,8 @@ + + diff --git a/PhonebookService.Infrastructure/Repositories/PhonebookRepository.cs b/PhonebookService.Infrastructure/Repositories/PhonebookRepository.cs new file mode 100644 index 0000000..94d6120 --- /dev/null +++ b/PhonebookService.Infrastructure/Repositories/PhonebookRepository.cs @@ -0,0 +1,81 @@ +using PhonebookService.Domain.Models; +using PhonebookService.Domain.Queries; +using PhonebookService.Domain.Repositories; + +namespace PhonebookService.Infrastructure.Repositories; + +/// +/// Phonebook repository implementation +/// +public class PhonebookRepository : IPhonebookRepository +{ + private readonly PhonebookContext _context; + + public PhonebookRepository(PhonebookContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + /// + public async Task CreateItemAsync(PhonebookRecord item) + { + var entry = await _context.Records.AddAsync(item); + + await _context.SaveChangesAsync(); + + return entry.Entity; + } + + /// + public async Task DeleteItemAsync(PhonebookRecord item) + { + _context.Records.Remove(item); + + await _context.SaveChangesAsync(); + } + + /// + public async Task GetItemByIdAsync(int id) + { + var entry = await _context.Records.FindAsync(id); + + return entry; + } + + /// + public Task> GetItemsAsync(PhonebookFilterQuery query) + { + IQueryable dbQuery = _context.Records; + + if (query.FirstName is not null) + dbQuery = dbQuery.Where(i => i.FirstName.Contains(query.FirstName)); + + if (query.Phone is not null) + dbQuery = dbQuery.Where(i => i.PhoneNumber == query.Phone); + + if (query.City is not null) + dbQuery = dbQuery.Where(i => i.City == query.City); + + if (query.ZipCode is not null) + dbQuery = dbQuery.Where(i => i.ZipCode == query.ZipCode); + + if (query.Sort == SortMode.Ascending) + dbQuery = dbQuery.OrderBy(i => i.FirstName); + else if (query.Sort == SortMode.Descending) + dbQuery = dbQuery.OrderByDescending(i => i.FirstName); + + ICollection list = dbQuery.Skip((query.Page - 1) * 5).Take(5).ToList(); + + return Task.FromResult(list); + } + + /// + public async Task UpdateItemAsync(PhonebookRecord item) + { + var entry = _context.Records.Update(item); + + await _context.SaveChangesAsync(); + + return entry.Entity; + } +}