using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Vit.Core.Util.ConfigurationManager; using Vit.Core.Util.Reflection; using Vit.Linq; using Vitorm.DataProvider; using Vitorm.Entity; namespace Vitorm { public partial class Data { static Data() { #region #1 load dataProvider { var dataSourceConfigs = Appsettings.json.GetByPath>>("Vitorm.Data"); var dataProviders = dataSourceConfigs?.Select(CreateDataProvider).NotNull().ToList(); if (dataProviders?.Any() == true) providerCache.AddRange(dataProviders); } #endregion #region #2 load entityLoader from appsettings.json { var configs = Appsettings.json.GetByPath>>("Vitorm.EntityLoader"); configs?.ForEach(config => { object temp; string className = config.TryGetValue("className", out temp) ? temp as string : null; string assemblyFile = config.TryGetValue("assemblyFile", out temp) ? temp as string : null; string assemblyName = config.TryGetValue("assemblyName", out temp) ? temp as string : null; int index = config.TryGetValue("index", out temp) && temp is int i ? i : 0; var entityLoader = ObjectLoader.CreateInstance(className, assemblyFile: assemblyFile, assemblyName: assemblyName) as IEntityLoader; if (entityLoader == null) return; EntityLoaders.Instance.loaders.Insert(index, entityLoader); }); } #endregion } public static bool AddDataSource(Dictionary dataSourceConfig) { var provider = CreateDataProvider(dataSourceConfig); if (provider == null) return false; providerCache.Insert(0, provider); providerMap.Clear(); return true; } public static void ClearDataSource(Predicate predicate = null) { if (predicate != null) providerCache.RemoveAll(predicate); else providerCache.Clear(); providerMap.Clear(); } #region LoadDataProvider public static IDataProvider DataProvider() => DataProvider(typeof(Entity)); public static IDataProvider DataProvider(Type entityType) { return providerMap.GetOrAdd(entityType, GetDataProviderFromConfig); static IDataProvider GetDataProviderFromConfig(Type entityType) { var classFullName = entityType.FullName; return providerCache.FirstOrDefault(cache => cache.Match(classFullName))?.dataProvider ?? throw new NotImplementedException("can not find config for type: " + classFullName); } } /// /// dataProviderName: dataProviderName or dataProviderNamespace /// /// /// public static IDataProvider DataProvider(string dataProviderName) { return providerCache.FirstOrDefault(cache => cache.name == dataProviderName || cache.@namespace == dataProviderName)?.dataProvider; } static readonly ConcurrentDictionary providerMap = new(); static readonly List providerCache = new(); static DataProviderCache CreateDataProvider(Dictionary dataSourceConfig) { /* "provider": "Vitorm.Sqlite.DataProvider", "assemblyName": "Vitorm.Sqlite", "assemblyFile": "Vitorm.Sqlite.dll", */ object temp; string provider = dataSourceConfig.TryGetValue("provider", out temp) ? temp as string : null; string assemblyName = dataSourceConfig.TryGetValue("assemblyName", out temp) ? temp as string : null; string assemblyFile = dataSourceConfig.TryGetValue("assemblyFile", out temp) ? temp as string : null; Type providerType; IDataProvider dataProvider; // #1 load providerType = ObjectLoader.GetType(className: provider, assemblyName: assemblyName, assemblyFile: assemblyFile); dataProvider = providerType?.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }) as IDataProvider; // #2 try load by database type (Sqlite/MySql/SqlServer) if (dataProvider == null) { providerType = ObjectLoader.GetType(className: $"Vitorm.{provider}.DataProvider", assemblyName: $"Vitorm.{provider}", assemblyFile: $"Vitorm.{provider}.dll"); dataProvider = providerType?.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }) as IDataProvider; } if (dataProvider == null) return null; dataProvider.Init(dataSourceConfig); return new DataProviderCache(dataProvider, dataSourceConfig); } #endregion #region CRUD Sync // #0 Schema : TryCreateTable TryDropTable public static void TryCreateTable() => DataProvider().TryCreateTable(); public static void TryDropTable() => DataProvider().TryDropTable(); public static void Truncate() => DataProvider().Truncate(); // #1 Create : Add AddRange public static Entity Add(Entity entity) => DataProvider().Add(entity); public static void AddRange(IEnumerable entities) => DataProvider().AddRange(entities); // #2 Retrieve : Get Query public static Entity Get(object keyValue) => DataProvider().Get(keyValue); public static IQueryable Query() => DataProvider().Query(); // #3 Update: Update UpdateRange public static int Update(Entity entity) => DataProvider().Update(entity); public static int UpdateRange(IEnumerable entities) => DataProvider().UpdateRange(entities); // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys public static int Delete(Entity entity) => DataProvider().Delete(entity); public static int DeleteRange(IEnumerable entities) => DataProvider().DeleteRange(entities); public static int DeleteByKey(object keyValue) => DataProvider().DeleteByKey(keyValue); public static int DeleteByKeys(IEnumerable keys) => DataProvider().DeleteByKeys(keys); #endregion #region CRUD Async // #0 Schema : TryCreateTable TryDropTable public static Task TryCreateTableAsync() => DataProvider().TryCreateTableAsync(); public static Task TryDropTableAsync() => DataProvider().TryDropTableAsync(); public static Task TruncateAsync() => DataProvider().TruncateAsync(); // #1 Create : Add AddRange public static Task AddAsync(Entity entity) => DataProvider().AddAsync(entity); public static Task AddRangeAsync(IEnumerable entities) => DataProvider().AddRangeAsync(entities); // #2 Retrieve : Get Query public static Task GetAsync(object keyValue) => DataProvider().GetAsync(keyValue); // #3 Update: Update UpdateRange public static Task UpdateAsync(Entity entity) => DataProvider().UpdateAsync(entity); public static Task UpdateRangeAsync(IEnumerable entities) => DataProvider().UpdateRangeAsync(entities); // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys public static Task DeleteAsync(Entity entity) => DataProvider().DeleteAsync(entity); public static Task DeleteRangeAsync(IEnumerable entities) => DataProvider().DeleteRangeAsync(entities); public static Task DeleteByKeyAsync(object keyValue) => DataProvider().DeleteByKeyAsync(keyValue); public static Task DeleteByKeysAsync(IEnumerable keys) => DataProvider().DeleteByKeysAsync(keys); #endregion } }