Skip to content

Commit

Permalink
add simple vm
Browse files Browse the repository at this point in the history
  • Loading branch information
nhathoang989 committed Sep 16, 2024
1 parent 12b9782 commit 9b80aa6
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 4 deletions.
142 changes: 142 additions & 0 deletions src/mix.heart/ViewModel/SimpleViewModelBase.Async.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Mix.Heart.Enums;
using Mix.Heart.Exceptions;
using Mix.Heart.Helpers;
using Mix.Heart.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Mix.Heart.ViewModel
{
public abstract partial class SimpleViewModelBase<TDbContext, TEntity, TPrimaryKey, TView>
{
#region Async

public async Task DeleteAsync(CancellationToken cancellationToken = default)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
BeginUow();
await DeleteHandlerAsync(cancellationToken);
await CompleteUowAsync(cancellationToken);
}
catch (Exception ex)
{
await HandleExceptionAsync(ex);
}
finally
{
await CloseUowAsync();
}
}

protected virtual async Task DeleteHandlerAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
Repository.SetUowInfo(UowInfo);
await Repository.DeleteAsync(Id, cancellationToken);
ModifiedEntities.Add(new(typeof(TEntity), Id, ViewModelAction.Delete));
await DeleteEntityRelationshipAsync(cancellationToken);
}

public async Task<TPrimaryKey> SaveAsync(CancellationToken cancellationToken = default)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
BeginUow();
IsValid = Validator.TryValidateObject(this, ValidateContext, Errors);
await Validate(cancellationToken);
if (!IsValid)
{
await HandleExceptionAsync(new MixException(MixErrorStatus.Badrequest, Errors.Select(e => e.ErrorMessage).ToArray()));
}
var entity = await SaveHandlerAsync(cancellationToken);
await CompleteUowAsync(cancellationToken);
return entity.Id;
}
catch (Exception ex)
{
await HandleExceptionAsync(ex);
return default;
}
finally
{
await CloseUowAsync();
}
}

public async Task<TPrimaryKey> SaveFieldsAsync(IEnumerable<EntityPropertyModel> properties, CancellationToken cancellationToken = default)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
BeginUow();
foreach (var property in properties)
{
// check if field name is exist
var lamda = ReflectionHelper.GetLambda<TEntity>(property.PropertyName);
if (lamda != null)
{
ReflectionHelper.SetPropertyValue(this, property);
}
else
{
await HandleExceptionAsync(new MixException(MixErrorStatus.Badrequest, $"Invalid Property {property.PropertyName}"));
}
}
IsValid = Validator.TryValidateObject(this, ValidateContext, Errors);
await Validate(cancellationToken);
var entity = await ParseEntity(cancellationToken);
await Repository.SaveAsync(entity, cancellationToken);
await CompleteUowAsync(cancellationToken);
return entity.Id;
}
catch (Exception ex)
{
await HandleExceptionAsync(ex);
return default;
}
finally
{
await CloseUowAsync();
}
}

#region virtual methods

// Override this method
protected virtual async Task<TEntity> SaveHandlerAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var entity = await ParseEntity(cancellationToken);

ModifiedEntities.Add(new(typeof(TEntity), Id, !Id.Equals(default) ? ViewModelAction.Create : ViewModelAction.Update));

await Repository.SaveAsync(entity, cancellationToken);
await SaveEntityRelationshipAsync(entity, cancellationToken);
Id = entity.Id;
return entity;
}

// Override this method
protected virtual Task SaveEntityRelationshipAsync(TEntity parentEntity, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}

protected virtual Task DeleteEntityRelationshipAsync(CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}

#endregion

