diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/BaseEntity.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/BaseEntity.cs index aa331d1a..ea1d2d45 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/BaseEntity.cs +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/BaseEntity.cs @@ -1,9 +1,13 @@ using System; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; namespace Pcf.GivingToCustomer.Core.Domain { public class BaseEntity { + [BsonId] + [BsonRepresentation(BsonType.String)] public Guid Id { get; set; } } } \ No newline at end of file diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/Customer.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/Customer.cs index b41cb642..4f980bd7 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/Customer.cs +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Domain/Customer.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using System; +using System.Collections.Generic; namespace Pcf.GivingToCustomer.Core.Domain { @@ -7,13 +9,19 @@ public class Customer { public string FirstName { get; set; } public string LastName { get; set; } - public string FullName => $"{FirstName} {LastName}"; - public string Email { get; set; } + // связь многие-ко-многим как лист ID + [BsonRepresentation(MongoDB.Bson.BsonType.String)] + public List PreferenceIds { get; set; } = new List(); + + [BsonRepresentation(MongoDB.Bson.BsonType.String)] + public List PromoCodeIds { get; set; } = new List(); + + [BsonIgnore] public virtual ICollection Preferences { get; set; } - + [BsonIgnore] public virtual ICollection PromoCodes { get; set; } } } \ No newline at end of file diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Pcf.GivingToCustomer.Core.csproj b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Pcf.GivingToCustomer.Core.csproj index d36f76db..714f42fa 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Pcf.GivingToCustomer.Core.csproj +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.Core/Pcf.GivingToCustomer.Core.csproj @@ -4,4 +4,8 @@ net8.0 + + + + diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Data/MongoDbInitializer.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Data/MongoDbInitializer.cs new file mode 100644 index 00000000..6fb75519 --- /dev/null +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Data/MongoDbInitializer.cs @@ -0,0 +1,40 @@ +using MongoDB.Driver; +using Pcf.GivingToCustomer.Core.Domain; +using System.Linq; + +namespace Pcf.GivingToCustomer.DataAccess.Data +{ + public class MongoDbInitializer : IDbInitializer + { + private readonly IMongoDBContext _context; + + public MongoDbInitializer(IMongoDBContext context) + { + _context = context; + } + + public void InitializeDb() + { + // чистим БД + _context.Database.DropCollection(nameof(Preference) + "s"); + _context.Database.DropCollection(nameof(Customer) + "s"); + + // Добавляем Preferences + var preferencesCollection = _context.GetCollection(); + preferencesCollection.InsertMany(FakeDataFactory.Preferences); + + // Добавляем Customers с вложенными Preferences + var customersCollection = _context.GetCollection(); + var customers = FakeDataFactory.Customers.Select(c => + { + // В Mongo мы обычно не храним навигационные свойства, + // поэтому маппим Preferences -> список PreferenceIds + c.PreferenceIds = c.Preferences?.Select(p => p.PreferenceId).ToList(); + c.Preferences = null; // навигационные свойства игнорируем + return c; + }).ToList(); + + customersCollection.InsertMany(customers); + } + } +} \ No newline at end of file diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/IMongoDBContext.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/IMongoDBContext.cs new file mode 100644 index 00000000..c8f135ea --- /dev/null +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/IMongoDBContext.cs @@ -0,0 +1,10 @@ +using MongoDB.Driver; + +namespace Pcf.GivingToCustomer.DataAccess +{ + public interface IMongoDBContext + { + IMongoDatabase Database { get; } + IMongoCollection GetCollection(string name = null); + } +} diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/MongoDBContext.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/MongoDBContext.cs new file mode 100644 index 00000000..af5a4676 --- /dev/null +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/MongoDBContext.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.Options; +using MongoDB.Driver; +using Pcf.GivingToCustomer.DataAccess.Settings; + +namespace Pcf.GivingToCustomer.DataAccess +{ + public class MongoDBContext : IMongoDBContext + { + private readonly IMongoDatabase _database; + + public MongoDBContext(IOptions settings) + { + //клиент (один на приложение: singleton). Нужен для связи с сервером и работы с БД. + var client = new MongoClient(settings.Value.ConnectionString); + //по имени получаем БД + _database = client.GetDatabase(settings.Value.DatabaseName); + } + + //короткая запись для свойства с геттером + public IMongoDatabase Database => _database; + + public IMongoCollection GetCollection(string name = null) + { + var collectionName = name ?? typeof(T).Name + "s"; + return _database.GetCollection(collectionName); + } + } +} diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Pcf.GivingToCustomer.DataAccess.csproj b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Pcf.GivingToCustomer.DataAccess.csproj index 133057bc..137ff1d1 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Pcf.GivingToCustomer.DataAccess.csproj +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Pcf.GivingToCustomer.DataAccess.csproj @@ -6,6 +6,7 @@ + diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Repositories/MongoRepository.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Repositories/MongoRepository.cs new file mode 100644 index 00000000..3e2dfc1d --- /dev/null +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Repositories/MongoRepository.cs @@ -0,0 +1,64 @@ +using MongoDB.Driver; +using Pcf.GivingToCustomer.Core.Abstractions.Repositories; +using Pcf.GivingToCustomer.Core.Domain; +using Pcf.GivingToCustomer.DataAccess; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; + +public class MongoRepository : IRepository where T : BaseEntity +{ + private readonly IMongoCollection _collection; + + public MongoRepository(IMongoDBContext context) + { + _collection = context.GetCollection(); + } + + public async Task> GetAllAsync() + { + return await _collection.Find(_ => true).ToListAsync(); + } + + public async Task GetByIdAsync(Guid id) + { + var filter = Builders.Filter.Eq(e => e.Id, id); + return await _collection.Find(filter).FirstOrDefaultAsync(); + } + + public async Task> GetRangeByIdsAsync(List ids) + { + var filter = Builders.Filter.In(e => e.Id, ids); + return await _collection.Find(filter).ToListAsync(); + } + + public async Task GetFirstWhere(Expression> predicate) + { + var filter = Builders.Filter.Where(predicate); + return await _collection.Find(filter).FirstOrDefaultAsync(); + } + + public async Task> GetWhere(Expression> predicate) + { + var filter = Builders.Filter.Where(predicate); + return await _collection.Find(filter).ToListAsync(); + } + + public async Task AddAsync(T entity) + { + await _collection.InsertOneAsync(entity); + } + + public async Task UpdateAsync(T entity) + { + var filter = Builders.Filter.Eq(e => e.Id, entity.Id); + await _collection.ReplaceOneAsync(filter, entity); + } + + public async Task DeleteAsync(T entity) + { + var filter = Builders.Filter.Eq(e => e.Id, entity.Id); + await _collection.DeleteOneAsync(filter); + } +} diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Settings/MongoSettings.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Settings/MongoSettings.cs new file mode 100644 index 00000000..f3409246 --- /dev/null +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.DataAccess/Settings/MongoSettings.cs @@ -0,0 +1,8 @@ +namespace Pcf.GivingToCustomer.DataAccess.Settings +{ + public class MongoSettings + { + public string ConnectionString { get; set; } + public string DatabaseName { get; set; } + } +} diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.IntegrationTests/Pcf.GivingToCustomer.IntegrationTests.csproj b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.IntegrationTests/Pcf.GivingToCustomer.IntegrationTests.csproj index 94d5ff64..d0f39abe 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.IntegrationTests/Pcf.GivingToCustomer.IntegrationTests.csproj +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.IntegrationTests/Pcf.GivingToCustomer.IntegrationTests.csproj @@ -12,6 +12,7 @@ + all diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Pcf.GivingToCustomer.WebHost.csproj b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Pcf.GivingToCustomer.WebHost.csproj index 6ead61da..b4e2f6d5 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Pcf.GivingToCustomer.WebHost.csproj +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Pcf.GivingToCustomer.WebHost.csproj @@ -17,6 +17,7 @@ + diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Startup.cs b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Startup.cs index 601337fc..dd81fe45 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Startup.cs +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/Startup.cs @@ -1,21 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Castle.Core.Configuration; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Configuration; using Pcf.GivingToCustomer.Core.Abstractions.Gateways; using Pcf.GivingToCustomer.Core.Abstractions.Repositories; using Pcf.GivingToCustomer.DataAccess; using Pcf.GivingToCustomer.DataAccess.Data; -using Pcf.GivingToCustomer.DataAccess.Repositories; +using Pcf.GivingToCustomer.DataAccess.Settings; using Pcf.GivingToCustomer.Integration; + using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; namespace Pcf.GivingToCustomer.WebHost @@ -35,16 +28,26 @@ public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddMvcOptions(x=> x.SuppressAsyncSuffixInActionNames = false); - services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); + + // MongoDB + services.Configure(Configuration.GetSection("MongoSettings")); + // MongoContext + services.AddSingleton(); + // + services.AddScoped(typeof(IRepository<>), typeof(MongoRepository<>)); + // FakeRepository + services.AddScoped(); + + //services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); services.AddScoped(); - services.AddScoped(); - services.AddDbContext(x => + //services.AddScoped(); + /*services.AddDbContext(x => { //x.UseSqlite("Filename=PromocodeFactoryGivingToCustomerDb.sqlite"); x.UseNpgsql(Configuration.GetConnectionString("PromocodeFactoryGivingToCustomerDb")); x.UseSnakeCaseNamingConvention(); x.UseLazyLoadingProxies(); - }); + });*/ services.AddOpenApiDocument(options => { diff --git a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/appsettings.json b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/appsettings.json index cfae3069..683f2362 100644 --- a/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/appsettings.json +++ b/Homeworks/NoSQL/src/Pcf.GivingToCustomer/Pcf.GivingToCustomer.WebHost/appsettings.json @@ -6,8 +6,12 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "ConnectionStrings":{ - "PromocodeFactoryGivingToCustomerDb":"Host=localhost;Database=promocode_factory_givingToCustomer_db;Username=postgres;Password=docker;Port=5435" + "ConnectionStrings": { + "PromocodeFactoryGivingToCustomerDb": "Host=localhost;Database=promocode_factory_givingToCustomer_db;Username=postgres;Password=docker;Port=5435" + }, + "MongoSettings": { + "ConnectionString": "mongodb://admin:otus@localhost:27017", + "DatabaseName": "givingToCustomer" }, "AllowedHosts": "*" }