From e2beb494d62b9fd4473f1f1ca13fbfcb7278395f Mon Sep 17 00:00:00 2001 From: Oleg Zhuk Date: Tue, 27 Jun 2023 09:18:17 +0200 Subject: [PATCH] PT-12212: Ability to override the DbContextUnitOfWork (#2666) feat: Ability to override the DbContextUnitOfWork --- .../Domain/AbstractTypeFactory.cs | 200 ++++++++++++++++-- .../Infrastructure/DbContextRepositoryBase.cs | 4 +- .../Infrastructure/DbContextUnitOfWork.cs | 14 +- .../VirtoCommerce.Platform.Web.csproj | 4 +- 4 files changed, 192 insertions(+), 30 deletions(-) diff --git a/src/VirtoCommerce.Platform.Core/Domain/AbstractTypeFactory.cs b/src/VirtoCommerce.Platform.Core/Domain/AbstractTypeFactory.cs index d87dcdc559d..5069060a385 100644 --- a/src/VirtoCommerce.Platform.Core/Domain/AbstractTypeFactory.cs +++ b/src/VirtoCommerce.Platform.Core/Domain/AbstractTypeFactory.cs @@ -5,7 +5,7 @@ namespace VirtoCommerce.Platform.Core.Common { /// - /// Abstract static type factory. With supports of type overriding and sets special factories. + /// Represents factory that supports type overriding and provides special factory capabilities. /// /// public static class AbstractTypeFactory @@ -13,7 +13,7 @@ public static class AbstractTypeFactory private static readonly List> _typeInfos = new List>(); /// - /// All registered type mapping informations within current factory instance + /// Gets all registered type mapping information within the current factory instance. /// public static IEnumerable> AllTypeInfos { @@ -23,9 +23,10 @@ public static IEnumerable> AllTypeInfos } } -#pragma warning disable S2743 // Static fields should not be used in generic types - // False-positive SLint warning disabled. - // This field really need for every class applied by the template +#pragma warning disable S2743 + /// + /// Gets a value indicating whether there are any type overrides registered in the factory. + /// public static bool HasOverrides #pragma warning restore S2743 // Static fields should not be used in generic types { @@ -36,14 +37,21 @@ public static bool HasOverrides } /// - /// Register new type (fluent method) + /// Registers a new type in the factory and returns a TypeInfo instance for further configuration. /// - /// TypeInfo instance to continue configuration through fluent syntax + /// The type to be registered. + /// TypeInfo instance for the registered type. public static TypeInfo RegisterType() where T : BaseType { return RegisterType(typeof(T)); } + /// + /// Registers a new type in the factory and returns a TypeInfo instance for further configuration. + /// + /// The type to be registered. + /// TypeInfo instance for the registered type. + /// public static TypeInfo RegisterType(Type type) { if (type == null) @@ -61,21 +69,27 @@ public static TypeInfo RegisterType(Type type) return result; } + /// - /// Override already registered type with a new one. + /// Overrides an already registered type with a new one and returns a TypeInfo instance for further configuration. /// - /// TypeInfo instance to continue configuration through fluent syntax + /// The currently registered type. + /// The currently registered type. + /// TypeInfo instance for the overridden type. public static TypeInfo OverrideType() where NewType : BaseType { return OverrideType(typeof(OldType), typeof(NewType)); } + + /// - /// Override already registered type with a new one. + /// Overrides an already registered type with a new one and returns a TypeInfo instance for further configuration. /// - /// The currently registered type - /// The type to override with - /// TypeInfo instance to continue configuration through fluent syntax + /// The currently registered type. + /// The type to override oldType with. + /// + /// public static TypeInfo OverrideType(Type oldType, Type newType) { if (!typeof(BaseType).IsAssignableFrom(newType)) @@ -95,36 +109,115 @@ public static TypeInfo OverrideType(Type oldType, Type newType) } /// - /// Create BaseType instance considering type mapping information + /// Creates an instance of the base type using the type name. /// - /// + /// An instance of the base type. public static BaseType TryCreateInstance() { return TryCreateInstance(typeof(BaseType).Name); } /// - /// Create derived from BaseType specified type instance considering type mapping information + /// Creates an instance of the base type using the type name and a default object. /// - /// + /// The default object to use if the instance cannot be created. + /// An instance of the base type. + public static BaseType TryCreateInstance(BaseType defaultObj) + { + return TryCreateInstance(typeof(BaseType).Name, defaultObj); + } + + /// + /// Creates an instance of the base type using the type name, a default object, and additional constructor arguments. + /// + /// The default object to use if the instance cannot be created. + /// Additional constructor arguments. + /// An instance of the base type. + public static BaseType TryCreateInstance(BaseType defaultObj, params object[] args) + { + return TryCreateInstance(typeof(BaseType).Name, defaultObj, args); + } + + /// + /// Creates an instance of the specified generic type using the type name. + /// + /// Generic type + /// An instance of the specified generic type. public static T TryCreateInstance() where T : BaseType { return (T)TryCreateInstance(typeof(T).Name); } + /// + /// Creates an instance of the specified generic type using the type name and a default object. + /// + /// Generic type + /// The default object to use if the instance cannot be created. + /// An instance of the specified generic type. + public static T TryCreateInstance(T defaultObj) where T : BaseType + { + return (T)TryCreateInstance(typeof(T).Name, defaultObj); + } + + /// + /// Creates an instance of the specified generic type using the type name, a default object, and additional constructor arguments. + /// + /// Generic type + /// The default object to use if the instance cannot be created. + /// Additional constructor arguments. + /// An instance of the specified generic type. + public static T TryCreateInstance(T defaultObj, params object[] args) where T : BaseType + { + return (T)TryCreateInstance(typeof(T).Name, defaultObj, args); + } + + /// + /// Creates an instance of the base type using the specified type name. + /// + /// The name of the type to create. + /// An instance of the base type. + public static BaseType TryCreateInstance(string typeName) + { + return TryCreateInstance(typeName, null); + } + + /// + /// Creates an instance of the base type using the specified type name and a default object. + /// + /// The name of the type to create. + /// The default object to use if the instance cannot be created. + /// An instance of the base type. public static BaseType TryCreateInstance(string typeName, BaseType defaultObj) + { + return TryCreateInstance(typeName, defaultObj, null); + } + + /// + /// Creates an instance of the base type using the specified type name, a default object, and additional constructor arguments. + /// + /// The name of the type to create. + /// The default object to use if the instance cannot be created. + /// Additional constructor arguments. + /// An instance of the base type. + public static BaseType TryCreateInstance(string typeName, BaseType defaultObj, params object[] args) { var result = defaultObj; var typeInfo = FindTypeInfoByName(typeName); if (typeInfo != null) { - result = TryCreateInstance(typeName); + result = TryCreateInstance(typeName, args); } return result; } - - public static BaseType TryCreateInstance(string typeName) + /// + /// Creates an instance of the base type using the specified type name and additional constructor arguments. + /// + /// The name of the type to create. + /// Additional constructor arguments. + /// An instance of the base type. + /// + public static BaseType TryCreateInstance(string typeName, params object[] args) { BaseType result; var typeInfo = FindTypeInfoByName(typeName); @@ -136,7 +229,7 @@ public static BaseType TryCreateInstance(string typeName) } else { - result = (BaseType)Activator.CreateInstance(typeInfo.Type); + result = (BaseType)Activator.CreateInstance(typeInfo.Type, args); } typeInfo.SetupAction?.Invoke(result); } @@ -154,6 +247,11 @@ public static BaseType TryCreateInstance(string typeName) return result; } + /// + /// Finds the type information for the specified type name. + /// + /// The name of the type to find. + /// The TypeInfo instance for the specified type name. public static TypeInfo FindTypeInfoByName(string typeName) { //Try find first direct type match from registered types @@ -168,7 +266,7 @@ public static TypeInfo FindTypeInfoByName(string typeName) } /// - /// Helper class contains type mapping information + /// Helper class that contains type mapping information. /// public class TypeInfo { @@ -179,18 +277,47 @@ public TypeInfo(Type type) TypeName = type.Name; } + /// + /// Gets or sets the name of the type. + /// public string TypeName { get; private set; } + /// + /// Gets or sets the factory function used to create an instance of the type. + /// public Func Factory { get; private set; } + /// + /// Gets or sets the setup action to be performed on the created instance. + /// public Action SetupAction { get; private set; } + /// + /// Gets or sets the type associated with the type mapping information. + /// public Type Type { get; private set; } + /// + /// Gets or sets the mapped type that the associated type should be mapped to. + /// public Type MappedType { get; set; } + /// + /// Gets or sets the mapped type that the associated type should be mapped to. + /// public ICollection Services { get; set; } + /// + /// Gets the service of the specified type from the collection of services. + /// + /// + /// The service of the specified type, or default(T) if the service is not found. public T GetService() { return Services.OfType().FirstOrDefault(); } + /// + /// Adds the specified service to the collection of services. + /// + /// + /// + /// The setup action. public TypeInfo WithService(T service) { if (!Services.Contains(service)) @@ -200,36 +327,63 @@ public TypeInfo WithService(T service) return this; } + /// + /// Maps the associated type to the specified type. + /// + /// + /// The setup action. public TypeInfo MapToType() { MappedType = typeof(T); return this; } + /// + /// Maps the associated type to the specified type. + /// + /// The factory function. + /// The setup action. public TypeInfo WithFactory(Func factory) { Factory = factory; return this; } + /// + /// Maps the associated type to the specified type. + /// + /// The setup action. + /// The setup action. public TypeInfo WithSetupAction(Action setupAction) { SetupAction = setupAction; return this; } + /// + /// Sets the name of the type. + /// + /// Sets the name of the type. + /// Sets the name of the type. public TypeInfo WithTypeName(string name) { TypeName = name; return this; } - + /// + /// Checks if the associated type is assignable to the specified type name. + /// + /// The name of the type to check. + /// true if the associated type is assignable to the specified type name; otherwise, false. public bool IsAssignableTo(string typeName) { return Type.GetTypeInheritanceChainTo(typeof(BaseType)).Concat(new[] { typeof(BaseType) }).Any(t => typeName.EqualsInvariant(t.Name)); } + /// + /// Gets all subclasses of the associated type. + /// public IEnumerable AllSubclasses { get diff --git a/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextRepositoryBase.cs b/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextRepositoryBase.cs index 1c8972f537e..486b59e975f 100644 --- a/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextRepositoryBase.cs +++ b/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextRepositoryBase.cs @@ -22,14 +22,14 @@ protected DbContextRepositoryBase(TContext dbContext, IUnitOfWork unitOfWork = n DbContext.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges; DbContext.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges; - UnitOfWork = unitOfWork ?? new DbContextUnitOfWork(dbContext); + UnitOfWork = unitOfWork ?? AbstractTypeFactory.TryCreateInstance(new DbContextUnitOfWork(dbContext), (DbContext)dbContext); var connectionDb = dbContext.Database.GetDbConnection(); var connectionTimeout = connectionDb.ConnectionTimeout; dbContext.Database.SetCommandTimeout(connectionTimeout); } - + public TContext DbContext { get; private set; } #region IRepository Members diff --git a/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextUnitOfWork.cs b/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextUnitOfWork.cs index 879f2824c22..14382598176 100644 --- a/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextUnitOfWork.cs +++ b/src/VirtoCommerce.Platform.Data/Infrastructure/DbContextUnitOfWork.cs @@ -12,7 +12,7 @@ public class DbContextUnitOfWork : IUnitOfWork /// /// The database context. /// - public DbContext DbContext { get; private set; } + public DbContext DbContext { get; protected set; } /// /// Initializes a new instance of the class. @@ -23,12 +23,20 @@ public DbContextUnitOfWork(DbContext context) DbContext = context; } - public int Commit() + /// + /// Commits all changes made in this context + /// + /// + public virtual int Commit() { return DbContext.SaveChanges(); } - public Task CommitAsync() + /// + /// Commits all changes made in this context + /// + /// + public virtual Task CommitAsync() { return DbContext.SaveChangesAsync(); } diff --git a/src/VirtoCommerce.Platform.Web/VirtoCommerce.Platform.Web.csproj b/src/VirtoCommerce.Platform.Web/VirtoCommerce.Platform.Web.csproj index 311ba9acf96..08ae60180df 100644 --- a/src/VirtoCommerce.Platform.Web/VirtoCommerce.Platform.Web.csproj +++ b/src/VirtoCommerce.Platform.Web/VirtoCommerce.Platform.Web.csproj @@ -1,4 +1,4 @@ - + net6.0 true @@ -52,7 +52,7 @@ - +