├── .gitattributes ├── .gitignore ├── AA.AspNetCore ├── AA.AspNetCore.csproj ├── Extensions │ └── ServiceCollectionExtensions.cs └── Results │ └── Result.cs ├── AA.AutoMapper ├── AA.AutoMapper.csproj ├── AutoMapperConfiguration.cs ├── AutoMapperObjectMapper.cs └── IMapperConfiguration.cs ├── AA.Dapper ├── AA.Dapper.csproj ├── Advanced │ ├── Attributes │ │ ├── DataSourceAttribute.cs │ │ └── TransactionAttribute.cs │ ├── DbContextHolder.cs │ ├── DbDataSource.cs │ ├── IDbDatasource.cs │ └── Interceptor │ │ ├── DataSourceInterceptor.cs │ │ └── TransactionInterceptor.cs ├── Configuration │ ├── IMapConfiguration.cs │ └── MapConfiguration.cs ├── ConfigurationBasedDbMetadataFactory.cs ├── DapperContext.cs ├── DbMetadata.cs ├── DbMetadataFactory.cs ├── DbProvider.cs ├── Dommel │ ├── Any.cs │ ├── AutoMultiMap.cs │ ├── Cache.cs │ ├── ColumnPropertyInfo.cs │ ├── Count.cs │ ├── DefaultColumnNameResolver.cs │ ├── DefaultForeignKeyPropertyResolver.cs │ ├── DefaultKeyPropertyResolver.cs │ ├── DefaultPropertyResolver.cs │ ├── DefaultTableNameResolver.cs │ ├── Delete.cs │ ├── DommelMapper.cs │ ├── ForeignKeyRelation.cs │ ├── From.cs │ ├── Get.cs │ ├── IColumnNameResolver.cs │ ├── IForeignKeyPropertyResolver.cs │ ├── IKeyPropertyResolver.cs │ ├── IPropertyResolver.cs │ ├── ISqlBuilder.cs │ ├── ITableNameResolver.cs │ ├── IgnoreAttribute.cs │ ├── Insert.cs │ ├── MultiMap.cs │ ├── MySqlSqlBuilder.cs │ ├── PostgresSqlBuilder.cs │ ├── Project.cs │ ├── Resolvers.cs │ ├── Select.cs │ ├── SqlExpression.cs │ ├── SqlServerCeSqlBuilder.cs │ ├── SqlServerSqlBuilder.cs │ ├── SqliteSqlBuilder.cs │ └── Update.cs ├── EmbeddedAssemblyResourceDbMetadataFactory.cs ├── FluentMap.Dommel │ ├── FluentMapConfigurationExtensions.cs │ ├── Mapping │ │ ├── DommelEntityMap.cs │ │ └── DommelPropertyMap.cs │ └── Resolvers │ │ ├── DommelColumnNameResolver.cs │ │ ├── DommelKeyPropertyResolver.cs │ │ ├── DommelPropertyResolver.cs │ │ └── DommelTableNameResolver.cs ├── FluentMap │ ├── Configuration │ │ ├── FluentConventionConfiguration.cs │ │ └── FluentMapConfiguration.cs │ ├── Conventions │ │ ├── Convention.cs │ │ ├── ConventionPropertyConfiguration.cs │ │ └── PropertyConventionConfiguration.cs │ ├── FluentMapper.cs │ ├── Mapping │ │ ├── EntityMap.cs │ │ └── PropertyMap.cs │ ├── TypeMaps │ │ ├── FluentConventionTypeMap.cs │ │ ├── FluentTypeMap.cs │ │ ├── IgnoredPropertyInfo.cs │ │ └── MultiTypeMap.cs │ └── Utils │ │ ├── DictionaryExtensions.cs │ │ └── ReflectionHelper.cs ├── IDapperContext.cs ├── IDbProvider.cs ├── Repositories │ ├── DapperRepository.cs │ └── IDapperRepository.cs ├── TimeSpanParseRuleAttribute.cs ├── Util │ ├── Configuration.cs │ ├── DBConnectionManager.cs │ ├── DataBase.cs │ ├── DynamicExpression.cs │ ├── IDbConnectionManager.cs │ ├── ObjectUtils.cs │ └── PropertiesParser.cs └── dbproviders.netstandard.properties ├── AA.FrameWork.Tests.Unit ├── AA.FrameWork.Tests.Unit.csproj ├── AutoMapper │ ├── AutoMapperTest.cs │ ├── UserVm.cs │ └── WebMapperConfigurations.cs ├── Log4Net │ ├── log4net.config │ └── log4netTest.cs ├── NLog │ ├── NLogTest.cs │ └── nlog.config ├── RabbitMQ │ └── ServiceBus │ │ ├── Consumer.cs │ │ ├── Producer.cs │ │ └── meesageContracts │ │ ├── OrderSubmitted.cs │ │ └── SubmitOrder.cs └── dapper │ ├── AADapperContext.cs │ ├── AADapperRepositoryMysqlTest.cs │ ├── AADapperRepositoryTest.cs │ ├── Advanced │ └── DbDataSourceText.cs │ ├── DapperContextTest.cs │ ├── Entity │ ├── User.cs │ ├── UserInfo.cs │ └── Village.cs │ ├── EntityMap │ ├── UserInfoMap.cs │ ├── UserMap.cs │ └── VillageMap.cs │ ├── Init │ └── DbEntityMap.cs │ └── Repository │ ├── IUserInfoRepository.cs │ ├── IUserRepository.cs │ ├── IVillageRepository.cs │ ├── UserInfoRepository.cs │ ├── UserRepository.cs │ └── VillageRepository.cs ├── AA.FrameWork ├── AA.FrameWork.csproj ├── AAException.cs ├── Application │ └── Services │ │ └── Dto │ │ ├── IListResult.cs │ │ ├── IPagedResult.cs │ │ ├── IPagedResultRequestDto.cs │ │ ├── ListResultDto.cs │ │ ├── PagedResultDto.cs │ │ └── PagedResultRequestDto.cs ├── Domain │ ├── IEntity.cs │ ├── IPage.cs │ ├── ISoftDelete.cs │ ├── Page.cs │ └── PageRequest.cs ├── Engine │ ├── AAEngine.cs │ ├── BaseSingleton.cs │ ├── DependencyManagement │ │ └── IDependencyRegistrar.cs │ ├── EngineContext.cs │ ├── IEngine.cs │ ├── ITypeFinder.cs │ ├── Singleton.cs │ ├── SingletonDictionary.cs │ └── SingletonList.cs ├── Extensions │ ├── DateTimeExtension.cs │ ├── GuidExtension.cs │ ├── ObjectExtension.cs │ └── StringExtensions.cs ├── Logging │ ├── ILogger.cs │ ├── Ilog.cs │ └── Logger.cs ├── ObjectMapping │ ├── IObjectMapper.cs │ └── ObjectMapManager.cs ├── Serialize │ └── ISerialize.cs └── Util │ ├── CodeUtil.cs │ ├── ForCallContext.cs │ └── TaskUtil.cs ├── AA.Log4Net ├── AA.Log4Net.csproj ├── Log4NetLog.cs └── Log4NetLogger.cs ├── AA.NLog ├── AA.NLog.csproj ├── NLogLog.cs └── NLogLogger.cs ├── AA.RabbitMQ ├── AA.RabbitMQ.csproj ├── EventMessage.cs ├── MqConfigDom.cs ├── MqConfigDomFactory.cs ├── RabbitMqClientContext.cs ├── RabbitMqClientFactory.cs └── RabbitMqHelper.cs ├── AA.Redis ├── AA.Redis.csproj ├── Contracts │ ├── BitfieldType.cs │ ├── IContext.cs │ ├── ISerializer.cs │ ├── OverflowType.cs │ ├── Providers │ │ ├── ICacheProvider.cs │ │ ├── ICacheProviderAsync.cs │ │ └── ICollectionProvider.cs │ ├── RedisObjects │ │ ├── IRedisBitmap.cs │ │ ├── IRedisDictionary.cs │ │ ├── IRedisDictionaryAsync.cs │ │ ├── IRedisLexicographicSet.cs │ │ ├── IRedisList.cs │ │ ├── IRedisListAsync.cs │ │ ├── IRedisObject.cs │ │ ├── IRedisSet.cs │ │ ├── IRedisSetAsync.cs │ │ ├── IRedisSortedSet.cs │ │ ├── IRedisString.cs │ │ └── IRedisStringAsync.cs │ ├── SortedMember.cs │ ├── TextAttribute.cs │ └── When.cs ├── Lua │ └── Unlock.lua ├── LuaScriptResource.cs ├── Providers │ ├── RedisCacheProvider.cs │ ├── RedisCollectionProvider.cs │ ├── RedisProviderBase.cs │ └── RedisProviderContext.cs ├── RedisContext.cs ├── RedisLock │ ├── LockInfo.cs │ ├── LockServerInfo.cs │ └── RedisLock.cs ├── RedisObjects │ ├── IRedisBitmap.cs │ ├── RedisBaseObject.cs │ ├── RedisBitmap.cs │ ├── RedisDictionary.cs │ ├── RedisLexicographicSet.cs │ ├── RedisList.cs │ ├── RedisSet.cs │ ├── RedisSortedSet.cs │ └── RedisString.cs ├── Serializers │ └── JsonSerializer.cs ├── TaskExtensions.cs └── Util │ └── EmbeddedResourceLoader.cs ├── AA.ServiceBus ├── AA.ServiceBus.csproj ├── Configuration │ └── ServiceBusConfiguration.cs └── ServiceBusManager.cs ├── AA.sln └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /AA.AspNetCore/AA.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;netcoreapp3.1 5 | AspNetCore 常用的 6 | https://github.com/ChengLab/AAFrameWork 7 | https://github.com/ChengLab/AAFrameWork 8 | git 9 | netcore 10 | true 11 | 6.0.4 12 | 2.0.1.0 13 | 2.0.1.0 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AA.AspNetCore/Results/Result.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace AA.AspNetCore.Results 7 | { 8 | 9 | public class Result : Result 10 | { 11 | public T Data { get; set; } 12 | 13 | public static Result Response(bool isSuccess, T data, string code = "", string msg = "") 14 | { 15 | return new Result 16 | { 17 | IsSuccess = isSuccess, 18 | Message = msg, 19 | Code = code, 20 | Data = data 21 | }; 22 | } 23 | } 24 | public class Result 25 | { 26 | 27 | public bool IsSuccess { get; set; } 28 | public string Message { get; set; } 29 | public string Code { get; set; } 30 | public Result() { } 31 | public Result(bool isSuccess, string code, string msg) 32 | { 33 | this.IsSuccess = isSuccess; 34 | this.Message = msg; 35 | this.Code = code; 36 | } 37 | public static Result ResponseSuccess(string msg = "", string code = "") 38 | { 39 | return new Result(true, code, msg); 40 | } 41 | 42 | public static Result ResponseError(string msg = "", string code = "") 43 | { 44 | return new Result(false, code, msg); 45 | } 46 | public static Result Response(bool isSuccess, T data, string code = "", string msg = "") 47 | { 48 | return new Result 49 | { 50 | IsSuccess = isSuccess, 51 | Message = msg, 52 | Code = code, 53 | Data = data 54 | }; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AA.AutoMapper/AA.AutoMapper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;netcoreapp3.1 5 | true 6 | ChengTian 7 | AA 8 | AA 9 | AutoMapper 10 | AA;AutoMapper; 11 | https://github.com/ChengLab/AAFrameWork 12 | https://github.com/ChengLab/AAFrameWork 13 | git 14 | 3.1.0 15 | 2.0.1.0 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AA.AutoMapper/AutoMapperConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace AA.AutoMapper 7 | { 8 | public static class AutoMapperConfiguration 9 | { 10 | private static MapperConfiguration _mapperConfiguration; 11 | private static IMapper _mapper; 12 | 13 | public static void Init(List> configurationActions) 14 | { 15 | if (configurationActions == null) 16 | throw new ArgumentNullException("configurationActions"); 17 | 18 | _mapperConfiguration = new MapperConfiguration(cfg => 19 | { 20 | foreach (var ca in configurationActions) 21 | { 22 | ca(cfg); 23 | } 24 | }); 25 | _mapper = _mapperConfiguration.CreateMapper(); 26 | } 27 | public static MapperConfiguration MapperConfiguration 28 | { 29 | get { return _mapperConfiguration; } 30 | } 31 | 32 | public static IMapper Mapper => _mapper; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AA.AutoMapper/AutoMapperObjectMapper.cs: -------------------------------------------------------------------------------- 1 | using AA.FrameWork.ObjectMapping; 2 | using AutoMapper; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using IObjectMapper = AA.FrameWork.ObjectMapping.IObjectMapper; 7 | namespace AA.AutoMapper 8 | { 9 | public class AutoMapperObjectMapper : IObjectMapper 10 | { 11 | private readonly IMapper _mapper; 12 | 13 | public AutoMapperObjectMapper() 14 | { 15 | _mapper = AutoMapperConfiguration.Mapper; 16 | } 17 | public TDestination Map(object source) 18 | { 19 | return _mapper.Map(source); 20 | } 21 | 22 | public TDestination Map(TSource source) 23 | { 24 | return _mapper.Map(source); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AA.AutoMapper/IMapperConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace AA.AutoMapper 7 | { 8 | public interface IMapperConfiguration 9 | { 10 | Action GetConfiguration(); 11 | 12 | int Order { get; } 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /AA.Dapper/AA.Dapper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;netcoreapp3.1 5 | LiMingCheng 6 | AA 7 | AA 8 | AA.Dapper 基于dapper+dommel 开发 , 支持工作单元、仓储模式、读写分离和原生dapper的操作 9 | https://github.com/ChengLab/AAFrameWork 10 | https://github.com/ChengLab/AAFrameWork 11 | git 12 | AA;Dapper;dommel; 13 | true 14 | 2.0.5.0 15 | 2.0.5.0 16 | 5.0.2 17 | preview 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/Attributes/DataSourceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace AA.Dapper.Advanced 6 | { 7 | /// 8 | /// 数据源类型 master slave 9 | /// 10 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 11 | public class DataSourceAttribute:Attribute 12 | { 13 | private string _DataSourceType; 14 | public DataSourceAttribute(string dsType) 15 | { 16 | _DataSourceType = dsType; 17 | } 18 | 19 | public string DataSourceType 20 | { 21 | get { return _DataSourceType; } 22 | set { _DataSourceType = value; } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/Attributes/TransactionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace AA.Dapper.Advanced 6 | { 7 | /// 8 | /// 事务标记 9 | /// 10 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 11 | public class TransactionAttribute : Attribute 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/DbContextHolder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | using AA.FrameWork; 6 | namespace AA.Dapper.Advanced 7 | { 8 | public static class DbContextHolder 9 | { 10 | private static AsyncLocal asyncLocal = new AsyncLocal(); 11 | 12 | public static string _master = "master"; 13 | 14 | public static string _slave = "slave"; 15 | public static string GetDbSourceMode() 16 | { 17 | if (string.IsNullOrEmpty(asyncLocal.Value)) 18 | { 19 | return _master; 20 | } 21 | return asyncLocal.Value; 22 | } 23 | 24 | public static void SetDbSourceMode(string dbType) 25 | { 26 | if (string.IsNullOrEmpty(dbType)) 27 | { 28 | throw new AAException("DbContextHolder SetDbSourceMode set dbType not null"); 29 | } 30 | asyncLocal.Value = dbType; 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/DbDataSource.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.Util; 2 | using AA.FrameWork; 3 | using AA.FrameWork.Extensions; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Collections.Specialized; 7 | using System.Text; 8 | 9 | namespace AA.Dapper.Advanced 10 | { 11 | public class DbDataSource : IDbDatasource 12 | { 13 | public const string PropertyDataSourcePrefix = "aa.dataSource"; 14 | public const string PropertyDataSourceProvider = "provider"; 15 | public const string PropertyDataSourceConnectionString = "connectionString"; 16 | 17 | private static readonly DbDataSource dbDataSource = new DbDataSource(); 18 | 19 | private AAException initException; 20 | private PropertiesParser cfg; 21 | 22 | public static IDbDatasource Instance => dbDataSource; 23 | public void Init(NameValueCollection props) 24 | { 25 | IDbConnectionManager dbMgr = null; 26 | cfg = new PropertiesParser(props); 27 | 28 | var dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix); 29 | foreach (string dataSourceName in dsNames) 30 | { 31 | string datasourceKey = "{0}.{1}".FormatInvariant(PropertyDataSourcePrefix, dataSourceName); 32 | NameValueCollection propertyGroup = cfg.GetPropertyGroup(datasourceKey, true); 33 | PropertiesParser pp = new PropertiesParser(propertyGroup); 34 | string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null); 35 | string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null); 36 | 37 | if (dsProvider == null) 38 | { 39 | initException = new AAException("Provider not specified for DataSource: {0}".FormatInvariant(dataSourceName)); 40 | throw initException; 41 | } 42 | if (dsConnectionString == null) 43 | { 44 | initException = new AAException("Connection string not specified for DataSource: {0}".FormatInvariant(dataSourceName)); 45 | throw initException; 46 | } 47 | try 48 | { 49 | DbProvider dbp = new DbProvider(dsProvider, dsConnectionString); 50 | dbp.Initialize(); 51 | 52 | dbMgr = DBConnectionManager.Instance; 53 | dbMgr.AddConnectionProvider(dataSourceName, dbp); 54 | 55 | } 56 | catch (Exception exception) 57 | { 58 | initException = new AAException("Could not Initialize DataSource: {0}".FormatInvariant(dataSourceName), exception); 59 | throw initException; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/IDbDatasource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Collections; 5 | using System.Collections.Specialized; 6 | 7 | namespace AA.Dapper.Advanced 8 | { 9 | public interface IDbDatasource 10 | { 11 | void Init(NameValueCollection props); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/Interceptor/DataSourceInterceptor.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace AA.Dapper.Advanced 7 | { 8 | public class DataSourceInterceptor : IInterceptor 9 | { 10 | public void Intercept(IInvocation invocation) 11 | { 12 | var customAttrs = invocation.MethodInvocationTarget.GetCustomAttributes(true); 13 | foreach (var attr in customAttrs) 14 | { 15 | var dataSource = attr as DataSourceAttribute; 16 | if (dataSource != null) 17 | { 18 | DbContextHolder.SetDbSourceMode(dataSource.DataSourceType); 19 | } 20 | } 21 | invocation.Proceed(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AA.Dapper/Advanced/Interceptor/TransactionInterceptor.cs: -------------------------------------------------------------------------------- 1 | using AA.FrameWork.Engine; 2 | using Castle.DynamicProxy; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace AA.Dapper.Advanced 8 | { 9 | public class TransactionInterceptor : IInterceptor 10 | { 11 | private IDapperContext dapperContext; 12 | public void Intercept(IInvocation invocation) 13 | { 14 | var customAttrs = invocation.MethodInvocationTarget.GetCustomAttributes(true); 15 | foreach (var attr in customAttrs) 16 | { 17 | var transactionAttribute = attr as TransactionAttribute; 18 | if (transactionAttribute != null) 19 | { 20 | //事务操作默认在主库上进行 21 | DbContextHolder.SetDbSourceMode("master"); 22 | dapperContext = EngineContext.Current.Resolve(); 23 | using (var dbtransaction = dapperContext.BeginTransaction()) 24 | { 25 | try 26 | { 27 | invocation.Proceed(); 28 | dbtransaction.Commit(); 29 | } 30 | catch (Exception ex) 31 | { 32 | Console.Write(ex.Message); 33 | dbtransaction.Rollback(); 34 | throw new Exception(ex.Message); 35 | } 36 | } 37 | } 38 | } 39 | invocation.Proceed(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AA.Dapper/Configuration/IMapConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.FluentMap.Configuration; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AA.Dapper.Configuration 9 | { 10 | public interface IMapConfiguration 11 | { 12 | public Action GetConfiguration(); 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AA.Dapper/Configuration/MapConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.FluentMap; 2 | using AA.Dapper.FluentMap.Configuration; 3 | using AA.Dapper.FluentMap.Dommel; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace AA.Dapper.Configuration 8 | { 9 | public static class MapConfiguration 10 | { 11 | public static void Init(List> configures) 12 | { 13 | FluentMapper.Initialize(config => 14 | { 15 | foreach (var a in configures) 16 | { 17 | a.Invoke(config); 18 | }; 19 | config.ForDommel(); 20 | }); 21 | } 22 | public static void Init(Action configure) 23 | { 24 | FluentMapper.Initialize(config => 25 | { 26 | configure.Invoke(config); 27 | config.ForDommel(); 28 | }); 29 | } 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /AA.Dapper/ConfigurationBasedDbMetadataFactory.cs: -------------------------------------------------------------------------------- 1 |  2 | using AA.Dapper.Util; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Specialized; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace AA.Dapper 11 | { 12 | /// 13 | /// The DbMetadata factory based on application configuration 14 | /// 15 | public class ConfigurationBasedDbMetadataFactory : DbMetadataFactory 16 | { 17 | private readonly string sectionName; 18 | private readonly string providerNamePrefix; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// Name of the configuration section. 24 | /// The provider name prefix. 25 | /// The providerNamePrefix cannot be null or empty. 26 | public ConfigurationBasedDbMetadataFactory(string sectionName, string providerNamePrefix) 27 | { 28 | if (string.IsNullOrEmpty(providerNamePrefix)) 29 | { 30 | throw new ArgumentNullException(nameof(providerNamePrefix)); 31 | } 32 | 33 | this.sectionName = sectionName; 34 | this.providerNamePrefix = providerNamePrefix; 35 | } 36 | 37 | /// 38 | /// Gets the properties parser. 39 | /// 40 | /// The properties parser 41 | protected virtual PropertiesParser GetPropertiesParser() 42 | { 43 | var settings = Util.Configuration.GetSection(sectionName) ?? new NameValueCollection(); 44 | var result = new PropertiesParser(settings); 45 | return result; 46 | } 47 | 48 | /// 49 | /// Gets the supported provider names. 50 | /// 51 | /// The enumeration of the supported provider names 52 | public override IReadOnlyCollection GetProviderNames() 53 | { 54 | PropertiesParser pp = GetPropertiesParser(); 55 | var result = pp.GetPropertyGroups(providerNamePrefix); 56 | return result; 57 | } 58 | 59 | /// 60 | /// Gets the database metadata associated to the specified provider name. 61 | /// 62 | /// Name of the provider. 63 | /// The metadata instance for the specified name 64 | public override DbMetadata GetDbMetadata(string providerName) 65 | { 66 | try 67 | { 68 | PropertiesParser pp = GetPropertiesParser(); 69 | NameValueCollection props = pp.GetPropertyGroup(providerNamePrefix + "." + providerName, true); 70 | DbMetadata metadata = new DbMetadata(); 71 | 72 | ObjectUtils.SetObjectProperties(metadata, props); 73 | metadata.Init(); 74 | 75 | return metadata; 76 | } 77 | catch (Exception ex) 78 | { 79 | throw new ArgumentException("Error while reading metadata information for provider '" + providerName + "'", nameof(providerName), ex); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /AA.Dapper/DapperContext.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.Advanced; 2 | using AA.Dapper.Util; 3 | using AA.FrameWork.Extensions; 4 | using AA.FrameWork.Util; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Collections.Specialized; 8 | using System.Configuration; 9 | using System.Data; 10 | using System.Data.SqlClient; 11 | namespace AA.Dapper 12 | { 13 | public class DapperContext : IDapperContext 14 | { 15 | private IDbConnection _connection = null; 16 | private IDbTransaction _dbTransaction = null; 17 | 18 | public DataBase DataBase 19 | { 20 | get 21 | { 22 | return new DataBase(this); 23 | } 24 | } 25 | /// 26 | /// Get or set the database connection manager. 27 | /// 28 | public IDbConnectionManager ConnectionManager { get; set; } = DBConnectionManager.Instance; 29 | public IDbConnection Connection 30 | { 31 | get 32 | { 33 | if (_connection == null) 34 | { 35 | var prefixDataSource = DbContextHolder.GetDbSourceMode(); 36 | _connection = ConnectionManager.GetConnection(prefixDataSource); 37 | } 38 | return _connection; 39 | } 40 | } 41 | 42 | public IDbTransaction dbTransaction { get { return _dbTransaction; } } 43 | public void Dispose() 44 | { 45 | if (_connection != null && _connection.State == ConnectionState.Open) 46 | _connection.Close(); 47 | } 48 | 49 | 50 | public IDbTransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted) 51 | { 52 | if (Connection.State != ConnectionState.Open) 53 | { 54 | Connection.Open(); 55 | } 56 | _dbTransaction = Connection.BeginTransaction(isolationLevel); 57 | return dbTransaction; 58 | } 59 | 60 | public void Commit() 61 | { 62 | _dbTransaction.Commit(); 63 | _dbTransaction = null; 64 | } 65 | 66 | public void RollBack() 67 | { 68 | _dbTransaction.Rollback(); 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /AA.Dapper/DbMetadataFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AA.Dapper 8 | { 9 | /// 10 | /// Base class for the DbMetadata Factory implementations 11 | /// 12 | public abstract class DbMetadataFactory 13 | { 14 | /// 15 | /// Gets the supported provider names. 16 | /// 17 | /// The enumeration of the supported provider names 18 | public abstract IReadOnlyCollection GetProviderNames(); 19 | 20 | /// 21 | /// Gets the database metadata associated to the specified provider name. 22 | /// 23 | /// Name of the provider. 24 | /// The metadata instance for the requested provider 25 | public abstract DbMetadata GetDbMetadata(string providerName); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/Cache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace AA.Dapper.Dommel 5 | { 6 | internal enum QueryCacheType 7 | { 8 | Get, 9 | GetByMultipleIds, 10 | GetAll, 11 | Project, 12 | ProjectAll, 13 | Count, 14 | Insert, 15 | Update, 16 | Delete, 17 | DeleteAll, 18 | Any, 19 | } 20 | 21 | internal struct QueryCacheKey : IEquatable 22 | { 23 | public QueryCacheKey(QueryCacheType cacheType, ISqlBuilder sqlBuilder, MemberInfo memberInfo) 24 | { 25 | SqlBuilderType = sqlBuilder.GetType(); 26 | CacheType = cacheType; 27 | MemberInfo = memberInfo; 28 | } 29 | 30 | public QueryCacheType CacheType { get; } 31 | 32 | public Type SqlBuilderType { get; } 33 | 34 | public MemberInfo MemberInfo { get; } 35 | 36 | public bool Equals(QueryCacheKey other) => CacheType == other.CacheType && SqlBuilderType == other.SqlBuilderType && MemberInfo == other.MemberInfo; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/ColumnPropertyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.Reflection; 4 | 5 | namespace AA.Dapper.Dommel 6 | { 7 | /// 8 | /// Represents the column of an entity. 9 | /// 10 | public class ColumnPropertyInfo 11 | { 12 | /// 13 | /// Initializes a new instance from the 14 | /// specified instance. 15 | /// 16 | /// 17 | /// The property which represents the database column. The is 18 | /// determined from the option specified on 19 | /// the property. Defaults to when 20 | /// is true; otherwise, . 21 | /// 22 | /// Indicates whether a property is a key column. 23 | public ColumnPropertyInfo(PropertyInfo property, bool isKey = false) 24 | { 25 | Property = property ?? throw new ArgumentNullException(nameof(property)); 26 | GeneratedOption = property.GetCustomAttribute()?.DatabaseGeneratedOption 27 | ?? (isKey ? DatabaseGeneratedOption.Identity : DatabaseGeneratedOption.None); 28 | } 29 | 30 | /// 31 | /// Initializes a new instance from the 32 | /// specified instance using the specified 33 | /// . 34 | /// 35 | /// The property which represents the database column. 36 | /// 37 | /// The which specifies whether the value of 38 | /// the column this property represents is generated by the database. 39 | /// 40 | public ColumnPropertyInfo(PropertyInfo property, DatabaseGeneratedOption generatedOption) 41 | { 42 | Property = property ?? throw new ArgumentNullException(nameof(property)); 43 | GeneratedOption = generatedOption; 44 | } 45 | 46 | /// 47 | /// Gets a reference to the instance. 48 | /// 49 | public PropertyInfo Property { get; } 50 | 51 | /// 52 | /// Gets the which specifies whether the value of 53 | /// the column this property represents is generated by the database. 54 | /// 55 | public DatabaseGeneratedOption GeneratedOption { get; } 56 | 57 | /// 58 | /// Gets a value indicating whether this key property's value is generated by the database. 59 | /// 60 | public bool IsGenerated => GeneratedOption != DatabaseGeneratedOption.None; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/DefaultColumnNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | using System.Reflection; 3 | 4 | namespace AA.Dapper.Dommel 5 | { 6 | /// 7 | /// Implements the . 8 | /// 9 | public class DefaultColumnNameResolver : IColumnNameResolver 10 | { 11 | /// 12 | /// Resolves the column name for the property. 13 | /// Looks for the [Column] attribute. Otherwise it's just the name of the property. 14 | /// 15 | public virtual string ResolveColumnName(PropertyInfo propertyInfo) 16 | { 17 | var columnAttr = propertyInfo.GetCustomAttribute(); 18 | if (columnAttr != null) 19 | { 20 | return columnAttr.Name; 21 | } 22 | 23 | return propertyInfo.Name; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/DefaultKeyPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace AA.Dapper.Dommel 7 | { 8 | /// 9 | /// Implements the interface by resolving key properties 10 | /// with the [] or with the name 'Id'. 11 | /// 12 | public class DefaultKeyPropertyResolver : IKeyPropertyResolver 13 | { 14 | /// 15 | /// Finds the key properties by looking for properties with the 16 | /// [] attribute or with the name 'Id'. 17 | /// 18 | public ColumnPropertyInfo[] ResolveKeyProperties(Type type) 19 | { 20 | var keyProps = Resolvers 21 | .Properties(type) 22 | .Select(x => x.Property) 23 | .Where(p => string.Equals(p.Name, "Id", StringComparison.OrdinalIgnoreCase) || p.GetCustomAttribute() != null) 24 | .ToArray(); 25 | 26 | if (keyProps.Length == 0) 27 | { 28 | throw new InvalidOperationException($"Could not find the key properties for type '{type.FullName}'."); 29 | } 30 | 31 | return keyProps.Select(p => new ColumnPropertyInfo(p, isKey: true)).ToArray(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/DefaultPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Reflection; 5 | 6 | namespace AA.Dapper.Dommel 7 | { 8 | /// 9 | /// Default implemenation of the interface. 10 | /// 11 | public class DefaultPropertyResolver : IPropertyResolver 12 | { 13 | private static readonly HashSet PrimitiveTypesSet = new HashSet 14 | { 15 | typeof(object), 16 | typeof(string), 17 | typeof(Guid), 18 | typeof(decimal), 19 | typeof(double), 20 | typeof(float), 21 | typeof(DateTime), 22 | typeof(DateTimeOffset), 23 | typeof(TimeSpan), 24 | typeof(byte[]), 25 | }; 26 | 27 | /// 28 | /// Resolves the properties to be mapped for the specified type. 29 | /// 30 | /// The type to resolve the properties to be mapped for. 31 | /// A collection of 's of the . 32 | public virtual IEnumerable ResolveProperties(Type type) 33 | { 34 | foreach (var property in FilterComplexTypes(type.GetRuntimeProperties())) 35 | { 36 | if (!property.IsDefined(typeof(IgnoreAttribute)) && !property.IsDefined(typeof(NotMappedAttribute))) 37 | { 38 | yield return new ColumnPropertyInfo(property); 39 | } 40 | } 41 | } 42 | 43 | /// 44 | /// Gets a collection of types that are considered 'primitive' for Dommel but are not for the CLR. 45 | /// Override this to specify your own set of types. 46 | /// 47 | protected virtual HashSet PrimitiveTypes => PrimitiveTypesSet; 48 | 49 | /// 50 | /// Filters the complex types from the specified collection of properties. 51 | /// 52 | /// A collection of properties. 53 | /// The properties that are considered 'primitive' of . 54 | protected virtual IEnumerable FilterComplexTypes(IEnumerable properties) 55 | { 56 | foreach (var property in properties) 57 | { 58 | var type = property.PropertyType; 59 | type = Nullable.GetUnderlyingType(type) ?? type; 60 | if (type.GetTypeInfo().IsPrimitive || type.GetTypeInfo().IsEnum || PrimitiveTypes.Contains(type)) 61 | { 62 | yield return property; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/DefaultTableNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.Reflection; 4 | 5 | namespace AA.Dapper.Dommel 6 | { 7 | /// 8 | /// Default implementation of the interface. 9 | /// 10 | public class DefaultTableNameResolver : ITableNameResolver 11 | { 12 | /// 13 | /// Resolves the table name. 14 | /// Looks for the [Table] attribute. Otherwise by making the type 15 | /// plural (eg. Product -> Products) and removing the 'I' prefix for interfaces. 16 | /// 17 | public virtual string ResolveTableName(Type type) 18 | { 19 | var typeInfo = type.GetTypeInfo(); 20 | var tableAttr = typeInfo.GetCustomAttribute(); 21 | if (tableAttr != null) 22 | { 23 | if (!string.IsNullOrEmpty(tableAttr.Schema)) 24 | { 25 | return $"{tableAttr.Schema}.{tableAttr.Name}"; 26 | } 27 | 28 | return tableAttr.Name; 29 | } 30 | 31 | // Fall back to plural of table name 32 | var name = type.Name; 33 | if (name.EndsWith("y", StringComparison.OrdinalIgnoreCase)) 34 | { 35 | // Category -> Categories 36 | name = name.Remove(name.Length - 1) + "ies"; 37 | } 38 | else if (!name.EndsWith("s", StringComparison.OrdinalIgnoreCase)) 39 | { 40 | // Product -> Products 41 | name += "s"; 42 | } 43 | 44 | return name; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/ForeignKeyRelation.cs: -------------------------------------------------------------------------------- 1 | namespace AA.Dapper.Dommel 2 | { 3 | /// 4 | /// Describes a foreign key relationship. 5 | /// 6 | public enum ForeignKeyRelation 7 | { 8 | /// 9 | /// Specifies a one-to-one relationship. 10 | /// 11 | OneToOne, 12 | 13 | /// 14 | /// Specifies a one-to-many relationship. 15 | /// 16 | OneToMany 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/From.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Threading.Tasks; 5 | using Dapper; 6 | 7 | namespace AA.Dapper.Dommel 8 | { 9 | public static partial class DommelMapper 10 | { 11 | /// 12 | /// Executes an expression to query data from . 13 | /// 14 | /// The entity to query data from. 15 | /// The connection to query data from. 16 | /// A callback to build a . 17 | /// Optional transaction for the command. 18 | /// 19 | /// A value indicating whether the result of the query should be executed directly, 20 | /// or when the query is materialized (using ToList() for example). 21 | /// 22 | /// The collection of entities returned from the query. 23 | public static IEnumerable From(this IDbConnection con, Action> sqlBuilder, IDbTransaction? transaction = null, bool buffered = true) 24 | { 25 | var sqlExpression = CreateSqlExpression(GetSqlBuilder(con)); 26 | sqlBuilder(sqlExpression); 27 | var sql = sqlExpression.ToSql(out var parameters); 28 | return con.Query(sql.Replace("True","1=1"), parameters, transaction, buffered); 29 | } 30 | 31 | /// 32 | /// Executes an expression to query data from . 33 | /// 34 | /// The entity to query data from. 35 | /// The connection to query data from. 36 | /// A callback to build a . 37 | /// Optional transaction for the command. 38 | /// The collection of entities returned from the query. 39 | public static async Task> FromAsync(this IDbConnection con, Action> sqlBuilder, IDbTransaction? transaction = null) 40 | { 41 | var sqlExpression = CreateSqlExpression(GetSqlBuilder(con)); 42 | sqlBuilder(sqlExpression); 43 | var sql = sqlExpression.ToSql(out var parameters); 44 | return await con.QueryAsync(sql.Replace("True", "1=1"), parameters, transaction); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/IColumnNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// Defines methods for resolving column names for entities. 7 | /// Custom implementations can be registered with . 8 | /// 9 | public interface IColumnNameResolver 10 | { 11 | /// 12 | /// Resolves the column name for the specified property. 13 | /// 14 | /// The property of the entity. 15 | /// The column name for the property. 16 | string ResolveColumnName(PropertyInfo propertyInfo); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/IForeignKeyPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace AA.Dapper.Dommel 5 | { 6 | /// 7 | /// Defines methods for resolving foreign key properties. 8 | /// Custom implementations can be registered with . 9 | /// 10 | public interface IForeignKeyPropertyResolver 11 | { 12 | /// 13 | /// Resolves the foreign key property for the specified source type and including type. 14 | /// 15 | /// The source type which should contain the foreign key property. 16 | /// The type of the foreign key relation. 17 | /// The foreign key relationship type. 18 | /// The foreign key property for and . 19 | PropertyInfo ResolveForeignKeyProperty(Type sourceType, Type includingType, out ForeignKeyRelation foreignKeyRelation); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/IKeyPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace AA.Dapper.Dommel 5 | { 6 | /// 7 | /// Defines methods for resolving the key property of entities. 8 | /// Custom implementations can be registered with . 9 | /// 10 | public interface IKeyPropertyResolver 11 | { 12 | /// 13 | /// Resolves the key properties for the specified type. 14 | /// 15 | /// The type to resolve the key properties for. 16 | /// A collection of instances of the key properties of . 17 | ColumnPropertyInfo[] ResolveKeyProperties(Type type); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/IPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace AA.Dapper.Dommel 6 | { 7 | /// 8 | /// Defines methods for resolving the properties of entities. 9 | /// Custom implementations can be registered with . 10 | /// 11 | public interface IPropertyResolver 12 | { 13 | /// 14 | /// Resolves the properties to be mapped for the specified type. 15 | /// 16 | /// The type to resolve the properties to be mapped for. 17 | /// A collection of 's of the . 18 | IEnumerable ResolveProperties(Type type); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/ISqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// Defines methods for building specialized SQL queries. 7 | /// 8 | public interface ISqlBuilder 9 | { 10 | /// 11 | /// Adds a prefix to the specified parameter. 12 | /// 13 | /// The name of the parameter to prefix. 14 | string PrefixParameter(string paramName); 15 | 16 | /// 17 | /// Builds an insert query using the specified table name, column names and parameter names. 18 | /// A query to fetch the new ID will be included as well. 19 | /// 20 | /// The type of the entity to generate the insert query for. 21 | /// The name of the table to query. 22 | /// The names of the columns in the table. 23 | /// The names of the parameters in the database command. 24 | /// An insert query including a query to fetch the new ID. 25 | string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames); 26 | 27 | /// 28 | /// Builds the paging part to be appended to an existing select query. 29 | /// 30 | /// The order by part of the query. 31 | /// The number of the page to fetch, starting at 1. 32 | /// The page size. 33 | /// The paging part of a query. 34 | string BuildPaging(string? orderBy, int pageNumber, int pageSize); 35 | 36 | /// 37 | /// Adds quotes around (or at the start) of an identifier such as a table or column name. 38 | /// 39 | /// The identifier add quotes around. E.g. a table or column name. 40 | /// The quoted . 41 | string QuoteIdentifier(string identifier); 42 | 43 | /// 44 | /// Adds a limit clause to query. 45 | /// 46 | /// The count of limit clause. 47 | /// A limit clause of the specified count. 48 | string LimitClause(int count); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/ITableNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// Defines methods for resolving table names of entities. 7 | /// Custom implementations can be registered with . 8 | /// 9 | public interface ITableNameResolver 10 | { 11 | /// 12 | /// Resolves the table name for the specified type. 13 | /// 14 | /// The type to resolve the table name for. 15 | /// A string containing the resolved table name for for . 16 | string ResolveTableName(Type type); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/IgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// Specifies that a property should be ignored. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public class IgnoreAttribute : Attribute 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/MySqlSqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// implementation for MySQL. 7 | /// 8 | public class MySqlSqlBuilder : ISqlBuilder 9 | { 10 | /// 11 | public virtual string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames) => 12 | $"insert into {tableName} ({string.Join(", ", columnNames)}) values ({string.Join(", ", paramNames)}); select LAST_INSERT_ID() id"; 13 | 14 | /// 15 | public virtual string BuildPaging(string? orderBy, int pageNumber, int pageSize) 16 | { 17 | var start = pageNumber >= 1 ? (pageNumber - 1) * pageSize : 0; 18 | return $" {orderBy} limit {start}, {pageSize}"; 19 | } 20 | 21 | /// 22 | public string PrefixParameter(string paramName) => $"@{paramName}"; 23 | 24 | /// 25 | public string QuoteIdentifier(string identifier) => $"`{identifier}`"; 26 | 27 | /// 28 | public string LimitClause(int count) => $"limit {count}"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/PostgresSqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace AA.Dapper.Dommel 5 | { 6 | /// 7 | /// implementation for Postgres. 8 | /// 9 | public class PostgresSqlBuilder : ISqlBuilder 10 | { 11 | /// 12 | public virtual string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames) 13 | { 14 | if (type == null) 15 | { 16 | throw new ArgumentNullException(nameof(type)); 17 | } 18 | 19 | var sql = $"insert into {tableName} ({string.Join(", ", columnNames)}) values ({string.Join(", ", paramNames)}) "; 20 | 21 | var keyColumns = Resolvers.KeyProperties(type).Where(p => p.IsGenerated).Select(p => Resolvers.Column(p.Property, this)); 22 | if (keyColumns.Any()) 23 | { 24 | sql += $"returning ({string.Join(", ", keyColumns)})"; 25 | } 26 | 27 | return sql; 28 | } 29 | 30 | /// 31 | public virtual string BuildPaging(string? orderBy, int pageNumber, int pageSize) 32 | { 33 | var start = pageNumber >= 1 ? (pageNumber - 1) * pageSize : 0; 34 | return $" {orderBy} offset {start} limit {pageSize}"; 35 | } 36 | 37 | /// 38 | public string PrefixParameter(string paramName) => $"@{paramName}"; 39 | 40 | /// 41 | public string QuoteIdentifier(string identifier) => $"\"{identifier}\""; 42 | 43 | /// 44 | public string LimitClause(int count) => $"limit {count}"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/SqlServerCeSqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// implementation for SQL Server Compact Edition. 7 | /// 8 | public class SqlServerCeSqlBuilder : ISqlBuilder 9 | { 10 | /// 11 | public virtual string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames) => 12 | $"insert into {tableName} ({string.Join(", ", columnNames)}) values ({string.Join(", ", paramNames)}); select @@IDENTITY"; 13 | 14 | /// 15 | public virtual string BuildPaging(string? orderBy, int pageNumber, int pageSize) 16 | { 17 | var start = pageNumber >= 1 ? (pageNumber - 1) * pageSize : 0; 18 | return $" {orderBy} offset {start} rows fetch next {pageSize} rows only"; 19 | } 20 | 21 | /// 22 | public string PrefixParameter(string paramName) => $"@{paramName}"; 23 | 24 | /// 25 | public string QuoteIdentifier(string identifier) => $"[{identifier}]"; 26 | 27 | /// 28 | public string LimitClause(int count) => $"order by 1 offset 0 rows fetch next {count} rows only"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/SqlServerSqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// implementation for SQL Server. 7 | /// 8 | public class SqlServerSqlBuilder : ISqlBuilder 9 | { 10 | /// 11 | public virtual string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames) => 12 | $"set nocount on insert into {tableName} ({string.Join(", ", columnNames)}) values ({string.Join(", ", paramNames)}); select scope_identity()"; 13 | 14 | /// 15 | public virtual string BuildPaging(string? orderBy, int pageNumber, int pageSize) 16 | { 17 | var start = pageNumber >= 1 ? (pageNumber - 1) * pageSize : 0; 18 | return $" {orderBy} offset {start} rows fetch next {pageSize} rows only"; 19 | } 20 | 21 | /// 22 | public string PrefixParameter(string paramName) => $"@{paramName}"; 23 | 24 | /// 25 | public string QuoteIdentifier(string identifier) => $"[{identifier}]"; 26 | 27 | /// 28 | public string LimitClause(int count) => $"order by 1 offset 0 rows fetch next {count} rows only"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/SqliteSqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AA.Dapper.Dommel 4 | { 5 | /// 6 | /// implementation for SQLite. 7 | /// 8 | public class SqliteSqlBuilder : ISqlBuilder 9 | { 10 | /// 11 | public virtual string BuildInsert(Type type, string tableName, string[] columnNames, string[] paramNames) => 12 | $"insert into {tableName} ({string.Join(", ", columnNames)}) values ({string.Join(", ", paramNames)}); select last_insert_rowid() id"; 13 | 14 | /// 15 | public virtual string BuildPaging(string? orderBy, int pageNumber, int pageSize) 16 | { 17 | var start = pageNumber >= 1 ? (pageNumber - 1) * pageSize : 0; 18 | return $" {orderBy} LIMIT {start}, {pageSize}"; 19 | } 20 | 21 | /// 22 | public string PrefixParameter(string paramName) => $"@{paramName}"; 23 | 24 | /// 25 | public string QuoteIdentifier(string identifier) => identifier; 26 | 27 | /// 28 | public string LimitClause(int count) => $"limit {count}"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AA.Dapper/Dommel/Update.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Dapper; 6 | 7 | namespace AA.Dapper.Dommel 8 | { 9 | public static partial class DommelMapper 10 | { 11 | /// 12 | /// Updates the values of the specified entity in the database. 13 | /// The return value indicates whether the operation succeeded. 14 | /// 15 | /// The type of the entity. 16 | /// The connection to the database. This can either be open or closed. 17 | /// The entity in the database. 18 | /// Optional transaction for the command. 19 | /// A value indicating whether the update operation succeeded. 20 | public static bool Update(this IDbConnection connection, TEntity entity, IDbTransaction? transaction = null) 21 | { 22 | var sql = BuildUpdateQuery(GetSqlBuilder(connection), typeof(TEntity)); 23 | LogQuery(sql); 24 | return connection.Execute(sql, entity, transaction) > 0; 25 | } 26 | 27 | /// 28 | /// Updates the values of the specified entity in the database. 29 | /// The return value indicates whether the operation succeeded. 30 | /// 31 | /// The type of the entity. 32 | /// The connection to the database. This can either be open or closed. 33 | /// The entity in the database. 34 | /// Optional transaction for the command. 35 | /// A value indicating whether the update operation succeeded. 36 | public static async Task UpdateAsync(this IDbConnection connection, TEntity entity, IDbTransaction? transaction = null) 37 | { 38 | var sql = BuildUpdateQuery(GetSqlBuilder(connection), typeof(TEntity)); 39 | LogQuery(sql); 40 | return await connection.ExecuteAsync(sql, entity, transaction) > 0; 41 | } 42 | 43 | internal static string BuildUpdateQuery(ISqlBuilder sqlBuilder, Type type) 44 | { 45 | var cacheKey = new QueryCacheKey(QueryCacheType.Update, sqlBuilder, type); 46 | if (!QueryCache.TryGetValue(cacheKey, out var sql)) 47 | { 48 | var tableName = Resolvers.Table(type, sqlBuilder); 49 | 50 | // Use all non-key and non-generated properties for updates 51 | var keyProperties = Resolvers.KeyProperties(type); 52 | var typeProperties = Resolvers.Properties(type) 53 | .Where(x => !x.IsGenerated) 54 | .Select(x => x.Property) 55 | .Except(keyProperties.Where(p => p.IsGenerated).Select(p => p.Property)); 56 | 57 | var columnNames = typeProperties.Select(p => $"{Resolvers.Column(p, sqlBuilder)} = {sqlBuilder.PrefixParameter(p.Name)}").ToArray(); 58 | var whereClauses = keyProperties.Select(p => $"{Resolvers.Column(p.Property, sqlBuilder)} = {sqlBuilder.PrefixParameter(p.Property.Name)}"); 59 | sql = $"update {tableName} set {string.Join(", ", columnNames)} where {string.Join(" and ", whereClauses)}"; 60 | if (sql.IndexOf("(True") != -1) 61 | { 62 | sql = sql.Replace("(True", "(1=1"); 63 | } 64 | QueryCache.TryAdd(cacheKey, sql); 65 | } 66 | 67 | return sql; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /AA.Dapper/EmbeddedAssemblyResourceDbMetadataFactory.cs: -------------------------------------------------------------------------------- 1 |  2 | using AA.Dapper.Util; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Specialized; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace AA.Dapper 11 | { 12 | 13 | public class EmbeddedAssemblyResourceDbMetadataFactory : DbMetadataFactory 14 | { 15 | private readonly string resourceName; 16 | private readonly string propertyGroupName; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// Name of the resource. 22 | /// Name of the property group (The prefix of the provider name). 23 | public EmbeddedAssemblyResourceDbMetadataFactory(string resourceName, string propertyGroupName) 24 | { 25 | this.resourceName = resourceName; 26 | this.propertyGroupName = propertyGroupName; 27 | } 28 | 29 | /// 30 | /// Gets the supported provider names.(获取支持的数据库) 31 | /// 32 | /// The enumeration of the supported provider names 33 | public override IReadOnlyCollection GetProviderNames() 34 | { 35 | PropertiesParser pp = PropertiesParser.ReadFromEmbeddedAssemblyResource(resourceName); 36 | var result = pp.GetPropertyGroups(propertyGroupName); 37 | return result; 38 | } 39 | 40 | /// 41 | /// Gets the database metadata associated to the specified provider name. 42 | /// 43 | /// Name of the provider. 44 | /// The metadata instance for the specified name 45 | public override DbMetadata GetDbMetadata(string providerName) 46 | { 47 | List deprecatedProviders = new List 48 | { 49 | "Npgsql-10", 50 | "SqlServer-11" 51 | }; 52 | 53 | if (deprecatedProviders.Contains(providerName)) 54 | { 55 | throw new Exception(providerName + " provider is no longer supported."); 56 | } 57 | 58 | try 59 | { 60 | PropertiesParser pp = PropertiesParser.ReadFromEmbeddedAssemblyResource(resourceName); 61 | NameValueCollection props = pp.GetPropertyGroup(propertyGroupName + "." + providerName, true); 62 | DbMetadata metadata = new DbMetadata(); 63 | 64 | ObjectUtils.SetObjectProperties(metadata, props); 65 | metadata.Init(); 66 | 67 | return metadata; 68 | } 69 | catch (Exception ex) 70 | { 71 | throw new ArgumentException("Error while reading metadata information for provider '" + providerName + "'", nameof(providerName), ex); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/FluentMapConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.FluentMap.Configuration; 2 | using AA.Dapper.FluentMap.Dommel.Resolvers; 3 | using AA.Dapper.Dommel; 4 | 5 | namespace AA.Dapper.FluentMap.Dommel 6 | { 7 | /// 8 | /// Defines methods for configured Dapper.FluentMap.Dommel. 9 | /// 10 | public static class FluentMapConfigurationExtensions 11 | { 12 | /// 13 | /// Configures the specified configuration for Dapper.FluentMap.Dommel. 14 | /// 15 | /// The Dapper.FluentMap configuration. 16 | /// The Dapper.FluentMap configuration. 17 | public static FluentMapConfiguration ForDommel(this FluentMapConfiguration config) 18 | { 19 | DommelMapper.SetColumnNameResolver(new DommelColumnNameResolver()); 20 | DommelMapper.SetKeyPropertyResolver(new DommelKeyPropertyResolver()); 21 | DommelMapper.SetTableNameResolver(new DommelTableNameResolver()); 22 | DommelMapper.SetPropertyResolver(new DommelPropertyResolver()); 23 | return config; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Mapping/DommelEntityMap.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AA.Dapper.FluentMap.Mapping; 3 | 4 | namespace AA.Dapper.FluentMap.Dommel.Mapping 5 | { 6 | /// 7 | /// Represents a non-typed mapping of an entity for Dommel. 8 | /// 9 | public interface IDommelEntityMap : IEntityMap 10 | { 11 | /// 12 | /// Gets the table name for the current entity. 13 | /// 14 | string TableName { get; } 15 | } 16 | 17 | /// 18 | /// Represents the typed mapping of an entity for Dommel. 19 | /// 20 | /// The type of an entity. 21 | public abstract class DommelEntityMap : EntityMapBase, IDommelEntityMap 22 | where TEntity : class 23 | { 24 | /// 25 | /// Gets the implementation for the current entity map. 26 | /// 27 | /// The information about the property. 28 | /// An implementation of . 29 | protected override DommelPropertyMap GetPropertyMap(PropertyInfo info) 30 | { 31 | return new DommelPropertyMap(info); 32 | } 33 | 34 | /// 35 | /// Gets the table name for this entity map. 36 | /// 37 | public string TableName { get; private set; } 38 | 39 | /// 40 | /// Sets the table name for the current entity. 41 | /// 42 | /// The name of the table in the database. 43 | protected void ToTable(string tableName) 44 | { 45 | TableName = tableName; 46 | } 47 | 48 | /// 49 | /// Sets the table name for the current entity. 50 | /// 51 | /// The name of the table in the database. 52 | /// The name of the table schema in the database. 53 | protected void ToTable(string tableName, string schemaName) 54 | { 55 | TableName = $"{schemaName}.{tableName}"; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Mapping/DommelPropertyMap.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | using System.Reflection; 3 | using AA.Dapper.FluentMap.Mapping; 4 | 5 | namespace AA.Dapper.FluentMap.Dommel.Mapping 6 | { 7 | /// 8 | /// Represents mapping of a property for Dommel. 9 | /// 10 | public class DommelPropertyMap : PropertyMapBase, IPropertyMap 11 | { 12 | /// 13 | /// Initializes a new instance of the class 14 | /// with the specified object. 15 | /// 16 | /// The information about the property. 17 | public DommelPropertyMap(PropertyInfo info) : base(info) 18 | { 19 | } 20 | 21 | /// 22 | /// Gets a value indicating whether this property is a primary key. 23 | /// 24 | public bool Key { get; private set; } 25 | 26 | /// 27 | /// Gets a value indicating whether this primary key is an identity. 28 | /// 29 | public bool Identity { get; set; } 30 | 31 | /// 32 | /// Gets a value indicating how the column is generated. 33 | /// 34 | public DatabaseGeneratedOption GeneratedOption { get; set; } = DatabaseGeneratedOption.None; 35 | 36 | /// 37 | /// Specifies the current property as key for the entity. 38 | /// 39 | /// The current instance of . 40 | public DommelPropertyMap IsKey() 41 | { 42 | Key = true; 43 | return this; 44 | } 45 | 46 | /// 47 | /// Specifies the current property as an identity. 48 | /// 49 | /// The current instance of . 50 | public DommelPropertyMap IsIdentity() 51 | { 52 | Identity = true; 53 | return this; 54 | } 55 | 56 | /// 57 | /// Specifies how the property is generated. 58 | /// 59 | public DommelPropertyMap SetGeneratedOption(DatabaseGeneratedOption option) 60 | { 61 | GeneratedOption = option; 62 | return this; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Resolvers/DommelColumnNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using AA.Dapper.FluentMap.Dommel.Mapping; 4 | using AA.Dapper.FluentMap.Mapping; 5 | using AA.Dapper.Dommel; 6 | 7 | namespace AA.Dapper.FluentMap.Dommel.Resolvers 8 | { 9 | /// 10 | /// Implements the interface by using the configured mapping. 11 | /// 12 | public class DommelColumnNameResolver : IColumnNameResolver 13 | { 14 | private static readonly IColumnNameResolver DefaultResolver = new DefaultColumnNameResolver(); 15 | 16 | /// 17 | public string ResolveColumnName(PropertyInfo propertyInfo) 18 | { 19 | if (propertyInfo.DeclaringType != null) 20 | { 21 | #if NETSTANDARD1_3 22 | if (FluentMapper.EntityMaps.TryGetValue(propertyInfo.DeclaringType, out var entityMap)) 23 | 24 | #else 25 | if (FluentMapper.EntityMaps.TryGetValue(propertyInfo.ReflectedType, out var entityMap)) 26 | #endif 27 | { 28 | var mapping = entityMap as IDommelEntityMap; 29 | if (mapping != null) 30 | { 31 | var propertyMaps = entityMap.PropertyMaps.Where(m => m.PropertyInfo.Name == propertyInfo.Name).ToList(); 32 | if (propertyMaps.Count == 1) 33 | { 34 | return propertyMaps[0].ColumnName; 35 | } 36 | } 37 | } 38 | #if NETSTANDARD1_3 39 | else if (FluentMapper.TypeConventions.TryGetValue(propertyInfo.DeclaringType, out var conventions)) 40 | 41 | #else 42 | else if (FluentMapper.TypeConventions.TryGetValue(propertyInfo.ReflectedType, out var conventions)) 43 | #endif 44 | { 45 | foreach (var convention in conventions) 46 | { 47 | var propertyMaps = convention.PropertyMaps.Where(m => m.PropertyInfo.Name == propertyInfo.Name).ToList(); 48 | if (propertyMaps.Count == 1) 49 | { 50 | return propertyMaps[0].ColumnName; 51 | } 52 | } 53 | } 54 | } 55 | 56 | return DefaultResolver.ResolveColumnName(propertyInfo); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Resolvers/DommelKeyPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using AA.Dapper.FluentMap.Dommel.Mapping; 5 | using AA.Dapper.FluentMap.Mapping; 6 | using AA.Dapper.Dommel; 7 | 8 | namespace AA.Dapper.FluentMap.Dommel.Resolvers 9 | { 10 | /// 11 | /// Implements the interface by using the configured mapping. 12 | /// 13 | public class DommelKeyPropertyResolver : IKeyPropertyResolver 14 | { 15 | private static readonly IKeyPropertyResolver DefaultResolver = new DefaultKeyPropertyResolver(); 16 | 17 | /// 18 | public ColumnPropertyInfo[] ResolveKeyProperties(Type type) 19 | { 20 | IEntityMap entityMap; 21 | if (!FluentMapper.EntityMaps.TryGetValue(type, out entityMap)) 22 | { 23 | return DefaultResolver.ResolveKeyProperties(type); 24 | } 25 | 26 | var mapping = entityMap as IDommelEntityMap; 27 | if (mapping != null) 28 | { 29 | var allPropertyMaps = entityMap.PropertyMaps.OfType(); 30 | var keyPropertyInfos = allPropertyMaps 31 | .Where(e => e.Key) 32 | .Select(x => new ColumnPropertyInfo(x.PropertyInfo, isKey: true)) 33 | .ToArray(); 34 | 35 | // Now make sure there aren't any missing key properties that weren't explicitly defined in the mapping. 36 | try 37 | { 38 | // Make sure to exclude any keys that were defined in the dommel entity map and not marked as keys. 39 | var defaultKeyPropertyInfos = DefaultResolver.ResolveKeyProperties(type).Where(x => allPropertyMaps.Count(y => y.PropertyInfo.Equals(x.Property)) == 0); 40 | keyPropertyInfos = keyPropertyInfos.Union(defaultKeyPropertyInfos).ToArray(); 41 | } 42 | catch 43 | { 44 | // There could be no default Ids found. This is okay as long as we found a custom one. 45 | if (keyPropertyInfos.Length == 0) 46 | { 47 | throw new InvalidOperationException($"Could not find the key properties for type '{type.FullName}'."); 48 | } 49 | } 50 | 51 | return keyPropertyInfos; 52 | } 53 | 54 | // Fall back to the default mapping strategy. 55 | return DefaultResolver.ResolveKeyProperties(type); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Resolvers/DommelPropertyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using AA.Dapper.FluentMap.Dommel.Mapping; 6 | using AA.Dapper.FluentMap.Mapping; 7 | using AA.Dapper.Dommel; 8 | 9 | namespace AA.Dapper.FluentMap.Dommel.Resolvers 10 | { 11 | /// 12 | /// Implements the interface by using the configured mapping. 13 | /// 14 | public class DommelPropertyResolver : DefaultPropertyResolver 15 | { 16 | private static readonly IPropertyResolver DefaultResolver = new DefaultPropertyResolver(); 17 | 18 | /// 19 | protected override IEnumerable FilterComplexTypes(IEnumerable properties) 20 | { 21 | foreach (var propertyInfo in properties) 22 | { 23 | var type = propertyInfo.PropertyType; 24 | type = Nullable.GetUnderlyingType(type) ?? type; 25 | 26 | if (type.GetTypeInfo().IsPrimitive || type.GetTypeInfo().IsEnum || PrimitiveTypes.Contains(type)) 27 | { 28 | yield return propertyInfo; 29 | } 30 | } 31 | } 32 | 33 | /// 34 | public override IEnumerable ResolveProperties(Type type) 35 | { 36 | IEntityMap entityMap; 37 | if (FluentMapper.EntityMaps.TryGetValue(type, out entityMap)) 38 | { 39 | foreach (var property in FilterComplexTypes(type.GetProperties())) 40 | { 41 | // Determine whether the property should be ignored. 42 | var propertyMap = entityMap.PropertyMaps.FirstOrDefault(p => p.PropertyInfo.Name == property.Name); 43 | if (propertyMap == null || !propertyMap.Ignored) 44 | { 45 | var dommelPropertyMap = propertyMap as DommelPropertyMap; 46 | if (dommelPropertyMap != null) 47 | { 48 | yield return new ColumnPropertyInfo(property, isKey: dommelPropertyMap.Key); 49 | } 50 | else 51 | { 52 | yield return new ColumnPropertyInfo(property); 53 | } 54 | } 55 | } 56 | } 57 | else 58 | { 59 | foreach (var property in DefaultResolver.ResolveProperties(type)) 60 | { 61 | yield return property; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap.Dommel/Resolvers/DommelTableNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AA.Dapper.FluentMap.Dommel.Mapping; 3 | using AA.Dapper.FluentMap.Mapping; 4 | using AA.Dapper.Dommel; 5 | 6 | 7 | namespace AA.Dapper.FluentMap.Dommel.Resolvers 8 | { 9 | /// 10 | /// Implements the interface by using the configured mapping. 11 | /// 12 | public class DommelTableNameResolver : ITableNameResolver 13 | { 14 | private static readonly ITableNameResolver DefaultResolver = new DefaultTableNameResolver(); 15 | 16 | /// 17 | public string ResolveTableName(Type type) 18 | { 19 | IEntityMap entityMap; 20 | if (FluentMapper.EntityMaps.TryGetValue(type, out entityMap)) 21 | { 22 | var mapping = entityMap as IDommelEntityMap; 23 | 24 | if (mapping != null) 25 | { 26 | return mapping.TableName; 27 | } 28 | } 29 | 30 | return DefaultResolver.ResolveTableName(type); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/Configuration/FluentMapConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.ComponentModel; 4 | using AA.Dapper.FluentMap.Conventions; 5 | using AA.Dapper.FluentMap.Mapping; 6 | 7 | namespace AA.Dapper.FluentMap.Configuration 8 | { 9 | /// 10 | /// Defines methods for configuring Dapper.FluentMap. 11 | /// 12 | public class FluentMapConfiguration 13 | { 14 | /// 15 | /// Adds the specified to the configuration of Dapper.FluentMap. 16 | /// 17 | /// The type argument of the entity. 18 | /// 19 | /// An instance of the interface containing the 20 | /// entity mapping configuration. 21 | /// 22 | public void AddMap(IEntityMap mapper) where TEntity : class 23 | { 24 | if (FluentMapper.EntityMaps.TryAdd(typeof(TEntity), mapper)) 25 | { 26 | FluentMapper.AddTypeMap(); 27 | } 28 | else 29 | { 30 | throw new InvalidOperationException($"Adding entity map for type '{typeof(TEntity)}' failed. The type already exists. Current entity maps: " + string.Join(", ", FluentMapper.EntityMaps.Select(e => e.Key.ToString()))); 31 | } 32 | } 33 | 34 | /// 35 | /// Adds the specified to the configuration of Dapper.FluentMap. 36 | /// 37 | /// The type of the convention. 38 | /// 39 | /// An instance of 40 | /// which allows configuration of the convention. 41 | /// 42 | public FluentConventionConfiguration AddConvention() where TConvention : Convention, new() 43 | { 44 | return new FluentConventionConfiguration(new TConvention()); 45 | } 46 | 47 | #region EditorBrowsableStates 48 | /// 49 | [EditorBrowsable(EditorBrowsableState.Never)] 50 | public override string ToString() 51 | { 52 | return base.ToString(); 53 | } 54 | 55 | /// 56 | [EditorBrowsable(EditorBrowsableState.Never)] 57 | public override bool Equals(object obj) 58 | { 59 | return base.Equals(obj); 60 | } 61 | 62 | /// 63 | [EditorBrowsable(EditorBrowsableState.Never)] 64 | public override int GetHashCode() 65 | { 66 | return base.GetHashCode(); 67 | } 68 | 69 | /// 70 | [EditorBrowsable(EditorBrowsableState.Never)] 71 | public new Type GetType() 72 | { 73 | return base.GetType(); 74 | } 75 | #endregion 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/Conventions/PropertyConventionConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Reflection; 5 | 6 | namespace AA.Dapper.FluentMap.Conventions 7 | { 8 | /// 9 | /// Represents the configuration for a convention. 10 | /// 11 | public class PropertyConventionConfiguration 12 | { 13 | /// 14 | /// Initializes a new instance of the class, 15 | /// allowing configuration for a convention. 16 | /// 17 | public PropertyConventionConfiguration() 18 | { 19 | PropertyPredicates = new List>(); 20 | } 21 | 22 | internal IList> PropertyPredicates { get; } 23 | 24 | internal ConventionPropertyConfiguration PropertyConfiguration { get; private set; } 25 | 26 | /// 27 | /// Filters the properties that this convention applies to based on a predicate. 28 | /// 29 | /// A function to test each property for a condition. 30 | /// The same instance of . 31 | public PropertyConventionConfiguration Where(Func predicate) 32 | { 33 | PropertyPredicates.Add(predicate); 34 | return this; 35 | } 36 | 37 | /// 38 | /// Configures the properties that this convention applies to. 39 | /// 40 | /// 41 | /// An action that performs configuration against 42 | /// . 43 | /// 44 | public void Configure(Action configure) 45 | { 46 | var config = new ConventionPropertyConfiguration(); 47 | PropertyConfiguration = config; 48 | configure(config); 49 | } 50 | 51 | #region EditorBrowsableStates 52 | /// 53 | [EditorBrowsable(EditorBrowsableState.Never)] 54 | public override string ToString() 55 | { 56 | return base.ToString(); 57 | } 58 | 59 | /// 60 | [EditorBrowsable(EditorBrowsableState.Never)] 61 | public override bool Equals(object obj) 62 | { 63 | return base.Equals(obj); 64 | } 65 | 66 | /// 67 | [EditorBrowsable(EditorBrowsableState.Never)] 68 | public override int GetHashCode() 69 | { 70 | return base.GetHashCode(); 71 | } 72 | 73 | /// 74 | [EditorBrowsable(EditorBrowsableState.Never)] 75 | public new Type GetType() 76 | { 77 | return base.GetType(); 78 | } 79 | #endregion 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/FluentMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using Dapper; 5 | using AA.Dapper.FluentMap.Configuration; 6 | using AA.Dapper.FluentMap.Conventions; 7 | using AA.Dapper.FluentMap.Mapping; 8 | using AA.Dapper.FluentMap.TypeMaps; 9 | 10 | namespace AA.Dapper.FluentMap 11 | { 12 | /// 13 | /// Main entry point for Dapper.FluentMap configuration. 14 | /// 15 | public static class FluentMapper 16 | { 17 | private static readonly FluentMapConfiguration _configuration = new FluentMapConfiguration(); 18 | 19 | /// 20 | /// Gets the dictionary containing the entity mapping per entity type. 21 | /// 22 | public static readonly ConcurrentDictionary EntityMaps = new ConcurrentDictionary(); 23 | 24 | /// 25 | /// Gets the dictionary containing the conventions per entity type. 26 | /// 27 | public static readonly ConcurrentDictionary> TypeConventions = new ConcurrentDictionary>(); 28 | 29 | /// 30 | /// Initializes Dapper.FluentMap with the specified configuration. 31 | /// This is method should be called when the application starts or when the first mapping is needed. 32 | /// 33 | /// A callback containing the configuration of Dapper.FluentMap. 34 | public static void Initialize(Action configure) 35 | { 36 | configure(_configuration); 37 | } 38 | 39 | /// 40 | /// Registers a Dapper type map using fluent mapping for the specified . 41 | /// 42 | /// The type of the entity. 43 | internal static void AddTypeMap() 44 | { 45 | SqlMapper.SetTypeMap(typeof(TEntity), new FluentMapTypeMap()); 46 | } 47 | 48 | /// 49 | /// Registers a Dapper type map using fluent mapping for the specified . 50 | /// 51 | /// The type of the entity. 52 | internal static void AddTypeMap(Type entityType) 53 | { 54 | var instance = (SqlMapper.ITypeMap)Activator.CreateInstance(typeof(FluentMapTypeMap<>).MakeGenericType(entityType)); 55 | SqlMapper.SetTypeMap(entityType, instance); 56 | } 57 | 58 | /// 59 | /// Registers a Dapper type map using conventions for the specified . 60 | /// 61 | /// The type of the entity. 62 | internal static void AddConventionTypeMap() 63 | { 64 | SqlMapper.SetTypeMap(typeof(TEntity), new FluentConventionTypeMap()); 65 | } 66 | 67 | /// 68 | /// Registers a Dapper type map using conventions for the specified . 69 | /// 70 | /// The type of the entity. 71 | internal static void AddConventionTypeMap(Type entityType) 72 | { 73 | var instance = (SqlMapper.ITypeMap)Activator.CreateInstance(typeof(FluentConventionTypeMap<>).MakeGenericType(entityType)); 74 | SqlMapper.SetTypeMap(entityType, instance); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/TypeMaps/FluentTypeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Dapper; 5 | using AA.Dapper.FluentMap.Mapping; 6 | 7 | namespace AA.Dapper.FluentMap.TypeMaps 8 | { 9 | /// 10 | /// Represents a Dapper type mapping strategy which first tries to map the type using a 11 | /// , 12 | /// if that fails, the is used as mapping strategy. 13 | /// 14 | /// The type of the entity. 15 | public class FluentMapTypeMap : MultiTypeMap 16 | { 17 | /// 18 | /// Initializes a new instance of the class 19 | /// which uses the and 20 | /// as mapping strategies. 21 | /// 22 | public FluentMapTypeMap() 23 | : base(new CustomPropertyTypeMap(typeof(TEntity), GetPropertyInfo), new DefaultTypeMap(typeof(TEntity))) 24 | { 25 | } 26 | 27 | private static PropertyInfo GetPropertyInfo(Type type, string columnName) 28 | { 29 | var cacheKey = $"{type.FullName};{columnName}"; 30 | 31 | PropertyInfo info; 32 | if (TypePropertyMapCache.TryGetValue(cacheKey, out info)) 33 | { 34 | return info; 35 | } 36 | 37 | IEntityMap entityMap; 38 | if (FluentMapper.EntityMaps.TryGetValue(type, out entityMap)) 39 | { 40 | var propertyMaps = entityMap.PropertyMaps; 41 | 42 | // Find the mapping for the column name. 43 | var propertyMap = propertyMaps.FirstOrDefault(m => MatchColumnNames(m, columnName)); 44 | 45 | if (propertyMap != null) 46 | { 47 | if (!propertyMap.Ignored) 48 | { 49 | TypePropertyMapCache.TryAdd(cacheKey, propertyMap.PropertyInfo); 50 | return propertyMap.PropertyInfo; 51 | } 52 | #if !NETSTANDARD1_3 53 | else 54 | { 55 | var ignoredPropertyInfo = new IgnoredPropertyInfo(); 56 | TypePropertyMapCache.TryAdd(cacheKey, ignoredPropertyInfo); 57 | return ignoredPropertyInfo; 58 | } 59 | #endif 60 | } 61 | } 62 | 63 | // If we get here, the property was not mapped. 64 | TypePropertyMapCache.TryAdd(cacheKey, null); 65 | return null; 66 | } 67 | 68 | private static bool MatchColumnNames(IPropertyMap map, string columnName) 69 | { 70 | var comparison = StringComparison.Ordinal; 71 | if (!map.CaseSensitive) 72 | { 73 | comparison = StringComparison.OrdinalIgnoreCase; 74 | } 75 | 76 | return string.Equals(map.ColumnName, columnName, comparison); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/TypeMaps/IgnoredPropertyInfo.cs: -------------------------------------------------------------------------------- 1 | #if !NETSTANDARD1_3 2 | using System; 3 | using System.Globalization; 4 | using System.Reflection; 5 | 6 | namespace AA.Dapper.FluentMap.TypeMaps 7 | { 8 | internal class IgnoredPropertyInfo : PropertyInfo 9 | { 10 | public override Type PropertyType => throw new NotImplementedException(); 11 | public override PropertyAttributes Attributes => throw new NotImplementedException(); 12 | public override bool CanRead => throw new NotImplementedException(); 13 | public override bool CanWrite => throw new NotImplementedException(); 14 | public override string Name => throw new NotImplementedException(); 15 | public override Type DeclaringType => throw new NotImplementedException(); 16 | public override ParameterInfo[] GetIndexParameters() => throw new NotImplementedException(); 17 | public override Type ReflectedType => throw new NotImplementedException(); 18 | public override MethodInfo[] GetAccessors(bool nonPublic) => throw new NotImplementedException(); 19 | public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException(); 20 | public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); 21 | public override MethodInfo GetGetMethod(bool nonPublic) => throw new NotImplementedException(); 22 | public override MethodInfo GetSetMethod(bool nonPublic) => throw new NotImplementedException(); 23 | public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); 24 | public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) => throw new NotImplementedException(); 25 | public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) => throw new NotImplementedException(); 26 | } 27 | } 28 | #endif -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/Utils/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AA.Dapper.FluentMap.Utils 4 | { 5 | internal static class DictionaryExtensions 6 | { 7 | internal static void AddOrUpdate(this IDictionary> dict, TKey key, TValue value) 8 | { 9 | if (dict.ContainsKey(key)) 10 | { 11 | dict[key].Add(value); 12 | } 13 | else 14 | { 15 | dict.Add(key, new List { value }); 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AA.Dapper/FluentMap/Utils/ReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | namespace AA.Dapper.FluentMap.Utils 7 | { 8 | /// 9 | /// Provides helper methods for reflection operations. 10 | /// 11 | public static class ReflectionHelper 12 | { 13 | /// 14 | /// Returns the for the specified lamba expression. 15 | /// 16 | /// A lamba expression containing a MemberExpression. 17 | /// A object for the member in the specified lambda expression. 18 | public static MemberInfo GetMemberInfo(LambdaExpression lambda) 19 | { 20 | Expression expr = lambda; 21 | while (true) 22 | { 23 | switch (expr.NodeType) 24 | { 25 | case ExpressionType.Lambda: 26 | expr = ((LambdaExpression)expr).Body; 27 | break; 28 | 29 | case ExpressionType.Convert: 30 | expr = ((UnaryExpression)expr).Operand; 31 | break; 32 | 33 | case ExpressionType.MemberAccess: 34 | var memberExpression = (MemberExpression)expr; 35 | var member = memberExpression.Member; 36 | Type paramType; 37 | 38 | while (memberExpression != null) 39 | { 40 | paramType = memberExpression.Type; 41 | 42 | // Find the member on the base type of the member type 43 | // E.g. EmailAddress.Value 44 | var baseMember = paramType.GetMembers().FirstOrDefault(m => m.Name == member.Name); 45 | if (baseMember != null) 46 | { 47 | // Don't use the base type if it's just the nullable type of the derived type 48 | // or when the same member exists on a different type 49 | // E.g. Nullable -> decimal 50 | // or: SomeType { string Length; } -> string.Length 51 | if (baseMember is PropertyInfo baseProperty && member is PropertyInfo property) 52 | { 53 | if (baseProperty.DeclaringType == property.DeclaringType && 54 | baseProperty.PropertyType != Nullable.GetUnderlyingType(property.PropertyType)) 55 | { 56 | return baseMember; 57 | } 58 | } 59 | else 60 | { 61 | return baseMember; 62 | } 63 | } 64 | 65 | memberExpression = memberExpression.Expression as MemberExpression; 66 | } 67 | 68 | // Make sure we get the property from the derived type. 69 | paramType = lambda.Parameters[0].Type; 70 | return paramType.GetMember(member.Name)[0]; 71 | 72 | default: 73 | return null; 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AA.Dapper/IDapperContext.cs: -------------------------------------------------------------------------------- 1 | using AA.Dapper.Util; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.Text; 6 | 7 | namespace AA.Dapper 8 | { 9 | public interface IDapperContext : IDisposable 10 | { 11 | IDbTransaction dbTransaction { get; } 12 | IDbConnection Connection { get; } 13 | IDbTransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.RepeatableRead); 14 | void Commit(); 15 | void RollBack(); 16 | DataBase DataBase { get; } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AA.Dapper/IDbProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AA.Dapper 9 | { 10 | public interface IDbProvider 11 | { 12 | void Initialize(); 13 | 14 | /// 15 | /// Returns a new connection object to communicate with the database. 16 | /// 17 | /// A new 18 | DbConnection CreateConnection(); 19 | 20 | /// 21 | /// Connection string used to create connections. 22 | /// 23 | string ConnectionString { set; get; } 24 | 25 | DbMetadata Metadata { get; } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AA.Dapper/TimeSpanParseRuleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AA.Dapper 8 | { 9 | /// 10 | /// Attribute to use with public properties that 11 | /// can be set with Quartz configuration. Attribute can be used to advice 12 | /// parsing to use correct type of time span (milliseconds, seconds, minutes, hours) 13 | /// as it may depend on property. 14 | /// 15 | /// Marko Lahma (.NET) 16 | /// 17 | public class TimeSpanParseRuleAttribute : Attribute 18 | { 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The rule. 23 | public TimeSpanParseRuleAttribute(TimeSpanParseRule rule) 24 | { 25 | Rule = rule; 26 | } 27 | 28 | /// 29 | /// Gets the rule. 30 | /// 31 | /// The rule. 32 | public TimeSpanParseRule Rule { get; } 33 | } 34 | 35 | /// 36 | /// Possible parse rules for s. 37 | /// 38 | public enum TimeSpanParseRule 39 | { 40 | /// 41 | /// 42 | /// 43 | Milliseconds = 0, 44 | 45 | /// 46 | /// 47 | /// 48 | Seconds = 1, 49 | 50 | /// 51 | /// 52 | /// 53 | Minutes = 2, 54 | 55 | /// 56 | /// 57 | /// 58 | Hours = 3, 59 | 60 | /// 61 | /// 62 | /// 63 | Days = 3 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AA.Dapper/Util/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace AA.Dapper.Util 10 | { 11 | internal static class Configuration 12 | { 13 | 14 | 15 | internal static NameValueCollection GetSection(string sectionName) 16 | { 17 | try 18 | { 19 | return (NameValueCollection)ConfigurationManager.GetSection(sectionName); 20 | } 21 | catch (Exception e) 22 | { 23 | // log.Warn("could not read configuration using ConfigurationManager.GetSection: " + e.Message); 24 | return null; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AA.Dapper/Util/DataBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using AA.FrameWork.Domain; 7 | using Dapper; 8 | namespace AA.Dapper.Util 9 | { 10 | public class DataBase 11 | { 12 | private IDapperContext dapperContext; 13 | public DataBase(DapperContext dapperContext) 14 | { 15 | this.dapperContext = dapperContext; 16 | } 17 | public int Execute(string sql, object param = null) 18 | { 19 | return dapperContext.Connection.Execute(sql, param, dapperContext.dbTransaction); 20 | } 21 | 22 | public Task ExecuteAsync(string sql, object param = null) 23 | { 24 | return dapperContext.Connection.ExecuteAsync(sql, param, dapperContext.dbTransaction); 25 | } 26 | 27 | public T ExecuteScalar(string sql, object param = null) 28 | { 29 | return dapperContext.Connection.ExecuteScalar(sql, param, dapperContext.dbTransaction); 30 | } 31 | 32 | public Task ExecuteScalarAsync(string sql, object param = null) 33 | { 34 | return dapperContext.Connection.ExecuteScalarAsync(sql, param, dapperContext.dbTransaction); 35 | } 36 | 37 | public IEnumerable Query(string sql, object param = null) 38 | { 39 | return dapperContext.Connection.Query(sql, param, dapperContext.dbTransaction); 40 | } 41 | 42 | public Task> QueryAsync(string sql, object param = null) 43 | { 44 | return dapperContext.Connection.QueryAsync(sql, param, dapperContext.dbTransaction); 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AA.Dapper/Util/DynamicExpression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | 7 | namespace AA.Dapper.Util 8 | { 9 | public static class DynamicWhereExpression 10 | { 11 | 12 | public static Expression> Init() { return f => true; } 13 | 14 | public static Expression> And(this Expression> left, Expression> right) 15 | { 16 | if (left == null) 17 | { 18 | return right; 19 | } 20 | 21 | var invokeExpression = Expression.Invoke(right, left.Parameters.Cast()); 22 | return (Expression.Lambda>(Expression.AndAlso(left.Body, invokeExpression), left.Parameters)); 23 | } 24 | 25 | public static Expression> Or(this Expression> left, Expression> right) 26 | { 27 | if (left == null) 28 | { 29 | return right; 30 | } 31 | 32 | var invokeExpression = Expression.Invoke(right, left.Parameters.Cast()); 33 | return (Expression.Lambda>(Expression.OrElse(left.Body, invokeExpression), left.Parameters)); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AA.Dapper/Util/IDbConnectionManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AA.Dapper.Util 9 | { 10 | /// 11 | /// Manages a collection of IDbProviders, and provides transparent access 12 | /// to their database. 13 | /// 14 | public interface IDbConnectionManager 15 | { 16 | /// 17 | /// Shuts down database connections from the data source with the given name, 18 | /// if applicable for the underlying provider. 19 | /// 20 | void Shutdown(string dataSourceName); 21 | 22 | /// 23 | /// Get a database connection from the data source with the given name. 24 | /// 25 | DbConnection GetConnection(string dataSourceName); 26 | 27 | /// 28 | /// Returns meta data for data source with the given name. 29 | /// 30 | DbMetadata GetDbMetadata(string dataSourceName); 31 | 32 | /// 33 | /// Gets db provider for data source with the given name. 34 | /// 35 | IDbProvider GetDbProvider(string dataSourceName); 36 | 37 | /// 38 | /// Adds a connection provider to data source with the given name. 39 | /// 40 | void AddConnectionProvider(string dataSourceName, IDbProvider provider); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AA.FrameWork.Tests.Unit/AA.FrameWork.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /AA.FrameWork.Tests.Unit/AutoMapper/AutoMapperTest.cs: -------------------------------------------------------------------------------- 1 | using AA.AutoMapper; 2 | using AutoMapper; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Xunit; 7 | using AA.FrameWork.Extensions; 8 | namespace AA.FrameWork.Tests.Unit.AutoMapper 9 | { 10 | 11 | public class AutoMapperTest 12 | { 13 | private void Init() 14 | { 15 | var mapperConfig = new WebMapperConfigurations(); 16 | AutoMapperConfiguration.Init(new List> { mapperConfig.GetConfiguration() }); 17 | ObjectMapping.ObjectMapManager.ObjectMapper = new AutoMapperObjectMapper(); 18 | } 19 | 20 | [Fact] 21 | public void TestMap() 22 | { 23 | //init 24 | Init(); 25 | UserVm userVm = new UserVm { Id = 1, Name = "成天" ,Remark="微信公众号:dotNet知音"}; 26 | var userDto = userVm.MapTo(); 27 | //var userDto2 = userVm.MapTo(); 28 | 29 | } 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AA.FrameWork.Tests.Unit/AutoMapper/UserVm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace AA.FrameWork.Tests.Unit.AutoMapper 6 | { 7 | //viewModel 8 | public class UserVm 9 | { 10 | public int Id { get; set; } 11 | public string Name { get; set; } 12 | public string Remark { get; set; } 13 | } 14 | 15 | //dto 16 | public class UserInput 17 | { 18 | public int Id { get; set; } 19 | public string Name { get; set; } 20 | public string Remark { get; set; } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /AA.FrameWork.Tests.Unit/AutoMapper/WebMapperConfigurations.cs: -------------------------------------------------------------------------------- 1 | using AA.AutoMapper; 2 | using AutoMapper; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace AA.FrameWork.Tests.Unit.AutoMapper 8 | { 9 | public class WebMapperConfigurations : IMapperConfiguration 10 | { 11 | public int Order { get { return 0; } } 12 | 13 | public Action GetConfiguration() 14 | { 15 | Action action = cfg => 16 | { 17 | cfg.CreateMap(); 18 | }; 19 | return action; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AA.FrameWork.Tests.Unit/Log4Net/log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |