cs11dotnet7/vscode/PracticalApps/Northwind.WebApi/Repositories/CustomerRepository.cs

119 lines
3.1 KiB
C#
Raw Normal View History

2022-03-13 17:17:01 +01:00
using Microsoft.EntityFrameworkCore.ChangeTracking; // EntityEntry<T>
using Packt.Shared; // Customer
using System.Collections.Concurrent; // ConcurrentDictionary
namespace Northwind.WebApi.Repositories;
public class CustomerRepository : ICustomerRepository
{
2022-09-05 11:51:15 +02:00
// Use a static thread-safe dictionary field to cache the customers.
2022-03-13 17:17:01 +01:00
private static ConcurrentDictionary
<string, Customer>? customersCache;
2022-09-05 11:51:15 +02:00
// Use an instance data context field because it should not be
// cached due to the data context having internal caching.
2022-03-13 17:17:01 +01:00
private NorthwindContext db;
public CustomerRepository(NorthwindContext injectedContext)
{
db = injectedContext;
2022-09-05 11:51:15 +02:00
// Pre-load customers from database as a normal
2022-03-13 17:17:01 +01:00
// Dictionary with CustomerId as the key,
2022-09-05 11:51:15 +02:00
// then convert to a thread-safe ConcurrentDictionary.
2022-03-13 17:17:01 +01:00
if (customersCache is null)
{
customersCache = new ConcurrentDictionary<string, Customer>(
db.Customers.ToDictionary(c => c.CustomerId));
}
}
public async Task<Customer?> CreateAsync(Customer c)
{
2022-09-05 11:51:15 +02:00
// Normalize CustomerId into uppercase.
2022-03-13 17:17:01 +01:00
c.CustomerId = c.CustomerId.ToUpper();
2022-09-05 11:51:15 +02:00
// Add to database using EF Core.
2022-03-13 17:17:01 +01:00
EntityEntry<Customer> added = await db.Customers.AddAsync(c);
int affected = await db.SaveChangesAsync();
if (affected == 1)
{
if (customersCache is null) return c;
2022-09-05 11:51:15 +02:00
// If the customer is new, add it to cache, else
// call UpdateCache method.
2022-03-13 17:17:01 +01:00
return customersCache.AddOrUpdate(c.CustomerId, c, UpdateCache);
}
else
{
return null;
}
}
public Task<IEnumerable<Customer>> RetrieveAllAsync()
{
2022-09-05 11:51:15 +02:00
// For performance, get from cache.
2022-03-13 17:17:01 +01:00
return Task.FromResult(customersCache is null
? Enumerable.Empty<Customer>() : customersCache.Values);
}
public Task<Customer?> RetrieveAsync(string id)
{
2022-09-05 11:51:15 +02:00
// For performance, get from cache.
2022-03-13 17:17:01 +01:00
id = id.ToUpper();
if (customersCache is null) return null!;
customersCache.TryGetValue(id, out Customer? c);
return Task.FromResult(c);
}
private Customer UpdateCache(string id, Customer c)
{
Customer? old;
if (customersCache is not null)
{
if (customersCache.TryGetValue(id, out old))
{
if (customersCache.TryUpdate(id, c, old))
{
return c;
}
}
}
return null!;
}
public async Task<Customer?> UpdateAsync(string id, Customer c)
{
2022-09-05 11:51:15 +02:00
// Normalize customer Id.
2022-03-13 17:17:01 +01:00
id = id.ToUpper();
c.CustomerId = c.CustomerId.ToUpper();
2022-09-05 11:51:15 +02:00
// Update in database.
2022-03-13 17:17:01 +01:00
db.Customers.Update(c);
int affected = await db.SaveChangesAsync();
if (affected == 1)
{
2022-09-05 11:51:15 +02:00
// Update in cache.
2022-03-13 17:17:01 +01:00
return UpdateCache(id, c);
}
return null;
}
public async Task<bool?> DeleteAsync(string id)
{
id = id.ToUpper();
2022-09-05 11:51:15 +02:00
// Remove from database.
2022-03-13 17:17:01 +01:00
Customer? c = db.Customers.Find(id);
if (c is null) return null;
db.Customers.Remove(c);
int affected = await db.SaveChangesAsync();
if (affected == 1)
{
if (customersCache is null) return null;
2022-09-05 11:51:15 +02:00
// Remove from cache.
2022-03-13 17:17:01 +01:00
return customersCache.TryRemove(id, out c);
}
else
{
return null;
}
}
}