#endregion
}
}
76 changes: 76 additions & 0 deletions src/mix.heart/ViewModel/SimpleViewModelBase.Uow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Mix.Heart.Enums;
using Mix.Heart.Exceptions;
using Mix.Heart.Services;
using Mix.Heart.UnitOfWork;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Mix.Heart.ViewModel
{
public abstract partial class SimpleViewModelBase<TDbContext, TEntity, TPrimaryKey, TView>
{
private bool _isRoot;

protected virtual void BeginUow()
{
if (UowInfo == null)
{
InitRootUow();
}

UowInfo.Begin();

if (Repository != null)
{
Repository.SetUowInfo(UowInfo);
}
else
{
Repository = GetRepository(UowInfo, CacheService);
}
Repository.SetCacheService(CacheService);
Repository.CacheFolder = CacheFolder;
}

protected virtual void InitRootUow()
{
UowInfo ??= new UnitOfWorkInfo(InitDbContext());
_isRoot = true;
}

protected virtual async Task CloseUowAsync()
{
if (_isRoot)
{
await UowInfo.CloseAsync();
}
}

protected virtual async Task CompleteUowAsync(CancellationToken cancellationToken = default)
{
if (_isRoot)
{
await UowInfo.CompleteAsync(cancellationToken);
return;
};

_isRoot = false;
}

protected virtual TDbContext InitDbContext()
{
var dbContextType = typeof(TDbContext);
var contextCtorInfo = dbContextType.GetConstructor(new Type[] { });

if (contextCtorInfo == null)
{
throw new MixException(
MixErrorStatus.ServerError,
$"{dbContextType}: Contructor Parameterless Notfound");
}

return (TDbContext)contextCtorInfo.Invoke([]);
}
}
}
118 changes: 118 additions & 0 deletions src/mix.heart/ViewModel/SimpleViewModelBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using Microsoft.EntityFrameworkCore;
using Mix.Heart.Entities;
using Mix.Heart.Enums;
using Mix.Heart.Exceptions;
using Mix.Heart.Helpers;
using Mix.Heart.UnitOfWork;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Mix.Heart.ViewModel
{
public abstract partial class SimpleViewModelBase<TDbContext, TEntity, TPrimaryKey, TView> : ViewModelQueryBase<TDbContext, TEntity, TPrimaryKey, TView>
where TPrimaryKey : IComparable
where TEntity : class, IEntity<TPrimaryKey>
where TDbContext : DbContext
where TView : SimpleViewModelBase<TDbContext, TEntity, TPrimaryKey, TView>
{
#region Properties

public TPrimaryKey Id { get; set; }

#endregion

#region Constructors

public SimpleViewModelBase() : base()
{
}

public SimpleViewModelBase(TDbContext context) : base(context)
{
}

public SimpleViewModelBase(TEntity entity, UnitOfWorkInfo uowInfo) : base(entity, uowInfo)
{
}

public SimpleViewModelBase(UnitOfWorkInfo unitOfWorkInfo) : base(unitOfWorkInfo)
{
}

#endregion

#region Abstracts
public virtual void InitDefaultValues(string language = null, int? cultureId = null)
{
}

#endregion

public virtual async Task Validate(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (!IsValid)
{
await HandleExceptionAsync(new MixException(MixErrorStatus.Badrequest, Errors.Select(e => e.ErrorMessage).ToArray()));
}
}

public void SetDbContext(TDbContext context)
{
UowInfo = new UnitOfWorkInfo(context);
}

public virtual TEntity InitModel()
{
Type classType = typeof(TEntity);
return (TEntity)Activator.CreateInstance(classType);
}

public virtual Task<TEntity> ParseEntity(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();

if (IsDefaultId(Id))
{
InitDefaultValues();
}

var entity = Activator.CreateInstance<TEntity>();
ReflectionHelper.Map(this as TView, entity);
return Task.FromResult(entity);
}

public bool IsDefaultId(TPrimaryKey id)
{
return (id.GetType() == typeof(Guid) && Guid.Parse(id.ToString()) == Guid.Empty)
|| (id.GetType() == typeof(int) && int.Parse(id.ToString()) == default);
}

public virtual Task DuplicateAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}

public virtual void Duplicate()
{
}

protected async Task HandleErrorsAsync()
{
await HandleExceptionAsync(new MixException(MixErrorStatus.Badrequest, Errors.Select(e => e.ErrorMessage).ToArray()));
}

protected virtual async Task HandleExceptionAsync(Exception ex)
{
await Repository.HandleExceptionAsync(ex);
}

protected virtual void HandleException(Exception ex)
{
Repository.HandleException(ex);
}
}
}
1 change: 1 addition & 0 deletions src/mix.heart/ViewModel/ViewModelBase.Uow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Mix.Heart.Enums;
using Mix.Heart.Exceptions;
using Mix.Heart.Services;
using Mix.Heart.UnitOfWork;
using System;
using System.Threading;
Expand Down
5 changes: 1 addition & 4 deletions src/mix.heart/ViewModel/ViewModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,14 @@

namespace Mix.Heart.ViewModel
{
public abstract partial class ViewModelBase<TDbContext, TEntity, TPrimaryKey, TView> : ViewModelQueryBase<TDbContext, TEntity, TPrimaryKey, TView>
public abstract partial class ViewModelBase<TDbContext, TEntity, TPrimaryKey, TView> : SimpleViewModelBase<TDbContext, TEntity, TPrimaryKey, TView>
where TPrimaryKey : IComparable
where TEntity : class, IEntity<TPrimaryKey>
where TDbContext : DbContext
where TView : ViewModelBase<TDbContext, TEntity, TPrimaryKey, TView>
{
#region Properties

public TPrimaryKey Id { get; set; }

public DateTime CreatedDateTime { get; set; }

public DateTime? LastModified { get; set; }
Expand All @@ -45,7 +43,6 @@ public ViewModelBase() : base()

public ViewModelBase(TDbContext context) : base(context)
{
_isRoot = true;
}

public ViewModelBase(TEntity entity, UnitOfWorkInfo uowInfo) : base(entity, uowInfo)
Expand Down

0 comments on commit 9b80aa6

Please sign in to comment.