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;
+ }
+}