From e9b51a4b6653c461de3f0461f384a626869701ef Mon Sep 17 00:00:00 2001 From: hoang Date: Sun, 16 Sep 2018 19:37:57 +0700 Subject: [PATCH] update lib ref to 2.1.3 --- src/Swastika/Common/Helper/CommonHelper.cs | 52 +- .../Core/Repository/DefaultEcmRepositories.cs | 61 + .../Core/Repository/ViewEcmRepositoryBase.cs | 1668 +++++++++++++++++ .../Core/Repository/ViewRepositoryBase.cs | 9 +- .../Core/ViewModels/EcmViewModelBase.cs | 657 +++++++ src/Swastika/Swastika.csproj | 12 +- 6 files changed, 2426 insertions(+), 33 deletions(-) create mode 100644 src/Swastika/Domain/Core/Repository/DefaultEcmRepositories.cs create mode 100644 src/Swastika/Domain/Core/Repository/ViewEcmRepositoryBase.cs create mode 100644 src/Swastika/Domain/Core/ViewModels/EcmViewModelBase.cs diff --git a/src/Swastika/Common/Helper/CommonHelper.cs b/src/Swastika/Common/Helper/CommonHelper.cs index 278b515..20b033c 100644 --- a/src/Swastika/Common/Helper/CommonHelper.cs +++ b/src/Swastika/Common/Helper/CommonHelper.cs @@ -302,31 +302,35 @@ public static void WriteBytesToFile(string fullPath, string strBase64) } } - //TODO: Still need? - //public static string UploadPhoto(string fullPath, Image img) - //{ - // try - // { - // if (!Directory.Exists(fullPath)) - // { - // Directory.CreateDirectory(fullPath); - // } + public static string ConvertCaseString(string phrase, Case cases) + { + string[] splittedPhrase = phrase.Split(' ', '-', '.'); + var sb = new StringBuilder(); - // if (img != null) - // { - // //string fileExt = GetFilenameExtension(img.RawFormat); - // //file_name = (guid + fileExt).Trim(); - // //file_dir = filePath + file_name; - // //ImageResizer.ResizeStream(TTXConstants.Params.photoSize, img, file_dir); + if (cases == Case.CamelCase) + { + //splittedPhrase[0] = string.Empty; + } + else if (cases == Case.PascalCase) + sb.Append(splittedPhrase[0].ToLower()); + - // return ImageHelper.ResizeImage(img, fullPath); - // } - // } - // catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only - // { - // return string.Empty; - // } - // return string.Empty; - //} + foreach (String s in splittedPhrase) + { + char[] splittedPhraseChars = s.ToCharArray(); + if (splittedPhraseChars.Length > 0) + { + splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0]; + } + sb.Append(new String(splittedPhraseChars)); + } + return sb.ToString(); + } + + public enum Case + { + PascalCase, + CamelCase + } } } diff --git a/src/Swastika/Domain/Core/Repository/DefaultEcmRepositories.cs b/src/Swastika/Domain/Core/Repository/DefaultEcmRepositories.cs new file mode 100644 index 0000000..c5b7eef --- /dev/null +++ b/src/Swastika/Domain/Core/Repository/DefaultEcmRepositories.cs @@ -0,0 +1,61 @@ +// Licensed to the Swastika I/O Foundation under one or more agreements. +// The Swastika I/O Foundation licenses this file to you under the GNU General Public License v3.0. +// See the LICENSE file in the project root for more information. + +using Microsoft.EntityFrameworkCore; +using System; + +namespace Swastika.Domain.Data.Repository +{ + /// + /// Default Repository with view + /// + /// The type of the database context. + /// The type of the model. + /// The type of the view. + /// + public class EcmDefaultRepository : + Swastika.Domain.Data.Repository.EcmViewRepositoryBase + where TDbContext : DbContext + where TModel : class + where TView : Swastika.Domain.Data.ViewModels.EcmViewModelBase + { + /// + /// The instance + /// + private static volatile EcmDefaultRepository instance; + + /// + /// The synchronize root + /// + private static readonly object syncRoot = new Object(); + + /// + /// Prevents a default instance of the class from being created. + /// + private EcmDefaultRepository() + { + } + + /// + /// Gets the instance. + /// + /// + /// The instance. + /// + public static EcmDefaultRepository Instance { + get { + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + instance = new EcmDefaultRepository(); + } + } + + return instance; + } + } + } +} diff --git a/src/Swastika/Domain/Core/Repository/ViewEcmRepositoryBase.cs b/src/Swastika/Domain/Core/Repository/ViewEcmRepositoryBase.cs new file mode 100644 index 0000000..764acf3 --- /dev/null +++ b/src/Swastika/Domain/Core/Repository/ViewEcmRepositoryBase.cs @@ -0,0 +1,1668 @@ +// Licensed to the Swastika I/O Foundation under one or more agreements. +// The Swastika I/O Foundation licenses this file to you under the GNU General Public License v3.0. +// See the LICENSE file in the project root for more information. + +using AutoMapper; +using Microsoft.Data.OData.Query; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; +using Swastika.Common.Helper; +using Swastika.Domain.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; + +namespace Swastika.Domain.Data.Repository +{ + /// + /// View Repository Base + /// + /// The type of the database context. + /// The type of the model. + /// The type of the view. + public abstract class EcmViewRepositoryBase + where TDbContext : DbContext + where TModel : class + where TView : ViewModels.EcmViewModelBase + { + /// + /// Initializes a new instance of the class. + /// + protected EcmViewRepositoryBase() + { + //RegisterAutoMapper(); + } + + /// + /// Checks the is exists. + /// + /// The entity. + /// The context. + /// The transaction. + /// + public virtual bool CheckIsExists(TModel entity, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + //For the former case use: + return context.Set().Any(e => e == entity); + + //For the latter case use(it will check loaded entities as well): + //return (_context.Set().Find(keys) != null); + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + LogErrorMessage(ex); + if (isRoot) + { + transaction.Rollback(); + } + return false; + } + finally + { + if (isRoot) + { + //if current Context is Root + transaction.Dispose(); + context.Dispose(); + } + } + } + + /// + /// Checks the is exists. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public bool CheckIsExists(System.Func predicate, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + //For the former case use: + return context.Set().Any(predicate); + + //For the latter case use(it will check loaded entities as well): + //return (_context.Set().Find(keys) != null); + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + LogErrorMessage(ex); + if (isRoot) + { + transaction.Rollback(); + } + return false; + } + finally + { + if (isRoot) + { + //if current Context is Root + transaction.Dispose(); + context.Dispose(); + } + } + } + + /// + /// Creates the model. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse CreateModel(TView view + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + bool isRoot = _context == null; + TDbContext context = _context ?? InitContext(); + var transaction = _transaction ?? context.Database.BeginTransaction(); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + try + { + context.Entry(view.Model).State = EntityState.Added; + result.IsSucceed = context.SaveChanges() > 0; + result.Data = view; + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + LogErrorMessage(ex); + result.IsSucceed = false; + result.Exception = ex; + if (isRoot) + { + transaction.Rollback(); + } + return result; + } + finally + { + if (isRoot) + { + //if current Context is Root + transaction.Dispose(); + context.Dispose(); + } + } + } + + /// + /// Creates the model asynchronous. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual async Task> CreateModelAsync(TView view + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + try + { + context.Entry(view.Model).State = EntityState.Added; + result.IsSucceed = await context.SaveChangesAsync().ConfigureAwait(false) > 0; + result.Data = view; + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + transaction.Dispose(); + context.Dispose(); + } + } + } + + /// + /// Edits the model. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse EditModel(TView view + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + try + { + //context.Entry(view.Model).State = EntityState.Modified; + context.Set().Update(view.Model); + result.IsSucceed = context.SaveChanges() > 0; + result.Data = view; + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + transaction.Dispose(); + context.Dispose(); + } + } + } + + /// + /// Edits the model asynchronous. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual async Task> EditModelAsync(TView view, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + try + { + //context.Entry(view.Model).State = EntityState.Modified; + context.Set().Update(view.Model); + result.IsSucceed = await context.SaveChangesAsync().ConfigureAwait(false) > 0; + result.Data = view; + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the single model. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse GetSingleModel( + Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + context = _context ?? InitContext(); + transaction = _transaction ?? context.Database.BeginTransaction(); + + TModel model = context.Set().SingleOrDefault(predicate); + if (model != null) + { + context.Entry(model).State = EntityState.Detached; + var viewResult = ParseView(model, context, transaction); + return new RepositoryResponse() + { + IsSucceed = true, + Data = viewResult + }; + } + else + { + return new RepositoryResponse() + { + IsSucceed = false, + Data = default + }; + } + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context?.Dispose(); + } + } + } + + /// + /// Gets the single model asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task> GetSingleModelAsync( + Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + TModel model = await context.Set().SingleOrDefaultAsync(predicate).ConfigureAwait(false); + if (model != null) + { + context.Entry(model).State = EntityState.Detached; + + var viewResult = ParseView(model, context, transaction); + return new RepositoryResponse() + { + IsSucceed = true, + Data = viewResult + }; + } + else + { + return new RepositoryResponse() + { + IsSucceed = false, + Data = default + }; + } + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Initializes the context. + /// + /// + public virtual TDbContext InitContext() + { + Type classType = typeof(TDbContext); + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { }); + TDbContext context = (TDbContext)classConstructor.Invoke(new object[] { }); + + return context; + } + + /// + /// Logs the error message. User.Claims.ToList() error CS0103: The name 'User' does not exist in the current context + /// + /// The ex. + public virtual void LogErrorMessage(Exception ex) + { + } + + /// + /// Parses the paging query. + /// + /// The query. + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual PaginationModel ParsePagingQuery(IQueryable query + , string orderByPropertyName, int direction + , int? pageSize, int? pageIndex + , TDbContext context, IDbContextTransaction transaction) + { + List lstModel = new List(); + + PaginationModel result = new PaginationModel() + { + TotalItems = query.Count(), + PageIndex = pageIndex ?? 0 + }; + dynamic orderBy = GetLambda(CommonHelper.ConvertCaseString(orderByPropertyName, CommonHelper.Case.CamelCase)); + IQueryable sorted = null; + try + { + result.PageSize = pageSize ?? result.TotalItems; + + if (pageSize.HasValue) + { + result.TotalPage = (result.TotalItems / pageSize.Value) + (result.TotalItems % pageSize.Value > 0 ? 1 : 0); + } + + switch (direction) + { + case 1: + sorted = Queryable.OrderByDescending(query, orderBy); + if (pageSize.HasValue) + { + lstModel = sorted.Skip(pageIndex.Value * pageSize.Value) + .Take(pageSize.Value) + .ToList(); + } + else + { + lstModel = sorted.ToList(); + } + break; + + default: + sorted = Queryable.OrderBy(query, orderBy); + if (pageSize.HasValue) + { + lstModel = sorted + .Skip(pageIndex.Value * pageSize.Value) + .Take(pageSize.Value) + .ToList(); + } + else + { + lstModel = sorted.ToList(); + } + break; + } + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + var lstView = ParseView(lstModel, context, transaction); + result.Items = lstView; + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + LogErrorMessage(ex); + return null; + } + } + + /// + /// Parses the paging query asynchronous. + /// + /// The query. + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual async Task> ParsePagingQueryAsync(IQueryable query + , string orderByPropertyName, int direction + , int? pageSize, int? pageIndex + , TDbContext context, IDbContextTransaction transaction) + { + List lstModel = new List(); + + PaginationModel result = new PaginationModel() + { + TotalItems = query.Count(), + PageIndex = pageIndex ?? 0 + }; + dynamic orderBy = GetLambda(CommonHelper.ConvertCaseString(orderByPropertyName, CommonHelper.Case.CamelCase)); + IQueryable sorted = null; + try + { + result.PageSize = pageSize ?? result.TotalItems; + + if (pageSize.HasValue) + { + result.TotalPage = (result.TotalItems / pageSize.Value) + (result.TotalItems % pageSize.Value > 0 ? 1 : 0); + } + + switch (direction) + { + case 1: + sorted = Queryable.OrderByDescending(query, orderBy); + if (pageSize.HasValue) + { + lstModel = await sorted.Skip(pageIndex.Value * pageSize.Value) + .Take(pageSize.Value) + .ToListAsync().ConfigureAwait(false); + } + else + { + lstModel = sorted.ToList(); + } + break; + + default: + sorted = Queryable.OrderBy(query, orderBy); + if (pageSize.HasValue) + { + lstModel = await sorted + .Skip(pageIndex.Value * pageSize.Value) + .Take(pageSize.Value) + .ToListAsync().ConfigureAwait(false); + } + else + { + lstModel = await sorted.ToListAsync().ConfigureAwait(false); + } + break; + } + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + var lstView = ParseView(lstModel, context, transaction); + result.Items = lstView; + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + LogErrorMessage(ex); + return null; + } + } + + /// + /// Parses the view. + /// + /// The LST models. + /// The context. + /// The transaction. + /// + public virtual List ParseView(List lstModels, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + List lstView = new List(); + foreach (var model in lstModels) + { + lstView.Add(ParseView(model, _context, _transaction)); + } + + return lstView; + } + + /// + /// Parses the view. + /// + /// The model. + /// The context. + /// The transaction. + /// + public virtual TView ParseView(TModel model, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + Type classType = typeof(TView); + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { model.GetType(), typeof(TDbContext), typeof(IDbContextTransaction) }); + if (classConstructor != null) + { + return (TView)classConstructor.Invoke(new object[] { model, _context, _transaction }); + } + else + { + classConstructor = classType.GetConstructor(new Type[] { model.GetType() }); + return (TView)classConstructor.Invoke(new object[] { model }); + } + } + + /// + /// Registers the automatic mapper. + /// + public virtual void RegisterAutoMapper() + { + Mapper.Initialize(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + } + + #region GetModelList + + /// + /// Gets the model list. + /// + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse> GetModelList(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + bool isRoot = _context == null; + var context = _context ?? InitContext(); + var transaction = _transaction ?? context.Database.BeginTransaction(); + List result = new List(); + try + { + var lstModel = context.Set().ToList(); + + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + result = ParseView(lstModel, context, transaction); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list. + /// + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse> GetModelList( + string orderByPropertyName, int direction, int? pageSize, int? pageIndex + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + bool isRoot = _context == null; + var context = _context ?? InitContext(); + var transaction = _transaction ?? context.Database.BeginTransaction(); + + try + { + var query = context.Set(); + + var result = ParsePagingQuery(query, orderByPropertyName, direction, pageSize, pageIndex + , context, transaction); + + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list asynchronous. + /// + /// The context. + /// The transaction. + /// + public virtual async Task>> GetModelListAsync(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + bool isRoot = _context == null; + var context = _context ?? InitContext(); + var transaction = _transaction ?? context.Database.BeginTransaction(); + List result = new List(); + try + { + var lstModel = await context.Set().ToListAsync().ConfigureAwait(false); + + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + result = ParseView(lstModel, _context, _transaction); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list asynchronous. + /// + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual async Task>> GetModelListAsync( + string orderByPropertyName, int direction, int? pageSize, int? pageIndex + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + bool isRoot = _context == null; + var context = _context ?? InitContext(); + var transaction = _transaction ?? context.Database.BeginTransaction(); + + try + { + var query = context.Set(); + + var result = await ParsePagingQueryAsync(query, orderByPropertyName, direction, pageSize, pageIndex, context, transaction).ConfigureAwait(false); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion GetModelList + + #region GetModelListBy + + /// + /// Gets the model list by. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse> GetModelListBy(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var lstModel = context.Set().Where(predicate).ToList(); + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + var lstViewResult = ParseView(lstModel, _context, _transaction); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = lstViewResult + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list by. + /// + /// The predicate. + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse> GetModelListBy( + Expression> predicate, string orderByPropertyName, int direction, int? pageSize, int? pageIndex + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var query = context.Set().Where(predicate); + var result = ParsePagingQuery(query + , orderByPropertyName, direction + , pageSize, pageIndex + , context, transaction); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list by asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task>> GetModelListByAsync(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + + try + { + var query = context.Set().Where(predicate); + var lstModel = await query.ToListAsync().ConfigureAwait(false); + lstModel.ForEach(model => context.Entry(model).State = EntityState.Detached); + var result = ParseView(lstModel, _context, _transaction); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Gets the model list by asynchronous. + /// + /// The predicate. + /// Name of the order by property. + /// The direction. + /// Size of the page. + /// Index of the page. + /// The context. + /// The transaction. + /// + public virtual async Task>> GetModelListByAsync( + Expression> predicate, string orderByPropertyName + , int direction, int? pageSize, int? pageIndex + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var query = context.Set().Where(predicate); + + var result = await ParsePagingQueryAsync(query + , orderByPropertyName, direction + , pageSize, pageIndex + , context, transaction).ConfigureAwait(false); + return new RepositoryResponse>() + { + IsSucceed = true, + Data = result + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion GetModelListBy + + // TODO: Should return return enum status code instead + /// + /// Removes the list model. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse> RemoveListModel(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var Items = context.Set().Where(predicate).ToList(); + bool result = true; + if (Items != null) + { + foreach (var model in Items) + { + if (result) + { + var r = RemoveModel(model, context, transaction); + result = result && r.IsSucceed; + } + else + { + break; + } + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse>() + { + IsSucceed = result, + Data = Items + }; + } + else + { + return new RepositoryResponse>() + { + IsSucceed = result, + Data = Items + }; + } + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + // TODO: Should return return enum status code instead + /// + /// Removes the list model asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task>> RemoveListModelAsync(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var Items = await context.Set().Where(predicate).ToListAsync().ConfigureAwait(false); + bool result = true; + if (Items != null) + { + foreach (var model in Items) + { + if (result) + { + var r = await RemoveModelAsync(model, context, transaction).ConfigureAwait(false); + result = result && r.IsSucceed; + } + else + { + break; + } + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse>() + { + IsSucceed = result, + Data = Items + }; + } + else + { + return new RepositoryResponse>() + { + IsSucceed = true, + Data = Items + }; + } + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + // TODO: Should return return enum status code instead + /// + /// Removes the model. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse RemoveModel(Expression> predicate, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + TModel model = context.Set().FirstOrDefault(predicate); + bool result = true; + if (model != null && CheckIsExists(model, context, transaction)) + { + context.Entry(model).State = EntityState.Deleted; + result = context.SaveChanges() > 0; + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse() + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + // TODO: Should return return enum status code instead + /// + /// Removes the model. + /// + /// The model. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse RemoveModel(TModel model, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + bool result = true; + if (model != null && CheckIsExists(model, context, transaction)) + { + context.Entry(model).State = EntityState.Deleted; + result = context.SaveChanges() > 0; + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse() + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + // TODO: Should return return enum status code instead + /// + /// Removes the model asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task> RemoveModelAsync(Expression> predicate, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + TModel model = await context.Set().FirstOrDefaultAsync(predicate).ConfigureAwait(false); + bool result = true; + if (model != null && CheckIsExists(model, context, transaction)) + { + context.Entry(model).State = EntityState.Deleted; + result = await context.SaveChangesAsync().ConfigureAwait(false) > 0; + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse() + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + // TODO: Should return return enum status code instead + /// + /// Removes the model asynchronous. + /// + /// The model. + /// The context. + /// The transaction. + /// + public virtual async Task> RemoveModelAsync(TModel model, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + bool result = true; + if (model != null && CheckIsExists(model, context, transaction)) + { + context.Entry(model).State = EntityState.Deleted; + result = await context.SaveChangesAsync().ConfigureAwait(false) > 0; + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse() + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Saves the model. + /// + /// The view. + /// if set to true [is save sub models]. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse SaveModel(TView view, bool isSaveSubModels = false + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + if (CheckIsExists(view.Model, _context, _transaction)) + { + return EditModel(view, _context, _transaction); + } + else + { + return CreateModel(view, _context, _transaction); + } + } + + /// + /// Saves the model asynchronous. + /// + /// The view. + /// if set to true [is save sub models]. + /// The context. + /// The transaction. + /// + public virtual Task> SaveModelAsync(TView view, bool isSaveSubModels = false + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + if (CheckIsExists(view.Model, _context, _transaction)) + { + return EditModelAsync(view, _context, _transaction); + } + else + { + return CreateModelAsync(view, _context, _transaction); + } + } + + /// + /// Saves the sub model asynchronous. + /// + /// The model. + /// The context. + /// The transaction. + /// + /// + public virtual Task SaveSubModelAsync(TModel model, TDbContext context, IDbContextTransaction _transaction) + { + throw new NotImplementedException(); + } + + #region Max + + /// + /// Maximums the specified predicate. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse Max(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + var result = new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + try + { + total = context.Set().Max(predicate); + result.Data = total; + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleObjectException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Maximums the asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task> MaxAsync(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + try + { + total = await context.Set().MaxAsync(predicate).ConfigureAwait(false); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleObjectException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion Max + + #region Count + + /// + /// Counts the specified predicate. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse Count(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + try + { + total = context.Set().Count(predicate); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleObjectException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Counts the asynchronous. + /// + /// The predicate. + /// The context. + /// The transaction. + /// + public virtual async Task> CountAsync(Expression> predicate + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + try + { + total = await context.Set().CountAsync(predicate).ConfigureAwait(false); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + UnitOfWorkHelper.HandleException>(ex, isRoot, transaction); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion Count + + #region Count + + /// + /// Counts the specified context. + /// + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse Count(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + try + { + total = context.Set().Count(); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleObjectException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Counts the asynchronous. + /// + /// The context. + /// The transaction. + /// + public virtual async Task> CountAsync(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + int total = 0; + try + { + total = await context.Set().CountAsync().ConfigureAwait(false); + return new RepositoryResponse() + { + IsSucceed = true, + Data = total + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleObjectException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion Count + + #region Update Fields + + /// + /// Updates the fields. + /// + /// The predicate. + /// The fields. + /// The context. + /// The transaction. + /// + public RepositoryResponse UpdateFields(Expression> predicate + , List fields + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + bool result = false; + TModel model = context.Set().FirstOrDefault(predicate); + if (model != null) + { + foreach (var field in fields) + { + field.PropertyName = CommonHelper.ConvertCaseString(field.PropertyName, CommonHelper.Case.CamelCase); + var lamda = GetLambda(field.PropertyName, false); + if (lamda != null) + { + var prop = context.Entry(model).Property(field.PropertyName); + if (DateTime.TryParse(field.PropertyValue, out DateTime dateValue)) + { + prop.CurrentValue = dateValue; + } + else if (int.TryParse(field.PropertyValue, out int integerValue)) + { + prop.CurrentValue = integerValue; + } + else + { + prop.CurrentValue = field.PropertyValue; + } + + context.SaveChanges(); + result = true; + } + else + { + result = false; + break; + } + } + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse() + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Updates the fields asynchronous. + /// + /// The predicate. + /// The fields. + /// The context. + /// The transaction. + /// + public async Task> UpdateFieldsAsync(Expression> predicate + , List fields + , TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + bool result = false; + TModel model = await context.Set().FirstOrDefaultAsync(predicate).ConfigureAwait(false); + if (model != null) + { + foreach (var field in fields) + { + field.PropertyName = CommonHelper.ConvertCaseString(field.PropertyName, CommonHelper.Case.CamelCase); + var lamda = GetLambda(field.PropertyName, false); + if (lamda != null) + { + var prop = context.Entry(model).Property(field.PropertyName); + if (DateTime.TryParse(field.PropertyValue, out DateTime dateValue)) + { + prop.CurrentValue = dateValue; + } + else if (int.TryParse(field.PropertyValue, out int integerValue)) + { + prop.CurrentValue = integerValue; + } + else + { + prop.CurrentValue = field.PropertyValue; + } + + await context.SaveChangesAsync().ConfigureAwait(false); + result = true; + } + else + { + result = false; + break; + } + } + } + + UnitOfWorkHelper.HandleTransaction(result, isRoot, transaction); + + return new RepositoryResponse + { + IsSucceed = result, + Data = model + }; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + #endregion Update Fields + + /// + /// Gets the lambda. + /// + /// Name of the property. + /// if set to true [is get default]. + /// + protected LambdaExpression GetLambda(string propName, bool isGetDefault = true) + { + + var parameter = Expression.Parameter(typeof(TModel)); + var type = typeof(TModel); + var prop = Array.Find(type.GetProperties(), p => p.Name.ToLower() == propName.ToLower()); + if (prop == null && isGetDefault) + { + propName = type.GetProperties().FirstOrDefault()?.Name; + } + var memberExpression = Expression.Property(parameter, propName); + return Expression.Lambda(memberExpression, parameter); + } + } +} diff --git a/src/Swastika/Domain/Core/Repository/ViewRepositoryBase.cs b/src/Swastika/Domain/Core/Repository/ViewRepositoryBase.cs index a4d8f5d..abc69c0 100644 --- a/src/Swastika/Domain/Core/Repository/ViewRepositoryBase.cs +++ b/src/Swastika/Domain/Core/Repository/ViewRepositoryBase.cs @@ -406,7 +406,7 @@ public virtual PaginationModel ParsePagingQuery(IQueryable query TotalItems = query.Count(), PageIndex = pageIndex ?? 0 }; - dynamic orderBy = GetLambda(orderByPropertyName); + dynamic orderBy = GetLambda(CommonHelper.ConvertCaseString(orderByPropertyName, CommonHelper.Case.CamelCase)); IQueryable sorted = null; try { @@ -483,7 +483,7 @@ public virtual async Task> ParsePagingQueryAsync(IQueryab TotalItems = query.Count(), PageIndex = pageIndex ?? 0 }; - dynamic orderBy = GetLambda(orderByPropertyName); + dynamic orderBy = GetLambda(CommonHelper.ConvertCaseString(orderByPropertyName, CommonHelper.Case.CamelCase)); IQueryable sorted = null; try { @@ -1520,6 +1520,7 @@ public RepositoryResponse UpdateFields(Expression> pr { foreach (var field in fields) { + field.PropertyName = CommonHelper.ConvertCaseString(field.PropertyName, CommonHelper.Case.CamelCase); var lamda = GetLambda(field.PropertyName, false); if (lamda != null) { @@ -1591,6 +1592,7 @@ public async Task> UpdateFieldsAsync(Expression> UpdateFieldsAsync(Expression protected LambdaExpression GetLambda(string propName, bool isGetDefault = true) { + var parameter = Expression.Parameter(typeof(TModel)); var type = typeof(TModel); - var prop = Array.Find(type.GetProperties(), p => p.Name == propName); + var prop = Array.Find(type.GetProperties(), p => p.Name.ToLower() == propName.ToLower()); if (prop == null && isGetDefault) { propName = type.GetProperties().FirstOrDefault()?.Name; diff --git a/src/Swastika/Domain/Core/ViewModels/EcmViewModelBase.cs b/src/Swastika/Domain/Core/ViewModels/EcmViewModelBase.cs new file mode 100644 index 0000000..0e04394 --- /dev/null +++ b/src/Swastika/Domain/Core/ViewModels/EcmViewModelBase.cs @@ -0,0 +1,657 @@ +// Licensed to the Swastika I/O Foundation under one or more agreements. +// The Swastika I/O Foundation licenses this file to you under the GNU General Public License v3.0. +// See the LICENSE file in the project root for more information. + +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; +using Newtonsoft.Json; +using Swastika.Common.Helper; +using Swastika.Domain.Core.Models; +using Swastika.Domain.Core.ViewModels; +using Swastika.Domain.Data.Repository; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using static Swastika.Common.Utility.Enums; + +namespace Swastika.Domain.Data.ViewModels +{ + /// + /// + /// + /// The type of the database context. + /// The type of the model. + /// The type of the view. + public abstract class EcmViewModelBase + where TDbContext : DbContext + where TModel : class + where TView : EcmViewModelBase // instance of inherited + { + #region Properties + + [JsonProperty("priority")] + public int Priority { get; set; } + + /// + /// Returns true if ... is valid. + /// + private bool isValid = true; + + /// + /// The mapper + /// + private IMapper _mapper; + + /// + /// The model + /// + private TModel _model; + + /// + /// The model mapper + /// + private IMapper _modelMapper; + + [JsonIgnore] + public static readonly EcmDefaultRepository Repository; + + static EcmViewModelBase() + { + Repository = EcmDefaultRepository.Instance; + } + + /// + /// Gets or sets the exception. + /// + /// + /// The exception. + /// + [JsonIgnore] + public Exception Exception { get; set; } + + /// + /// Gets or sets the mapper. + /// + /// + /// The mapper. + /// + [JsonIgnore] + public IMapper Mapper + { + get { return _mapper ?? (_mapper = this.CreateMapper()); } + set => _mapper = value; + } + + /// + /// Gets or sets the model. + /// + /// + /// The model. + /// + [JsonIgnore] + public TModel Model + { + get + { + if (_model == null) + { + Type classType = typeof(TModel); + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { }); + _model = (TModel)classConstructor.Invoke(new object[] { }); + } + return _model; + } + set => _model = value; + } + + /// + /// Gets or sets the model mapper. + /// + /// + /// The model mapper. + /// + [JsonIgnore] + public IMapper ModelMapper + { + get { return _modelMapper ?? (_modelMapper = this.CreateModelMapper()); } + set => _modelMapper = value; + } + + /// + /// Creates the mapper. + /// + /// + private IMapper CreateMapper() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().ReverseMap()); + var mapper = new Mapper(config); + return mapper; + } + + /// + /// Creates the model mapper. + /// + /// + private IMapper CreateModelMapper() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().ReverseMap()); + var mapper = new Mapper(config); + return mapper; + } + + [JsonIgnore] + public List Errors { get; set; } = new List(); + + [JsonIgnore] + [JsonProperty("isValid")] + public bool IsValid { get => isValid; set => isValid = value; } + + #endregion Properties + + #region Common + + /// + /// Initializes the model. + /// + /// + public virtual TModel InitModel() + { + Type classType = typeof(TModel); + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { }); + TModel context = (TModel)classConstructor.Invoke(new object[] { }); + + return context; + } + + /// + /// Parses the model. + /// + /// + public virtual TModel ParseModel(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + //AutoMapper.Mapper.Map((TView)this, Model); + this.Model = InitModel(); + Mapper.Map((TView)this, Model); + return this.Model; + } + + /// + /// Validates the specified context. + /// + /// The context. + /// The transaction. + public virtual void Validate(TDbContext _context, IDbContextTransaction _transaction) + { + var validateContext = new System.ComponentModel.DataAnnotations.ValidationContext(this, serviceProvider: null, items: null); + var results = new List(); + + IsValid = Validator.TryValidateObject(this, validateContext, results); + if (!IsValid) + { + Errors.AddRange(results.Select(e => e.ErrorMessage)); + } + } + + #endregion Common + + #region Async + + /// + /// Expands the view. + /// + /// The context. + /// The transaction. + public virtual Task ExpandViewAsync(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + var taskSource = new TaskCompletionSource(); + taskSource.SetResult(true); + return taskSource.Task; + } + + + /// + /// Initializes the view. + /// + /// The model. + /// if set to true [is lazy load]. + /// The context. + /// The transaction. + /// + public static async Task InitViewAsync(TModel model = null, bool isLazyLoad = true, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + Type classType = typeof(TView); + + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { }); + if (model == null && classConstructor != null) + { + var view = (TView)classConstructor.Invoke(new object[] { }); + await view.ParseViewAsync(true, _context, _transaction); + return view; + } + else + { + classConstructor = classType.GetConstructor(new Type[] { typeof(TModel), typeof(bool), typeof(TDbContext), typeof(IDbContextTransaction) }); + if (classConstructor != null) + { + var view = (TView)classConstructor.Invoke(new object[] { model, isLazyLoad, _context, _transaction }); + await view.ParseViewAsync(isLazyLoad, _context, _transaction); + return view; + } + else + { + classConstructor = classType.GetConstructor(new Type[] { typeof(TModel), typeof(TDbContext), typeof(IDbContextTransaction) }); + var view = (TView)classConstructor.Invoke(new object[] { model, _context, _transaction }); + await view.ParseViewAsync(isLazyLoad, _context, _transaction); + return view; + } + } + } + + /// + /// Parses the view. + /// + /// if set to true [is expand]. + /// The context. + /// The transaction. + /// + public virtual async Task ParseViewAsync(bool isExpand = true, TDbContext _context = null, IDbContextTransaction _transaction = null + ) + { + Mapper.Map(Model, (TView)this); + if (isExpand) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + var expandResult = await ExpandViewAsync(context, transaction); + if (expandResult) + { + return this as TView; + } + else + { + return null; + } + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + Repository.LogErrorMessage(ex); + if (isRoot) + { + //if current transaction is root transaction + transaction.Rollback(); + } + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + return (TView)this; + } + + /// + /// Removes the related models asynchronous. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual async Task> RemoveRelatedModelsAsync(TView view, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + var taskSource = new TaskCompletionSource>(); + taskSource.SetResult(new RepositoryResponse() { IsSucceed = true }); + return await taskSource.Task; + } + + /// + /// Saves the model asynchronous. + /// + /// if set to true [is save sub models]. + /// The context. + /// The transaction. + /// + public virtual async Task> SaveModelAsync(bool isSaveSubModels = false, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + Validate(context, transaction); + if (IsValid) + { + try + { + ParseModel(context, transaction); + result = await Repository.SaveModelAsync((TView)this, _context: context, _transaction: transaction).ConfigureAwait(false); + + // Save sub Models + if (result.IsSucceed && isSaveSubModels) + { + var saveResult = await SaveSubModelsAsync(Model, context, transaction).ConfigureAwait(false); + if (!saveResult.IsSucceed) + { + result.Errors.AddRange(saveResult.Errors); + result.Exception = saveResult.Exception; + } + result.IsSucceed = result.IsSucceed && saveResult.IsSucceed; + } + + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + else + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + return new RepositoryResponse() + { + IsSucceed = false, + Data = null, + Errors = Errors + }; + } + } + + /// + /// Saves the sub models asynchronous. + /// + /// The parent. + /// The context. + /// The transaction. + /// + public virtual async Task> SaveSubModelsAsync(TModel parent, TDbContext _context, IDbContextTransaction _transaction) + { + var taskSource = new TaskCompletionSource>(); + taskSource.SetResult(new RepositoryResponse() { IsSucceed = true }); + return await taskSource.Task; + } + + #endregion Async + + #region Sync + + /// + /// Initializes the view. + /// + /// The model. + /// if set to true [is lazy load]. + /// The context. + /// The transaction. + /// + public virtual TView InitView(TModel model = null, bool isLazyLoad = true, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + Type classType = typeof(TView); + + ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { }); + if (model == null && classConstructor != null) + { + return (TView)classConstructor.Invoke(new object[] { }); + } + else + { + classConstructor = classType.GetConstructor(new Type[] { typeof(TModel), typeof(bool), typeof(TDbContext), typeof(IDbContextTransaction) }); + if (classConstructor != null) + { + return (TView)classConstructor.Invoke(new object[] { model, isLazyLoad, _context, _transaction }); + } + else + { + classConstructor = classType.GetConstructor(new Type[] { typeof(TModel), typeof(TDbContext), typeof(IDbContextTransaction) }); + return (TView)classConstructor.Invoke(new object[] { model, _context, _transaction }); + } + } + } + + + /// + /// Parses the view. + /// + /// if set to true [is expand]. + /// The context. + /// The transaction. + /// + public virtual TView ParseView(bool isExpand = true, TDbContext _context = null, IDbContextTransaction _transaction = null + ) + { + //AutoMapper.Mapper.Map(Model, (TView)this); + Mapper.Map(Model, (TView)this); + if (isExpand) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + try + { + ExpandView(context, transaction); + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + Repository.LogErrorMessage(ex); + if (isRoot) + { + //if current transaction is root transaction + transaction.Rollback(); + } + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + return (TView)this; + } + + /// + /// Expands the view. + /// + /// The context. + /// The transaction. + public virtual void ExpandView(TDbContext _context = null, IDbContextTransaction _transaction = null) + { + } + + /// + /// Removes the model. + /// + /// if set to true [is remove related models]. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse RemoveModel(bool isRemoveRelatedModels = false, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + try + { + ParseModel(_context, _transaction); + if (isRemoveRelatedModels) + { + var removeRelatedResult = RemoveRelatedModels((TView)this, context, transaction); + if (removeRelatedResult.IsSucceed) + { + result = Repository.RemoveModel(Model, context, transaction); + } + else + { + result.IsSucceed = result.IsSucceed && removeRelatedResult.IsSucceed; + result.Errors.AddRange(removeRelatedResult.Errors); + result.Exception = removeRelatedResult.Exception; + } + } + else + { + result = Repository.RemoveModel(Model, context, transaction); + } + + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + + /// + /// Removes the related models. + /// + /// The view. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse RemoveRelatedModels(TView view, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + return new RepositoryResponse() { IsSucceed = true }; + } + + /// + /// Saves the model. + /// + /// if set to true [is save sub models]. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse SaveModel(bool isSaveSubModels = false, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + UnitOfWorkHelper.InitTransaction(_context, _transaction, out TDbContext context, out IDbContextTransaction transaction, out bool isRoot); + RepositoryResponse result = new RepositoryResponse() { IsSucceed = true }; + Validate(context, transaction); + if (IsValid) + { + try + { + ParseModel(context, transaction); + result = Repository.SaveModel((TView)this, _context: context, _transaction: transaction); + + // Save sub Models + if (result.IsSucceed && isSaveSubModels) + { + var saveResult = SaveSubModels(Model, context, transaction); + if (!saveResult.IsSucceed) + { + result.Errors.AddRange(saveResult.Errors); + result.Exception = saveResult.Exception; + } + result.IsSucceed = result.IsSucceed && saveResult.IsSucceed; + } + + UnitOfWorkHelper.HandleTransaction(result.IsSucceed, isRoot, transaction); + return result; + } + catch (Exception ex) // TODO: Add more specific exeption types instead of Exception only + { + return UnitOfWorkHelper.HandleException(ex, isRoot, transaction); + } + finally + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + } + } + else + { + if (isRoot) + { + //if current Context is Root + context.Dispose(); + } + return new RepositoryResponse() + { + IsSucceed = false, + Data = null, + Errors = Errors + }; + } + } + + /// + /// Saves the sub models. + /// + /// The parent. + /// The context. + /// The transaction. + /// + public virtual RepositoryResponse SaveSubModels(TModel parent, TDbContext _context, IDbContextTransaction _transaction) + { + return new RepositoryResponse() { IsSucceed = true }; + } + + #endregion Sync + + #region Contructor + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The context. + /// The transaction. + protected EcmViewModelBase(TModel model, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + this.Model = model; + ParseView(_context: _context, _transaction: _transaction); + } + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// if set to true [is lazy load]. + /// The context. + /// The transaction. + protected EcmViewModelBase(TModel model, bool isLazyLoad, TDbContext _context = null, IDbContextTransaction _transaction = null) + { + this.Model = model; + ParseView(isExpand: isLazyLoad, _context: _context, _transaction: _transaction); + } + + /// + /// Initializes a new instance of the class. + /// + protected EcmViewModelBase() + { + this.Model = InitModel(); + ParseView(isExpand: false); + } + + #endregion Contructor + + } +} diff --git a/src/Swastika/Swastika.csproj b/src/Swastika/Swastika.csproj index f015479..76160ed 100644 --- a/src/Swastika/Swastika.csproj +++ b/src/Swastika/Swastika.csproj @@ -71,12 +71,12 @@ - - - - - - + + + + + +