1098 lines
36 KiB
C#
1098 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Threading.Tasks;
|
|
using MongoDB.Driver;
|
|
using MongoDB.Driver.Linq;
|
|
using xCommons.Extensions;
|
|
using xDataService.Configuration;
|
|
using xDataService.Extensions;
|
|
using xDataService.Interfaces;
|
|
using xDataService.Models;
|
|
using xModels.Base;
|
|
using xModels.Dtos;
|
|
|
|
namespace xDataService.MongoRepositories {
|
|
/// <summary>
|
|
/// Base MongoDb Base Entity Repository Pattern implementation ...
|
|
/// Only Used on MongoDb ...
|
|
/// </summary>
|
|
/// <typeparam name="T">is the Entity type</typeparam>
|
|
/// <typeparam name="TKey">is the Entity Key Type</typeparam>
|
|
/// <typeparam name="TDbContext">is the DbContext Type</typeparam>
|
|
public abstract class XBaseMongoRepository<T, TKey> : IXBaseRepository<T, TKey>
|
|
where T : XBaseEntity<TKey> {
|
|
//
|
|
private readonly string collectionName;
|
|
public List<WriteModel<T>> bulkCollection;
|
|
public readonly IMongoCollection<T> collection;
|
|
private readonly IXKeyGenerator<T, TKey> keyGenerator;
|
|
public readonly XDataServiceConfiguration configuration;
|
|
private readonly IXBaseRepositoryEvents<T> baseRepositoryEvents;
|
|
|
|
//
|
|
public abstract IMongoQueryable<T> GetFullDbSet ();
|
|
|
|
//
|
|
#region Constructor ...
|
|
protected XBaseMongoRepository (
|
|
XDataServiceConfiguration configuration,
|
|
string collectionName = null,
|
|
IXKeyGenerator<T, TKey> keyGenerator = null,
|
|
IXBaseRepositoryEvents<T> baseRepositoryEvents = null
|
|
) {
|
|
//
|
|
this.keyGenerator = keyGenerator;
|
|
this.configuration = configuration;
|
|
this.collectionName = collectionName
|
|
.IsNullOrEmpty () ?
|
|
typeof (T).Name :
|
|
collectionName;
|
|
this.baseRepositoryEvents = baseRepositoryEvents;
|
|
|
|
//
|
|
var client = new MongoClient (configuration.GetMongoDbURI ());
|
|
var database = client.GetDatabase (configuration.GetMongoDbDatabase ());
|
|
|
|
//
|
|
bulkCollection = new List<WriteModel<T>> ();
|
|
collection = database.GetCollection<T> (
|
|
this.collectionName
|
|
);
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Add ...
|
|
public async Task<T> AddAsync (
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Handle Key ...
|
|
item = await HandleKeyAsync (item);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new InsertOneModel<T> (item));
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.AddEvent (new XBaseEventModel<T> (item));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
item :
|
|
null;
|
|
}
|
|
|
|
public async Task<T> AddOrUpdateAsync (
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
var isExists = await IsExistsAsync (GetKey (item));
|
|
if (!isExists) {
|
|
//
|
|
// Handle Key ...
|
|
item = await HandleKeyAsync (item);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection
|
|
.Add (new InsertOneModel<T> (item));
|
|
} else {
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, item.Id);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection
|
|
.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = true });
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
//
|
|
if (isExists) {
|
|
baseRepositoryEvents
|
|
.UpdateEvent (new XBaseEventModel<T> (item));
|
|
} else {
|
|
baseRepositoryEvents
|
|
.AddEvent (new XBaseEventModel<T> (item));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
item :
|
|
null;
|
|
}
|
|
|
|
public async Task AddRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
foreach (var item in items) {
|
|
//
|
|
// Handle Key ...
|
|
var keyHandledItem = await HandleKeyAsync (item);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new InsertOneModel<T> (keyHandledItem));
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.AddManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Remove ...
|
|
public async Task<T> RemoveAsync (
|
|
TKey id,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Retrieve Item ...
|
|
var item = await GetAsync (
|
|
id,
|
|
ignoreSoftDeleteds : softDelete
|
|
);
|
|
if (item.IsNull ()) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, id);
|
|
|
|
//
|
|
// Check SoftDelete ...
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
// Set Soft Delete ...
|
|
item.Deleted = true;
|
|
|
|
//
|
|
// Update ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = true });
|
|
} else {
|
|
//
|
|
// Delete ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new DeleteOneModel<T> (filter));
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
//
|
|
baseRepositoryEvents
|
|
.RemoveEvent (new XBaseEventModel<T> (item));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
item :
|
|
null;
|
|
}
|
|
|
|
public async Task<T> RemoveAsync (
|
|
T item,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Check item Exists ...
|
|
var isExists = await IsExistsAsync (item.Id);
|
|
if (item.IsNull ()) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, item.Id);
|
|
|
|
//
|
|
// Check SoftDelete ...
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
// Set Soft Delete ...
|
|
item.Deleted = true;
|
|
|
|
//
|
|
// Update ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = true });
|
|
} else {
|
|
//
|
|
// Delete ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new DeleteOneModel<T> (filter));
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
//
|
|
baseRepositoryEvents
|
|
.RemoveEvent (new XBaseEventModel<T> (item));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
item :
|
|
null;
|
|
}
|
|
|
|
public async Task RemoveRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool softDelete = true,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// loop through items ...
|
|
foreach (var item in items) {
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, item.Id);
|
|
|
|
//
|
|
// Check Soft Delete ...
|
|
if (softDelete && configuration.EnableSoftDelete) {
|
|
//
|
|
// Set Soft Delete ...
|
|
item.Deleted = true;
|
|
|
|
//
|
|
// Update ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = true });
|
|
} else {
|
|
//
|
|
// Delete ...
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new DeleteOneModel<T> (filter));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.RemoveManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Retrieve ...
|
|
public IQueryable<T> AsQueryable () {
|
|
return collection.AsQueryable ();
|
|
}
|
|
|
|
public async Task<T> GetAsync (
|
|
TKey id,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
// Retrieve Result ...
|
|
var result = await FindOneAsync (
|
|
whereClause: x => x.Id
|
|
.ToString ()
|
|
.ToNormalString () == id
|
|
.ToString ()
|
|
.ToNormalString (),
|
|
ignoreSoftDeleteds : true,
|
|
containsDetail : containsDetail
|
|
);
|
|
|
|
//
|
|
await Task.CompletedTask;
|
|
|
|
//
|
|
// Resturn Result ...
|
|
return result;
|
|
}
|
|
|
|
public async Task<IEnumerable<T>> GetAllAsync (
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
var result = GetDbSet (containsDetail: containsDetail)
|
|
.AsQueryable ()
|
|
.AsEnumerable ();
|
|
|
|
//
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
result = result.Where (i => i.Deleted == false);
|
|
}
|
|
|
|
//
|
|
await Task.CompletedTask;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
public async Task<T> FindOneAsync (
|
|
Expression<Func<T, bool>> whereClause,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
// Generate Where Function ...
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = await GetAsyncEnumerable (containsDetail);
|
|
|
|
//
|
|
T result = null;
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
//
|
|
result = entity;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
public async Task<IEnumerable<T>> FindManyAsync (
|
|
Expression<Func<T, bool>> whereClause,
|
|
bool ignoreSoftDeleteds = true,
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
// Generate Where Function ...
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = await GetAsyncEnumerable (containsDetail);
|
|
|
|
//
|
|
var result = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
result.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result.AsEnumerable ();
|
|
}
|
|
|
|
public async Task<XQueryResult<T>> QueryAsync (
|
|
XQuery query,
|
|
bool ignoreSoftDeleteds = true
|
|
) {
|
|
//
|
|
if (query.PageSize < configuration
|
|
.PagingConfiguration
|
|
.MinAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.DefaultPageSize;
|
|
}
|
|
|
|
//
|
|
if (query.PageSize > configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize;
|
|
}
|
|
|
|
//
|
|
// Where Filter Handler ...
|
|
Expression<Func<T, bool>> whereClause = i =>
|
|
i.PropValuesContains (query.Filter);
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = await GetAsyncEnumerable (
|
|
containsDetail: query.ContainsDetail
|
|
);
|
|
|
|
//
|
|
// Count Total Items ...
|
|
var totalItemsCount = GetQueryable (
|
|
containsDetail: query.ContainsDetail
|
|
)
|
|
.Count ();
|
|
|
|
//
|
|
var filteredItems = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = (query.Filter
|
|
.IsNullOrEmpty () ?
|
|
true :
|
|
whereFunc (entity)
|
|
) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
filteredItems.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count Filtered Items ...
|
|
int totalFilteredItemsCount = filteredItems.Count ();
|
|
|
|
//
|
|
// Apply Paging ...
|
|
var items = filteredItems
|
|
.ApplyPaging (
|
|
query.Page,
|
|
query.PageSize);
|
|
|
|
//
|
|
// Apply Sorting ...
|
|
if (!query.SortBy.IsNullOrEmpty ()) {
|
|
items = items
|
|
.ApplySorting<T, TKey> (
|
|
query.SortBy,
|
|
query.IsAscending);
|
|
}
|
|
|
|
//
|
|
// Generate Result Object ...
|
|
var queryResult = new XQueryResult<T> {
|
|
Items = filteredItems.AsEnumerable (),
|
|
Page = query.Page,
|
|
PageSize = query.PageSize,
|
|
TotalItems = totalItemsCount,
|
|
TotalPages = await PagesCountAsync (
|
|
query.PageSize,
|
|
totalFilteredItemsCount
|
|
),
|
|
TotalFilteredItems = totalFilteredItemsCount
|
|
};
|
|
|
|
//
|
|
return queryResult;
|
|
}
|
|
|
|
public async Task<XQueryResult<T>> ConditionalQueryAsync (
|
|
Expression<Func<T, bool>> whereClause,
|
|
XQuery query,
|
|
bool ignoreSoftDeleteds = true
|
|
) {
|
|
//
|
|
if (query.PageSize < configuration
|
|
.PagingConfiguration
|
|
.MinAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.DefaultPageSize;
|
|
}
|
|
|
|
//
|
|
if (query.PageSize > configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize) {
|
|
query.PageSize = configuration
|
|
.PagingConfiguration
|
|
.MaxAvailablePageSize;
|
|
}
|
|
|
|
//
|
|
// Generate Where Func ...
|
|
var whereFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Where Filter Handler ...
|
|
Expression<Func<T, bool>> whereFilterClause = i =>
|
|
i.PropValuesContains (query.Filter);
|
|
var whereFilterFunc = whereClause.Compile ();
|
|
|
|
//
|
|
// Handle Soft Deleted Items ...
|
|
Func<T, bool> ignoreSoftDeletedsWhereFunc = null;
|
|
if (ignoreSoftDeleteds && configuration.EnableSoftDelete) {
|
|
//
|
|
Expression<Func<T, bool>> ignoreSoftDeletedsWhereClause = x => x.Deleted == false;
|
|
ignoreSoftDeletedsWhereFunc = ignoreSoftDeletedsWhereClause.Compile ();
|
|
}
|
|
|
|
//
|
|
// Get Enumerable ...
|
|
var enumerator = await GetAsyncEnumerable (
|
|
containsDetail: query.ContainsDetail
|
|
);
|
|
|
|
//
|
|
// Count Total Items ...
|
|
var totalItemsCount = GetQueryable (
|
|
containsDetail: query.ContainsDetail
|
|
)
|
|
.Count ();
|
|
|
|
//
|
|
var filteredItems = new List<T> ();
|
|
await
|
|
foreach (var entity in enumerator) {
|
|
//
|
|
var isApproved = whereFunc (entity) &&
|
|
(query.Filter
|
|
.IsNullOrEmpty () ?
|
|
true :
|
|
whereFilterFunc (entity)
|
|
) &&
|
|
(ignoreSoftDeletedsWhereFunc.IsNull () ?
|
|
true :
|
|
ignoreSoftDeletedsWhereFunc (entity));
|
|
if (isApproved) {
|
|
filteredItems.Add (entity);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count Filtered Items ...
|
|
int totalFilteredItemsCount = filteredItems.Count ();
|
|
|
|
//
|
|
// Apply Paging ...
|
|
var items = filteredItems
|
|
.ApplyPaging (
|
|
query.Page,
|
|
query.PageSize);
|
|
|
|
//
|
|
// Apply Sorting ...
|
|
if (!query.SortBy.IsNullOrEmpty ()) {
|
|
items = items
|
|
.ApplySorting<T, TKey> (
|
|
query.SortBy,
|
|
query.IsAscending);
|
|
}
|
|
|
|
//
|
|
// Generate Result Object ...
|
|
var queryResult = new XQueryResult<T> {
|
|
Items = filteredItems.AsEnumerable (),
|
|
Page = query.Page,
|
|
PageSize = query.PageSize,
|
|
TotalItems = totalItemsCount,
|
|
TotalPages = await PagesCountAsync (
|
|
query.PageSize,
|
|
totalFilteredItemsCount
|
|
),
|
|
TotalFilteredItems = totalFilteredItemsCount
|
|
};
|
|
|
|
//
|
|
return queryResult;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Update ...
|
|
public async Task<T> UpdateAsync (
|
|
TKey id,
|
|
T item,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, id);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = false });
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.UpdateEvent (new XBaseEventModel<T> (item));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed ?
|
|
item :
|
|
null;
|
|
}
|
|
|
|
public async Task<bool> UpdateRangeAsync (
|
|
IEnumerable<T> items,
|
|
bool saveChanges = true
|
|
) {
|
|
//
|
|
// loop through items ...
|
|
foreach (var item in items) {
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Id, item.Id);
|
|
|
|
//
|
|
// Add Action model to Bulk Collection ...
|
|
bulkCollection.Add (new ReplaceOneModel<T> (filter, item) { IsUpsert = true });
|
|
}
|
|
|
|
//
|
|
// Check action is Succeeded or not ...
|
|
var isSucceed = false;
|
|
if (saveChanges) {
|
|
//
|
|
// Get Modified Count ...
|
|
var qResult = await SaveChangesAsync ();
|
|
|
|
//
|
|
// set isSucceed Value based on Changes ...
|
|
isSucceed = qResult > 0;
|
|
}
|
|
|
|
//
|
|
// Notify Event ...
|
|
if (
|
|
isSucceed &&
|
|
!baseRepositoryEvents.IsNull ()
|
|
) {
|
|
baseRepositoryEvents
|
|
.UpdateManyEvent (new XBaseEventModel<IEnumerable<T>> (null));
|
|
}
|
|
|
|
//
|
|
// Return result base on action Succeed ...
|
|
return isSucceed;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Count ...
|
|
public async Task<int> CountAsync (bool ignoreSoftDeleteds = true) {
|
|
//
|
|
// Filter ...
|
|
var filter = Builders<T>.Filter.Eq (i => i.Deleted, false);
|
|
|
|
//
|
|
var result = ignoreSoftDeleteds && configuration.EnableSoftDelete ? (int) GetDbSet ()
|
|
.Count (x => filter.Inject ()) :
|
|
(int) GetDbSet ()
|
|
.Count ();
|
|
|
|
//
|
|
await Task.CompletedTask;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
public async Task<int> PagesCountAsync (
|
|
int pageSize,
|
|
int? totalItems = null
|
|
) {
|
|
//
|
|
int count = totalItems.HasValue ? totalItems.Value : await CountAsync ();
|
|
int pagesCount = count / pageSize;
|
|
|
|
//
|
|
if (count % pageSize > 0) {
|
|
pagesCount++;
|
|
}
|
|
|
|
//
|
|
return pagesCount;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Exists ...
|
|
public async Task<bool> IsExistsAsync (TKey id, bool ignoreSoftDeleteds = true) {
|
|
//
|
|
var result = await FindOneAsync (i =>
|
|
GetKey (i)
|
|
.ToString () == id
|
|
.ToString (),
|
|
ignoreSoftDeleteds : ignoreSoftDeleteds,
|
|
containsDetail : false
|
|
);
|
|
|
|
//
|
|
return !result.IsNull ();
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Unit Of Work ...
|
|
public async Task<int> SaveChangesAsync () {
|
|
//
|
|
try {
|
|
//
|
|
// Write all Bulk Models which stored inside bulkCollection ...
|
|
var result = await collection
|
|
.BulkWriteAsync (bulkCollection);
|
|
|
|
//
|
|
// Clear Bulk Collection ...
|
|
bulkCollection.Clear ();
|
|
|
|
//
|
|
// Return number of Modified Documents ...
|
|
var resultCount = (int) result.ModifiedCount +
|
|
(int) result.InsertedCount +
|
|
(int) result.DeletedCount;
|
|
|
|
//
|
|
return resultCount;
|
|
} catch (Exception ex) {
|
|
//
|
|
// Log Thrown Exception ...
|
|
Console.WriteLine ($"XMongo Repository Exception: {ex.Message} ...");
|
|
|
|
//
|
|
// Return less than zero value ...
|
|
return -1;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Keys ...
|
|
public void SetKey (
|
|
ref T item,
|
|
TKey id
|
|
) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var keyProp = props.FirstOrDefault (p => p.Name == nameof (XBaseEntity<TKey>.Id));
|
|
if (keyProp.IsNull ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
Type t = Nullable.GetUnderlyingType (keyProp.PropertyType) ?? keyProp.PropertyType;
|
|
object safeValue = (id == null) ? null : Convert.ChangeType (id, t);
|
|
keyProp.SetValue (item, safeValue, null);
|
|
}
|
|
|
|
public TKey GetKey (T item) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var keyProp = props.FirstOrDefault (p => p.Name == nameof (XBaseEntity<TKey>.Id));
|
|
|
|
//
|
|
var keyString = string.Empty;
|
|
if (keyProp.IsNull ()) {
|
|
keyString = string.Empty;
|
|
} else {
|
|
keyString = keyProp.GetValue (item).ToString ();
|
|
}
|
|
|
|
//
|
|
if (keyString.IsNullOrEmpty ()) {
|
|
return default (TKey);
|
|
}
|
|
|
|
//
|
|
// Prevent Deserializing issues throug JsonReader ...
|
|
if (keyString.IsGuid () && typeof (TKey) == typeof (Guid)) {
|
|
return item.Id;
|
|
}
|
|
|
|
//
|
|
return keyString.FromJSON<TKey> ();
|
|
}
|
|
|
|
public async Task<T> HandleKeyAsync (T item) {
|
|
//
|
|
var keyType = typeof (TKey);
|
|
|
|
//
|
|
// Handle Guid Key Type ...
|
|
if (!keyGenerator.IsNull () &&
|
|
keyGenerator.IsEmpty (item.Id)
|
|
) {
|
|
//
|
|
var newKey = await keyGenerator.GenerateKey (this);
|
|
|
|
//
|
|
// InCrease Key if Type of TKey is Int and BulkDocs Contaisn Items ...
|
|
if (keyType == typeof (int)) {
|
|
//
|
|
var lastBulkedInsertedItem = bulkCollection
|
|
.Where (i => i.GetType () == typeof (InsertOneModel<T>))
|
|
.Select (i => (i as InsertOneModel<T>).Document)
|
|
.OrderByDescending (nameof (XBaseEntity<TKey>.Id))
|
|
.FirstOrDefault ();
|
|
|
|
//
|
|
// Renew Key if Exists inside bulkCollection ...
|
|
if (!lastBulkedInsertedItem.IsNull ()) {
|
|
//
|
|
var increasedKey = (Convert.ToInt32 (lastBulkedInsertedItem.Id)) + 1;
|
|
|
|
//
|
|
newKey = Convert.ChangeType (
|
|
increasedKey.ToDynamicObject (),
|
|
typeof (TKey)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
SetKey (ref item, newKey);
|
|
}
|
|
|
|
//
|
|
return item;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Detach ...
|
|
public void Detach (T item) { }
|
|
|
|
public void Detach (IEnumerable<T> items) { }
|
|
|
|
public void Detach (XQueryResult<T> query) { }
|
|
|
|
public void Detach (XPageResponse<T> page) { }
|
|
#endregion
|
|
|
|
//
|
|
#region Others ...
|
|
public void Dispose () { }
|
|
|
|
public string GetPropValues (T item) {
|
|
//
|
|
var props = item.GetType ().GetProperties ();
|
|
var vals = props.Select (p => p.GetValue (p.Name));
|
|
|
|
//
|
|
return vals.ToJSON ();
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
#region Private ...
|
|
private IMongoQueryable<T> GetDbSet (
|
|
bool containsDetail = false
|
|
) {
|
|
//
|
|
IMongoQueryable<T> result = null;
|
|
if (!containsDetail) {
|
|
result = collection
|
|
.AsQueryable ();
|
|
} else {
|
|
result = GetFullDbSet ();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private IMongoQueryable<T> GetQueryable (
|
|
bool containsDetail = false
|
|
) {
|
|
return GetDbSet (
|
|
containsDetail: containsDetail
|
|
);
|
|
// .AsQueryable ();
|
|
}
|
|
|
|
private async Task<IAsyncCursor<T>> GetAsyncCursor (
|
|
bool containsDetail = false
|
|
) {
|
|
return await GetQueryable (
|
|
containsDetail: containsDetail
|
|
)
|
|
.ToCursorAsync ();
|
|
}
|
|
|
|
private async Task<IAsyncEnumerable<T>> GetAsyncEnumerable (
|
|
bool containsDetail = false
|
|
) {
|
|
return (await GetAsyncCursor (
|
|
containsDetail: containsDetail
|
|
))
|
|
.ToAsyncEnumerable ();
|
|
}
|
|
#endregion
|
|
}
|
|
} |