Commit e2efb556 by 刘军

检测报告API

parents
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
*.bin
*.obj
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
**/wwwroot/lib/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
/G.MES.API/Logs
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--<TargetFramework>netstandard2.0</TargetFramework>-->
<!--<TargetFramework>net40</TargetFramework>-->
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
<Version>3.8.0</Version>
<AssemblyVersion>3.8.0.0</AssemblyVersion>
<FileVersion>3.8.0.0</FileVersion>
<Description>A lightweight and high-performance Object/Relational Mapping(ORM) library.</Description>
<PackageId>Chloe.Extension</PackageId>
<Product>Chloe.ORM</Product>
<Authors>Shuxin Qin</Authors>
<Copyright>Copyright 2016-2019.</Copyright>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>NETFX</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
</ItemGroup>
</Project>
using Chloe.Extension;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Chloe
{
/// <summary>
/// 暂存 CURD 操作,最后调用 ExecuteActions 执行。
/// </summary>
public class DbActionBag
{
List<Func<int>> _actions = new List<Func<int>>();
IDbContext _dbContext;
public DbActionBag(IDbContext dbContext)
{
PublicHelper.CheckNull(dbContext);
this._dbContext = dbContext;
}
public void PushInsert<T>(T entity)
{
this._actions.Add(() =>
{
this._dbContext.Insert(entity);
return 1;
});
}
public void PushInsert<T>(Expression<Func<T>> body)
{
this._actions.Add(() =>
{
this._dbContext.Insert(body);
return 1;
});
}
public void PushUpdate<T>(T entity)
{
this._actions.Add(() =>
{
return this._dbContext.Update(entity);
});
}
public void PushUpdate<T>(Expression<Func<T, bool>> condition, Expression<Func<T, T>> body)
{
this._actions.Add(() =>
{
return this._dbContext.Update(condition, body);
});
}
public void PushDelete<T>(T entity)
{
this._actions.Add(() =>
{
return this._dbContext.Delete(entity);
});
}
public void PushDelete<T>(Expression<Func<T, bool>> condition)
{
this._actions.Add(() =>
{
return this._dbContext.Delete(condition);
});
}
public void Push(Func<IDbContext, int> action)
{
this._actions.Add(() =>
{
return action(this._dbContext);
});
}
public int ExecuteActions()
{
if (this._actions.Count == 0)
return 0;
int affected = 0;
if (this._dbContext.Session.IsInTransaction == true)
{
affected = this.InnerExecuteActions();
this._actions.Clear();
return affected;
}
affected = this._dbContext.DoWithTransaction(() =>
{
return this.InnerExecuteActions();
}, IsolationLevel.ReadCommitted);
this._actions.Clear();
return affected;
}
int InnerExecuteActions()
{
int affected = 0;
for (int i = 0; i < this._actions.Count; i++)
{
Func<int> action = this._actions[i];
affected += action();
}
return affected;
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Chloe.Extension;
namespace Chloe
{
public static class DbContextAsyncExtension
{
public static Task<TEntity> QueryByKeyAsync<TEntity>(this IDbContext dbContext, object key, bool tracking = false)
{
return Utils.MakeTask(() => dbContext.QueryByKey<TEntity>(key, tracking));
}
public static Task<List<T>> SqlQueryAsync<T>(this IDbContext dbContext, string sql, params DbParam[] parameters)
{
return Utils.MakeTask(() => dbContext.SqlQuery<T>(sql, parameters).ToList());
}
public static Task<List<T>> SqlQueryAsync<T>(this IDbContext dbContext, string sql, CommandType cmdType, params DbParam[] parameters)
{
return Utils.MakeTask(() => dbContext.SqlQuery<T>(sql, cmdType, parameters).ToList());
}
public static Task<TEntity> InsertAsync<TEntity>(this IDbContext dbContext, TEntity entity)
{
return Utils.MakeTask(() => dbContext.Insert<TEntity>(entity));
}
public static Task<object> InsertAsync<TEntity>(this IDbContext dbContext, Expression<Func<TEntity>> body)
{
return Utils.MakeTask(() => dbContext.Insert<TEntity>(body));
}
public static Task<int> UpdateAsync<TEntity>(this IDbContext dbContext, TEntity entity)
{
return Utils.MakeTask(() => dbContext.Update<TEntity>(entity));
}
public static Task<int> UpdateAsync<TEntity>(this IDbContext dbContext, Expression<Func<TEntity, bool>> condition, Expression<Func<TEntity, TEntity>> body)
{
return Utils.MakeTask(() => dbContext.Update<TEntity>(condition, body));
}
public static Task<int> DeleteAsync<TEntity>(this IDbContext dbContext, TEntity entity)
{
return Utils.MakeTask(() => dbContext.Delete<TEntity>(entity));
}
public static Task<int> DeleteAsync<TEntity>(this IDbContext dbContext, Expression<Func<TEntity, bool>> condition)
{
return Utils.MakeTask(() => dbContext.Delete<TEntity>(condition));
}
public static Task<int> DeleteByKeyAsync<TEntity>(this IDbContext dbContext, object key)
{
return Utils.MakeTask(() => dbContext.DeleteByKey<TEntity>(key));
}
}
}
using Chloe.Descriptors;
using Chloe.Exceptions;
using Chloe.Extension;
using Chloe.Infrastructure;
using Chloe.InternalExtensions;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace Chloe
{
public static partial class DbContextExtension
{
public static IQuery<T> Query<T>(this IDbContext dbContext, Expression<Func<T, bool>> predicate)
{
return dbContext.Query<T>().Where(predicate);
}
/// <summary>
/// dbContext.Update&lt;User&gt;(user, a =&gt; a.Id == 1)
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="dbContext"></param>
/// <param name="entity"></param>
/// <param name="condition"></param>
/// <returns></returns>
public static int Update<TEntity>(this IDbContext dbContext, TEntity entity, Expression<Func<TEntity, bool>> condition)
{
PublicHelper.CheckNull(dbContext);
PublicHelper.CheckNull(entity);
PublicHelper.CheckNull(condition);
Type entityType = typeof(TEntity);
TypeDescriptor typeDescriptor = EntityTypeContainer.GetDescriptor(entityType);
List<MemberBinding> bindings = new List<MemberBinding>();
ConstantExpression entityConstantExp = Expression.Constant(entity);
foreach (PropertyDescriptor propertyDescriptor in typeDescriptor.PropertyDescriptors)
{
if (propertyDescriptor.IsPrimaryKey || propertyDescriptor.IsAutoIncrement)
{
continue;
}
Expression entityMemberAccess = Expression.MakeMemberAccess(entityConstantExp, propertyDescriptor.Property);
MemberAssignment bind = Expression.Bind(propertyDescriptor.Property, entityMemberAccess);
bindings.Add(bind);
}
return UpdateOnly(dbContext, condition, bindings);
}
/// <summary>
/// dbContext.UpdateOnly&lt;User&gt;(user, a =&gt; new { a.Name, a.Age })
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="dbContext"></param>
/// <param name="entity"></param>
/// <param name="fields"></param>
/// <returns></returns>
public static int UpdateOnly<TEntity>(this IDbContext dbContext, TEntity entity, Expression<Func<TEntity, object>> fields)
{
PublicHelper.CheckNull(fields);
List<string> fieldList = FieldsResolver.Resolve(fields);
return dbContext.UpdateOnly(entity, fieldList.ToArray());
}
/// <summary>
/// dbContext.UpdateOnly&lt;User&gt;(user, "Name,Age", "NickName")
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="dbContext"></param>
/// <param name="entity"></param>
/// <param name="fields"></param>
/// <returns></returns>
public static int UpdateOnly<TEntity>(this IDbContext dbContext, TEntity entity, params string[] fields)
{
PublicHelper.CheckNull(dbContext);
PublicHelper.CheckNull(entity);
PublicHelper.CheckNull(fields);
/* 支持 context.UpdateOnly<User>(user, "Name,Age", "NickName"); */
fields = fields.SelectMany(a => a.Split(',')).Select(a => a.Trim()).ToArray();
if (fields.Length == 0)
throw new ArgumentException("fields");
Type entityType = typeof(TEntity);
TypeDescriptor typeDescriptor = EntityTypeContainer.GetDescriptor(entityType);
List<MemberBinding> bindings = new List<MemberBinding>();
ConstantExpression entityConstantExp = Expression.Constant(entity);
foreach (string field in fields)
{
MemberInfo memberInfo = entityType.GetMember(field)[0];
var propertyDescriptor = typeDescriptor.TryGetPropertyDescriptor(memberInfo);
if (propertyDescriptor == null)
throw new ArgumentException(string.Format("Could not find the member '{0}' from entity.", propertyDescriptor.Column.Name));
Expression entityMemberAccess = Expression.MakeMemberAccess(entityConstantExp, memberInfo);
MemberAssignment bind = Expression.Bind(memberInfo, entityMemberAccess);
bindings.Add(bind);
}
ParameterExpression parameter = Expression.Parameter(entityType, "a");
Expression conditionBody = null;
foreach (PropertyDescriptor primaryKey in typeDescriptor.PrimaryKeys)
{
Expression propOrField = Expression.PropertyOrField(parameter, primaryKey.Property.Name);
Expression keyValue = Expression.MakeMemberAccess(entityConstantExp, primaryKey.Property);
Expression e = Expression.Equal(propOrField, keyValue);
conditionBody = conditionBody == null ? e : Expression.AndAlso(conditionBody, e);
}
Expression<Func<TEntity, bool>> condition = Expression.Lambda<Func<TEntity, bool>>(conditionBody, parameter);
return UpdateOnly(dbContext, condition, bindings);
}
static int UpdateOnly<TEntity>(this IDbContext dbContext, Expression<Func<TEntity, bool>> condition, List<MemberBinding> bindings)
{
Type entityType = typeof(TEntity);
NewExpression newExp = Expression.New(entityType);
ParameterExpression parameter = Expression.Parameter(entityType, "a");
Expression lambdaBody = Expression.MemberInit(newExp, bindings);
Expression<Func<TEntity, TEntity>> lambda = Expression.Lambda<Func<TEntity, TEntity>>(lambdaBody, parameter);
return dbContext.Update(condition, lambda);
}
public static void BeginTransaction(this IDbContext dbContext)
{
dbContext.Session.BeginTransaction();
}
public static void BeginTransaction(this IDbContext dbContext, IsolationLevel il)
{
dbContext.Session.BeginTransaction(il);
}
public static void CommitTransaction(this IDbContext dbContext)
{
dbContext.Session.CommitTransaction();
}
public static void RollbackTransaction(this IDbContext dbContext)
{
dbContext.Session.RollbackTransaction();
}
public static void DoWithTransaction(this IDbContext dbContext, Action action)
{
dbContext.UseTransaction(action);
}
public static void DoWithTransaction(this IDbContext dbContext, Action action, IsolationLevel il)
{
dbContext.UseTransaction(action, il);
}
public static T DoWithTransaction<T>(this IDbContext dbContext, Func<T> action)
{
dbContext.Session.BeginTransaction();
return ExecuteAction(dbContext, action);
}
public static T DoWithTransaction<T>(this IDbContext dbContext, Func<T> action, IsolationLevel il)
{
dbContext.Session.BeginTransaction(il);
return ExecuteAction(dbContext, action);
}
static void ExecuteAction(IDbContext dbContext, Action action)
{
try
{
action();
dbContext.Session.CommitTransaction();
}
catch
{
if (dbContext.Session.IsInTransaction)
dbContext.Session.RollbackTransaction();
throw;
}
}
static T ExecuteAction<T>(IDbContext dbContext, Func<T> action)
{
try
{
T ret = action();
dbContext.Session.CommitTransaction();
return ret;
}
catch
{
if (dbContext.Session.IsInTransaction)
dbContext.Session.RollbackTransaction();
throw;
}
}
public static DbActionBag CreateActionBag(this IDbContext dbContext)
{
DbActionBag bag = new DbActionBag(dbContext);
return bag;
}
}
}
using Chloe.Descriptors;
using Chloe.Exceptions;
using Chloe.Extension;
using Chloe.Infrastructure;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Chloe
{
#if NETCORE
public static partial class DbContextExtension
{
/// <summary>
/// int id = 1;
/// dbContext.FormatSqlQuery&lt;User&gt;($"select Id,Name from Users where Id={id}");
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbContext"></param>
/// <param name="sql"></param>
/// <returns></returns>
public static IEnumerable<T> FormatSqlQuery<T>(this IDbContext dbContext, FormattableString sql)
{
/*
* Usage:
* int id = 1;
* dbContext.FormatSqlQuery<User>($"select Id,Name from Users where Id={id}").ToList();
*/
(string Sql, DbParam[] Parameters) r = BuildSqlAndParameters(dbContext, sql);
return dbContext.SqlQuery<T>(r.Sql, r.Parameters);
}
public static IEnumerable<T> FormatSqlQuery<T>(this IDbContext dbContext, FormattableString sql, CommandType cmdType)
{
/*
* Usage:
* int id = 1;
* dbContext.FormatSqlQuery<User>($"select Id,Name from Users where Id={id}").ToList();
*/
(string Sql, DbParam[] Parameters) r = BuildSqlAndParameters(dbContext, sql);
return dbContext.SqlQuery<T>(r.Sql, cmdType, r.Parameters);
}
public static Task<List<T>> FormatSqlQueryAsync<T>(this IDbContext dbContext, FormattableString sql)
{
return Utils.MakeTask(() => DbContextExtension.FormatSqlQuery<T>(dbContext, sql).ToList());
}
public static Task<List<T>> FormatSqlQueryAsync<T>(this IDbContext dbContext, FormattableString sql, CommandType cmdType)
{
return Utils.MakeTask(() => DbContextExtension.FormatSqlQuery<T>(dbContext, sql, cmdType).ToList());
}
static (string Sql, DbParam[] Parameters) BuildSqlAndParameters(IDbContext dbContext, FormattableString sql)
{
List<string> formatArgs = new List<string>(sql.ArgumentCount);
List<DbParam> parameters = new List<DbParam>(sql.ArgumentCount);
IDatabaseProvider databaseProvider = ((DbContext)dbContext).DatabaseProvider;
string parameterPrefix = "P_";
foreach (var arg in sql.GetArguments())
{
object paramValue = arg;
if (paramValue == null || paramValue == DBNull.Value)
{
formatArgs.Add("NULL");
continue;
}
Type paramType = arg.GetType();
if (paramType.IsEnum)
{
paramType = Enum.GetUnderlyingType(paramType);
if (paramValue != null)
paramValue = Convert.ChangeType(paramValue, paramType);
}
DbParam p;
p = parameters.Where(a => PublicHelper.AreEqual(a.Value, paramValue)).FirstOrDefault();
if (p != null)
{
formatArgs.Add(p.Name);
continue;
}
string paramName = databaseProvider.CreateParameterName(parameterPrefix + parameters.Count.ToString());
p = DbParam.Create(paramName, paramValue, paramType);
parameters.Add(p);
formatArgs.Add(p.Name);
}
string runSql = string.Format(sql.Format, formatArgs.ToArray());
return (runSql, parameters.ToArray());
}
}
#endif
}
using System.Data;
namespace Chloe.Extension
{
static class DbHelper
{
public static DataTable FillDataTable(IDataReader reader)
{
DataTable dt = new DataTable();
int fieldCount = reader.FieldCount;
for (int i = 0; i < fieldCount; i++)
{
DataColumn dc = new DataColumn(reader.GetName(i), reader.GetFieldType(i));
dt.Columns.Add(dc);
}
while (reader.Read())
{
DataRow dr = dt.NewRow();
for (int i = 0; i < fieldCount; i++)
{
dr[i] = reader[i];
}
dt.Rows.Add(dr);
}
return dt;
}
public static DataSet FillDataSet(IDataReader reader)
{
DataSet ds = new DataSet();
var dt = FillDataTable(reader);
ds.Tables.Add(dt);
while (reader.NextResult())
{
dt = FillDataTable(reader);
ds.Tables.Add(dt);
}
return ds;
}
}
}
using Chloe.Extension;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace Chloe
{
public static class DbSessionExtension
{
/// <summary>
/// dbSession.ExecuteDataTable("select Age from Users where Id=@Id", new { Id = 1 })
/// </summary>
/// <param name="dbSession"></param>
/// <param name="cmdText"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static DataTable ExecuteDataTable(this IDbSession dbSession, string cmdText, object parameter)
{
return ExecuteDataTable(dbSession, cmdText, Utils.BuildParams(dbSession.DbContext, parameter));
}
public static DataTable ExecuteDataTable(this IDbSession dbSession, string cmdText, params DbParam[] parameters)
{
using (var reader = dbSession.ExecuteReader(cmdText, parameters))
{
DataTable dt = DbHelper.FillDataTable(reader);
return dt;
}
}
/// <summary>
/// dbSession.ExecuteDataTable("select Age from Users where Id=@Id", CommandType.Text, new { Id = 1 })
/// </summary>
/// <param name="dbSession"></param>
/// <param name="cmdText"></param>
/// <param name="cmdType"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static DataTable ExecuteDataTable(this IDbSession dbSession, string cmdText, CommandType cmdType, object parameter)
{
return ExecuteDataTable(dbSession, cmdText, cmdType, Utils.BuildParams(dbSession.DbContext, parameter));
}
public static DataTable ExecuteDataTable(this IDbSession dbSession, string cmdText, CommandType cmdType, params DbParam[] parameters)
{
using (var reader = dbSession.ExecuteReader(cmdText, cmdType, parameters))
{
DataTable dt = DbHelper.FillDataTable(reader);
return dt;
}
}
/// <summary>
/// dbSession.ExecuteDataSet("select Age from Users where Id=@Id", new { Id = 1 })
/// </summary>
/// <param name="dbSession"></param>
/// <param name="cmdText"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static DataSet ExecuteDataSet(this IDbSession dbSession, string cmdText, object parameter)
{
return ExecuteDataSet(dbSession, cmdText, Utils.BuildParams(dbSession.DbContext, parameter));
}
public static DataSet ExecuteDataSet(this IDbSession dbSession, string cmdText, params DbParam[] parameters)
{
using (var reader = dbSession.ExecuteReader(cmdText, parameters))
{
DataSet ds = DbHelper.FillDataSet(reader);
return ds;
}
}
/// <summary>
/// dbSession.ExecuteDataSet("select Age from Users where Id=@Id", CommandType.Text, new { Id = 1 })
/// </summary>
/// <param name="dbSession"></param>
/// <param name="cmdText"></param>
/// <param name="cmdType"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static DataSet ExecuteDataSet(this IDbSession dbSession, string cmdText, CommandType cmdType, object parameter)
{
return ExecuteDataSet(dbSession, cmdText, cmdType, Utils.BuildParams(dbSession.DbContext, parameter));
}
public static DataSet ExecuteDataSet(this IDbSession dbSession, string cmdText, CommandType cmdType, params DbParam[] parameters)
{
using (var reader = dbSession.ExecuteReader(cmdText, cmdType, parameters))
{
DataSet ds = DbHelper.FillDataSet(reader);
return ds;
}
}
}
}
using Chloe.Descriptors;
using Chloe.Extensions;
using Chloe.Infrastructure;
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Chloe.Extension
{
class FieldsResolver
{
/// <summary>
///
/// </summary>
/// <param name="fieldsLambdaExpression">a => new { a.Name, a.Age } or a => new object[] { a.Name, a.Age }</param>
/// <returns></returns>
public static List<string> Resolve(LambdaExpression fieldsLambdaExpression)
{
ParameterExpression parameterExpression = fieldsLambdaExpression.Parameters[0];
var body = ExpressionExtension.StripConvert(fieldsLambdaExpression.Body);
ReadOnlyCollection<Expression> fieldExps = null;
NewExpression newExpression = body as NewExpression;
if (newExpression != null && newExpression.Type.IsAnonymousType())
{
fieldExps = newExpression.Arguments;
}
else
{
NewArrayExpression newArrayExpression = body as NewArrayExpression;
if (newArrayExpression == null)
throw new NotSupportedException(fieldsLambdaExpression.ToString());
fieldExps = newArrayExpression.Expressions;
}
Type entityType = parameterExpression.Type;
TypeDescriptor typeDescriptor = EntityTypeContainer.GetDescriptor(entityType);
List<string> fields = new List<string>(fieldExps.Count);
foreach (var item in fieldExps)
{
MemberExpression memberExp = ExpressionExtension.StripConvert(item) as MemberExpression;
if (memberExp == null)
throw new NotSupportedException(item.ToString());
if (memberExp.Expression != parameterExpression)
throw new NotSupportedException(item.ToString());
fields.Add(memberExp.Member.Name);
}
return fields;
}
}
}
using Chloe.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace Chloe.Extension
{
class ParameterTwoExpressionReplacer : ExpressionVisitor
{
LambdaExpression _lambda;
object _replaceObj;
Expression _expToReplace = null;
ParameterTwoExpressionReplacer(LambdaExpression lambda, object replaceObj)
{
this._lambda = lambda;
this._replaceObj = replaceObj;
}
public static LambdaExpression Replace(LambdaExpression lambda, object replaceObj)
{
LambdaExpression ret = new ParameterTwoExpressionReplacer(lambda, replaceObj).Replace();
return ret;
}
LambdaExpression Replace()
{
Expression lambdaBody = this._lambda.Body;
Expression newBody = this.Visit(lambdaBody);
ParameterExpression firstParameterExp = this._lambda.Parameters[0];
Type delegateType = typeof(Func<,>).MakeGenericType(firstParameterExp.Type, typeof(bool));
LambdaExpression newLambda = Expression.Lambda(delegateType, newBody, firstParameterExp);
return newLambda;
}
protected override Expression VisitParameter(ParameterExpression parameter)
{
Expression ret = parameter;
if (parameter == this._lambda.Parameters[1])
{
if (this._expToReplace == null)
this._expToReplace = ExpressionExtension.MakeWrapperAccess(this._replaceObj, parameter.Type);
ret = this._expToReplace;
}
return ret;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Chloe.Extension;
namespace Chloe
{
public static class QueryAsyncExtension
{
public static Task<T> FirstAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.First);
}
public static Task<T> FirstAsync<T>(this IQuery<T> q, Expression<Func<T, bool>> predicate)
{
return q.Where(predicate).FirstAsync();
}
public static Task<T> FirstOrDefaultAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.FirstOrDefault);
}
public static Task<T> FirstOrDefaultAsync<T>(this IQuery<T> q, Expression<Func<T, bool>> predicate)
{
return q.Where(predicate).FirstOrDefaultAsync();
}
public static Task<List<T>> ToListAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.ToList);
}
public static Task<bool> AnyAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.Any);
}
public static Task<bool> AnyAsync<T>(this IQuery<T> q, Expression<Func<T, bool>> predicate)
{
return q.Where(predicate).AnyAsync();
}
public static Task<int> CountAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.Count);
}
public static Task<long> LongCountAsync<T>(this IQuery<T> q)
{
return Utils.MakeTask(q.LongCount);
}
public static Task<TResult> MaxAsync<T, TResult>(this IQuery<T> q, Expression<Func<T, TResult>> selector)
{
return Utils.MakeTask(() => q.Max(selector));
}
public static Task<TResult> MinAsync<T, TResult>(this IQuery<T> q, Expression<Func<T, TResult>> selector)
{
return Utils.MakeTask(() => q.Min(selector));
}
public static Task<int> SumAsync<T>(this IQuery<T> q, Expression<Func<T, int>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<int?> SumAsync<T>(this IQuery<T> q, Expression<Func<T, int?>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<long> SumAsync<T>(this IQuery<T> q, Expression<Func<T, long>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<long?> SumAsync<T>(this IQuery<T> q, Expression<Func<T, long?>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<decimal> SumAsync<T>(this IQuery<T> q, Expression<Func<T, decimal>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<decimal?> SumAsync<T>(this IQuery<T> q, Expression<Func<T, decimal?>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<double> SumAsync<T>(this IQuery<T> q, Expression<Func<T, double>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<double?> SumAsync<T>(this IQuery<T> q, Expression<Func<T, double?>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<float> SumAsync<T>(this IQuery<T> q, Expression<Func<T, float>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<float?> SumAsync<T>(this IQuery<T> q, Expression<Func<T, float?>> selector)
{
return Utils.MakeTask(() => q.Sum(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, int>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, int?>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, long>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, long?>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<decimal?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, decimal>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<decimal?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, decimal?>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, double>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<double?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, double?>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<float?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, float>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
public static Task<float?> AverageAsync<T>(this IQuery<T> q, Expression<Func<T, float?>> selector)
{
return Utils.MakeTask(() => q.Average(selector));
}
}
}
using Chloe.Infrastructure;
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Chloe.Extension
{
static class Utils
{
public static Task<T> MakeTask<T>(Func<T> func)
{
var task = new Task<T>(func);
task.Start();
return task;
}
public static DbParam[] BuildParams(IDbContext dbContext, object parameter)
{
if (parameter == null)
return new DbParam[0];
if (parameter is IEnumerable<DbParam>)
{
return ((IEnumerable<DbParam>)parameter).ToArray();
}
IDatabaseProvider databaseProvider = ((DbContext)dbContext).DatabaseProvider;
List<DbParam> parameters = new List<DbParam>();
Type parameterType = parameter.GetType();
var props = parameterType.GetProperties();
foreach (var prop in props)
{
if (prop.GetGetMethod() == null)
{
continue;
}
object value = ReflectionExtension.GetMemberValue(prop, parameter);
string paramName = databaseProvider.CreateParameterName(prop.Name);
DbParam p = new DbParam(paramName, value, prop.PropertyType);
parameters.Add(p);
}
return parameters.ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer.Annotations
{
/// <summary>
/// 标识字段为 timestamp 类型
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class TimestampAttribute : Attribute
{
public TimestampAttribute()
{
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--<TargetFramework>netstandard2.0</TargetFramework>-->
<!--<TargetFramework>net40</TargetFramework>-->
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
<Version>3.9.0</Version>
<AssemblyVersion>3.9.0.0</AssemblyVersion>
<FileVersion>3.9.0.0</FileVersion>
<Description>A lightweight and high-performance Object/Relational Mapping(ORM) library.</Description>
<PackageId>Chloe.SqlServer</PackageId>
<Product>Chloe.ORM</Product>
<Authors>Shuxin Qin</Authors>
<Copyright>Copyright 2016-2019.</Copyright>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>NETFX</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
</ItemGroup>
</Project>
using Chloe.Core.Visitors;
using Chloe.Infrastructure;
using Chloe.Query;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
class DatabaseProvider : IDatabaseProvider
{
IDbConnectionFactory _dbConnectionFactory;
MsSqlContext _msSqlContext;
public string DatabaseType { get { return "SqlServer"; } }
public DatabaseProvider(IDbConnectionFactory dbConnectionFactory, MsSqlContext msSqlContext)
{
this._dbConnectionFactory = dbConnectionFactory;
this._msSqlContext = msSqlContext;
}
public IDbConnection CreateConnection()
{
return this._dbConnectionFactory.CreateConnection();
}
public IDbExpressionTranslator CreateDbExpressionTranslator()
{
if (this._msSqlContext.PagingMode == PagingMode.ROW_NUMBER)
{
return DbExpressionTranslator.Instance;
}
else if (this._msSqlContext.PagingMode == PagingMode.OFFSET_FETCH)
{
return DbExpressionTranslator_OffsetFetch.Instance;
}
throw new NotSupportedException();
}
public string CreateParameterName(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
if (name[0] == UtilConstants.ParameterNamePlaceholer[0])
{
return name;
}
return UtilConstants.ParameterNamePlaceholer + name;
}
}
}
using Chloe.Core;
using Chloe.DbExpressions;
using Chloe.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chloe.SqlServer
{
class DbExpressionTranslator : IDbExpressionTranslator
{
public static readonly DbExpressionTranslator Instance = new DbExpressionTranslator();
public virtual string Translate(DbExpression expression, out List<DbParam> parameters)
{
SqlGenerator generator = this.CreateSqlGenerator();
expression = EvaluableDbExpressionTransformer.Transform(expression);
expression.Accept(generator);
parameters = generator.Parameters;
string sql = generator.SqlBuilder.ToSql();
return sql;
}
public virtual SqlGenerator CreateSqlGenerator()
{
return SqlGenerator.CreateInstance();
}
}
class DbExpressionTranslator_OffsetFetch : DbExpressionTranslator
{
public static readonly new DbExpressionTranslator_OffsetFetch Instance = new DbExpressionTranslator_OffsetFetch();
public override SqlGenerator CreateSqlGenerator()
{
return new SqlGenerator_OffsetFetch();
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
class DbParamCollection
{
/* 以参数值为 key,DbParam 或 List<DbParam> 为 value */
Dictionary<object, object> _dbParams = new Dictionary<object, object>();
public int Count { get; private set; }
public DbParam Find(object value, Type paramType, DbType? dbType)
{
object dicVal;
if (!this._dbParams.TryGetValue(value, out dicVal))
return null;
DbParam dbParam = dicVal as DbParam;
if (dbParam != null)
{
if (value == DBNull.Value)
{
if (dbParam.Type == paramType)
return dbParam;
}
else if (dbParam.DbType == dbType)
{
return dbParam;
}
return null;
}
List<DbParam> dbParamList = dicVal as List<DbParam>;
if (value == DBNull.Value)
{
return dbParamList.Find(a => a.Type == paramType);
}
else
{
return dbParamList.Find(a => a.DbType == dbType);
}
}
public void Add(DbParam param)
{
object value = param.Value;
object dicVal;
if (!this._dbParams.TryGetValue(value, out dicVal))
{
this._dbParams.Add(value, param);
this.Count++;
return;
}
DbParam dbParam = dicVal as DbParam;
if (dbParam != null)
{
List<DbParam> dbParamList = new List<DbParam>(2) { dbParam, param };
this._dbParams[value] = dbParamList;
this.Count++;
}
else
{
List<DbParam> dbParamList = dicVal as List<DbParam>;
dbParamList.Add(param);
this.Count++;
}
}
public List<DbParam> ToParameterList()
{
List<DbParam> ret = new List<DbParam>(this.Count);
foreach (object dicVal in this._dbParams.Values)
{
DbParam dbParam = dicVal as DbParam;
if (dbParam != null)
{
ret.Add(dbParam);
}
else
{
List<DbParam> dbParamList = dicVal as List<DbParam>;
for (int i = 0; i < dbParamList.Count; i++)
{
ret.Add(dbParamList[i]);
}
}
}
return ret;
}
}
}
using Chloe.DbExpressions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
class DbValueExpressionTransformer : DbExpressionVisitor
{
static DbValueExpressionTransformer _transformer = new DbValueExpressionTransformer();
public static DbExpression Transform(DbExpression exp)
{
return exp.Accept(_transformer);
}
DbExpression ConvertDbBooleanExpression(DbExpression exp)
{
DbCaseWhenExpression caseWhenExpression = SqlGenerator.ConstructReturnCSharpBooleanCaseWhenExpression(exp);
return caseWhenExpression;
}
public override DbExpression Visit(DbEqualExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbNotEqualExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbNotExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbBitAndExpression exp)
{
return exp;
}
public override DbExpression Visit(DbAndExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbBitOrExpression exp)
{
return exp;
}
public override DbExpression Visit(DbOrExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbConvertExpression exp)
{
return exp;
}
// +
public override DbExpression Visit(DbAddExpression exp)
{
return exp;
}
// -
public override DbExpression Visit(DbSubtractExpression exp)
{
return exp;
}
// *
public override DbExpression Visit(DbMultiplyExpression exp)
{
return exp;
}
// /
public override DbExpression Visit(DbDivideExpression exp)
{
return exp;
}
// %
public override DbExpression Visit(DbModuloExpression exp)
{
return exp;
}
public override DbExpression Visit(DbNegateExpression exp)
{
return exp;
}
// <
public override DbExpression Visit(DbLessThanExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
// <=
public override DbExpression Visit(DbLessThanOrEqualExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
// >
public override DbExpression Visit(DbGreaterThanExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
// >=
public override DbExpression Visit(DbGreaterThanOrEqualExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
public override DbExpression Visit(DbConstantExpression exp)
{
return exp;
}
public override DbExpression Visit(DbCoalesceExpression exp)
{
return exp;
}
public override DbExpression Visit(DbCaseWhenExpression exp)
{
return exp;
}
public override DbExpression Visit(DbTableExpression exp)
{
return exp;
}
public override DbExpression Visit(DbColumnAccessExpression exp)
{
return exp;
}
public override DbExpression Visit(DbMemberExpression exp)
{
return exp;
}
public override DbExpression Visit(DbParameterExpression exp)
{
return exp;
}
public override DbExpression Visit(DbSubQueryExpression exp)
{
return exp;
}
public override DbExpression Visit(DbSqlQueryExpression exp)
{
return exp;
}
public override DbExpression Visit(DbMethodCallExpression exp)
{
if (exp.Type == UtilConstants.TypeOfBoolean || exp.Type == UtilConstants.TypeOfBoolean_Nullable)
return this.ConvertDbBooleanExpression(exp);
else
return exp;
}
public override DbExpression Visit(DbFromTableExpression exp)
{
return exp;
}
public override DbExpression Visit(DbJoinTableExpression exp)
{
return exp;
}
public override DbExpression Visit(DbAggregateExpression exp)
{
return exp;
}
public override DbExpression Visit(DbInsertExpression exp)
{
return exp;
}
public override DbExpression Visit(DbUpdateExpression exp)
{
return exp;
}
public override DbExpression Visit(DbDeleteExpression exp)
{
return exp;
}
public override DbExpression Visit(DbExistsExpression exp)
{
return this.ConvertDbBooleanExpression(exp);
}
}
}
using Chloe.Infrastructure;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
public class DefaultDbConnectionFactory : IDbConnectionFactory
{
string _connString;
public DefaultDbConnectionFactory(string connString)
{
PublicHelper.CheckNull(connString, "connString");
this._connString = connString;
}
public IDbConnection CreateConnection()
{
SqlConnection conn = new SqlConnection(this._connString);
return conn;
}
}
}
using Chloe.Descriptors;
using Chloe.Entity;
using Chloe.SqlServer.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
public static class EntityPropertyBuilderExtension
{
/// <summary>
/// 标识字段为 timestamp 类型
/// </summary>
/// <typeparam name="TProperty"></typeparam>
/// <param name="entityPropertyBuilder"></param>
/// <returns></returns>
public static IEntityPropertyBuilder<TProperty> IsTimestamp<TProperty>(this IEntityPropertyBuilder<TProperty> entityPropertyBuilder)
{
return entityPropertyBuilder.HasAnnotation(new TimestampAttribute());
}
/// <summary>
/// 标识字段为 timestamp 类型
/// </summary>
/// <param name="entityPropertyBuilder"></param>
/// <returns></returns>
public static IEntityPropertyBuilder IsTimestamp(this IEntityPropertyBuilder entityPropertyBuilder)
{
return entityPropertyBuilder.HasAnnotation(new TimestampAttribute());
}
}
public static class PropertyDescriptorExtension
{
/// <summary>
/// 判断字段是否为 timestamp 类型
/// </summary>
/// <param name="propertyDescriptor"></param>
/// <returns></returns>
public static bool IsTimestamp(this PropertyDescriptor propertyDescriptor)
{
return propertyDescriptor.HasAnnotation(UtilConstants.TypeOfTimestamp);
}
}
}
using Chloe.Annotations;
using Chloe.Core.Visitors;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
class EvaluableDbExpressionTransformer : EvaluableDbExpressionTransformerBase
{
static EvaluableDbExpressionTransformer _transformer = new EvaluableDbExpressionTransformer();
static KeyDictionary<MemberInfo> _toTranslateMembers = new KeyDictionary<MemberInfo>();
static EvaluableDbExpressionTransformer()
{
_toTranslateMembers.Add(UtilConstants.PropertyInfo_String_Length);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Now);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_UtcNow);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Today);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Date);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Year);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Month);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Day);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Hour);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Minute);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Second);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_Millisecond);
_toTranslateMembers.Add(UtilConstants.PropertyInfo_DateTime_DayOfWeek);
_toTranslateMembers = _toTranslateMembers.Clone();
}
public static DbExpression Transform(DbExpression exp)
{
return exp.Accept(_transformer);
}
public override bool CanTranslateToSql(DbMemberExpression exp)
{
return _toTranslateMembers.Exists(exp.Member);
}
public override bool CanTranslateToSql(DbMethodCallExpression exp)
{
IMethodHandler methodHandler;
if (SqlGenerator.MethodHandlers.TryGetValue(exp.Method.Name, out methodHandler))
{
if (methodHandler.CanProcess(exp))
{
return true;
}
}
return false;
}
}
}
using Chloe.DbExpressions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
interface IMethodHandler
{
bool CanProcess(DbMethodCallExpression exp);
void Process(DbMethodCallExpression exp, SqlGenerator generator);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chloe.SqlServer
{
interface ISqlBuilder
{
int Length { get; }
string ToSql();
ISqlBuilder Append(object obj);
ISqlBuilder Append(object obj1, object obj2);
ISqlBuilder Append(object obj1, object obj2, object obj3);
ISqlBuilder Append(object obj1, object obj2, object obj3, object obj4);
ISqlBuilder Append(object obj1, object obj2, object obj3, object obj4, object obj5);
ISqlBuilder Append(params object[] objs);
}
class SqlBuilder : ISqlBuilder
{
StringBuilder _sb = new StringBuilder();
public int Length { get { return this._sb.Length; } }
public string ToSql()
{
return this._sb.ToString();
}
public ISqlBuilder Append(object obj)
{
this._sb.Append(obj);
return this;
}
public ISqlBuilder Append(object obj1, object obj2)
{
return this.Append(obj1).Append(obj2);
}
public ISqlBuilder Append(object obj1, object obj2, object obj3)
{
return this.Append(obj1).Append(obj2).Append(obj3);
}
public ISqlBuilder Append(object obj1, object obj2, object obj3, object obj4)
{
return this.Append(obj1).Append(obj2).Append(obj3).Append(obj4);
}
public ISqlBuilder Append(object obj1, object obj2, object obj3, object obj4, object obj5)
{
return this.Append(obj1).Append(obj2).Append(obj3).Append(obj4).Append(obj5);
}
public ISqlBuilder Append(params object[] objs)
{
if (objs == null)
return this;
for (int i = 0; i < objs.Length; i++)
{
var obj = objs[i];
this.Append(obj);
}
return this;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Abs_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfMath)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("ABS(");
exp.Arguments[0].Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddDays_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "DAY", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddHours_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "HOUR", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddMilliseconds_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "MILLISECOND", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddMinutes_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "MINUTE", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddMonths_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "MONTH", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddSeconds_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "SECOND", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class AddYears_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfDateTime)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEADD(generator, "YEAR", exp);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Average_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_Average(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
namespace Chloe.SqlServer.MethodHandlers
{
class Compare_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
return exp.Method.DeclaringType == UtilConstants.TypeOfSql;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
DbExpression left = exp.Arguments[0];
DbExpression right = exp.Arguments[2];
CompareType compareType = (CompareType)exp.Arguments[1].Evaluate();
DbExpression newExp = null;
switch (compareType)
{
case CompareType.eq:
{
MethodInfo method_Sql_Equals = UtilConstants.MethodInfo_Sql_Equals.MakeGenericMethod(left.Type);
/* Sql.Equals(left, right) */
DbMethodCallExpression left_equals_right = DbExpression.MethodCall(null, method_Sql_Equals, new List<DbExpression>(2) { left, right });
newExp = left_equals_right;
}
break;
case CompareType.neq:
{
MethodInfo method_Sql_NotEquals = UtilConstants.MethodInfo_Sql_NotEquals.MakeGenericMethod(left.Type);
/* Sql.NotEquals(left, right) */
DbMethodCallExpression left_not_equals_right = DbExpression.MethodCall(null, method_Sql_NotEquals, new List<DbExpression>(2) { left, right });
newExp = left_not_equals_right;
}
break;
case CompareType.gt:
{
newExp = new DbGreaterThanExpression(left, right);
}
break;
case CompareType.gte:
{
newExp = new DbGreaterThanOrEqualExpression(left, right);
}
break;
case CompareType.lt:
{
newExp = new DbLessThanExpression(left, right);
}
break;
case CompareType.lte:
{
newExp = new DbLessThanOrEqualExpression(left, right);
}
break;
default:
throw new NotSupportedException("CompareType: " + compareType.ToString());
}
newExp.Accept(generator);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
namespace Chloe.SqlServer.MethodHandlers
{
class Contains_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
MethodInfo method = exp.Method;
if (exp.Method == UtilConstants.MethodInfo_String_Contains)
{
return true;
}
Type declaringType = method.DeclaringType;
if (typeof(IList).IsAssignableFrom(declaringType) || (declaringType.IsGenericType && typeof(ICollection<>).MakeGenericType(declaringType.GetGenericArguments()).IsAssignableFrom(declaringType)))
{
return true;
}
if (method.IsStatic && declaringType == typeof(Enumerable) && exp.Arguments.Count == 2)
{
return true;
}
return false;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodInfo method = exp.Method;
if (exp.Method == UtilConstants.MethodInfo_String_Contains)
{
Method_String_Contains(exp, generator);
return;
}
List<DbExpression> exps = new List<DbExpression>();
IEnumerable values = null;
DbExpression operand = null;
Type declaringType = method.DeclaringType;
if (typeof(IList).IsAssignableFrom(declaringType) || (declaringType.IsGenericType && typeof(ICollection<>).MakeGenericType(declaringType.GetGenericArguments()).IsAssignableFrom(declaringType)))
{
if (exp.Object.NodeType == DbExpressionType.SqlQuery)
{
/* where Id in(select id from T) */
operand = exp.Arguments[0];
In(generator, (DbSqlQueryExpression)exp.Object, operand);
return;
}
if (!exp.Object.IsEvaluable())
throw new NotSupportedException(exp.ToString());
values = DbExpressionExtension.Evaluate(exp.Object) as IEnumerable; //Enumerable
operand = exp.Arguments[0];
goto constructInState;
}
if (method.IsStatic && declaringType == typeof(Enumerable) && exp.Arguments.Count == 2)
{
DbExpression arg0 = exp.Arguments[0];
if (arg0.NodeType == DbExpressionType.SqlQuery)
{
/* where Id in(select id from T) */
operand = exp.Arguments[1];
In(generator, (DbSqlQueryExpression)arg0, operand);
return;
}
if (!arg0.IsEvaluable())
throw UtilExceptions.NotSupportedMethod(exp.Method);
values = DbExpressionExtension.Evaluate(arg0) as IEnumerable;
operand = exp.Arguments[1];
goto constructInState;
}
throw UtilExceptions.NotSupportedMethod(exp.Method);
constructInState:
foreach (object value in values)
{
if (value == null)
exps.Add(DbExpression.Constant(null, operand.Type));
else
{
Type valueType = value.GetType();
if (valueType.IsEnum)
valueType = Enum.GetUnderlyingType(valueType);
if (Utils.IsToStringableNumericType(valueType))
exps.Add(DbExpression.Constant(value));
else
exps.Add(DbExpression.Parameter(value));
}
}
In(generator, exps, operand);
}
static void Method_String_Contains(DbMethodCallExpression exp, SqlGenerator generator)
{
exp.Object.Accept(generator);
generator.SqlBuilder.Append(" LIKE '%' + ");
exp.Arguments.First().Accept(generator);
generator.SqlBuilder.Append(" + '%'");
}
static void In(SqlGenerator generator, List<DbExpression> elementExps, DbExpression operand)
{
if (elementExps.Count == 0)
{
generator.SqlBuilder.Append("1=0");
return;
}
operand.Accept(generator);
generator.SqlBuilder.Append(" IN (");
for (int i = 0; i < elementExps.Count; i++)
{
if (i > 0)
generator.SqlBuilder.Append(",");
elementExps[i].Accept(generator);
}
generator.SqlBuilder.Append(")");
}
static void In(SqlGenerator generator, DbSqlQueryExpression sqlQuery, DbExpression operand)
{
operand.Accept(generator);
generator.SqlBuilder.Append(" IN (");
sqlQuery.Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Count_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_Count(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffDays_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "DAY", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffHours_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "HOUR", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffMicroseconds_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "MICROSECOND", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffMilliseconds_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "MILLISECOND", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffMinutes_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "MINUTE", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffMonths_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "MONTH", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffSeconds_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "SECOND", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class DiffYears_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.DbFunction_DATEDIFF(generator, "YEAR", exp.Arguments[0], exp.Arguments[1]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
using static Chloe.DbExpressions.DbCaseWhenExpression;
namespace Chloe.SqlServer.MethodHandlers
{
class Else_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
return exp.Method.DeclaringType.IsGenericType && exp.Method.DeclaringType.GetGenericTypeDefinition() == typeof(Then<>);
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
List<WhenThenExpressionPair> pairs = new List<WhenThenExpressionPair>();
GetWhenThenPairs(exp.Object as DbMethodCallExpression, pairs);
pairs.Reverse();
List<WhenThenExpressionPair> whenThenPairs = pairs;
DbExpression elseExp = exp.Arguments[0];
DbCaseWhenExpression caseWhenExp = new DbCaseWhenExpression(exp.Type, whenThenPairs, elseExp);
caseWhenExp.Accept(generator);
}
void GetWhenThenPairs(DbMethodCallExpression thenCall, List<WhenThenExpressionPair> pairs)
{
DbMethodCallExpression whenCall = thenCall.Object as DbMethodCallExpression;
var thenExp = thenCall.Arguments[0];
var conditionExp = whenCall.Arguments[0];
WhenThenExpressionPair pair = new WhenThenExpressionPair(conditionExp, thenExp);
pairs.Add(pair);
if (whenCall.Object == null)
{
return;
}
GetWhenThenPairs(whenCall.Object as DbMethodCallExpression, pairs);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class EndsWith_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_EndsWith)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
exp.Object.Accept(generator);
generator.SqlBuilder.Append(" LIKE '%' + ");
exp.Arguments.First().Accept(generator);
}
}
}
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Equals_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
MethodInfo method = exp.Method;
if (method.DeclaringType == UtilConstants.TypeOfSql)
{
return true;
}
if (method.ReturnType != UtilConstants.TypeOfBoolean || method.IsStatic || method.GetParameters().Length != 1)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodInfo method = exp.Method;
if (method.DeclaringType == UtilConstants.TypeOfSql)
{
Method_Sql_Equals(exp, generator);
return;
}
DbExpression right = exp.Arguments[0];
if (right.Type != exp.Object.Type)
{
right = DbExpression.Convert(right, exp.Object.Type);
}
DbExpression.Equal(exp.Object, right).Accept(generator);
}
static void Method_Sql_Equals(DbMethodCallExpression exp, SqlGenerator generator)
{
DbExpression left = exp.Arguments[0];
DbExpression right = exp.Arguments[1];
left = DbExpressionExtension.StripInvalidConvert(left);
right = DbExpressionExtension.StripInvalidConvert(right);
//明确 left right 其中一边一定为 null
if (DbExpressionExtension.AffirmExpressionRetValueIsNull(right))
{
left.Accept(generator);
generator.SqlBuilder.Append(" IS NULL");
return;
}
if (DbExpressionExtension.AffirmExpressionRetValueIsNull(left))
{
right.Accept(generator);
generator.SqlBuilder.Append(" IS NULL");
return;
}
SqlGenerator.AmendDbInfo(left, right);
left.Accept(generator);
generator.SqlBuilder.Append(" = ");
right.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class In_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
MethodInfo method = exp.Method;
/* public static bool In<T>(this T obj, IEnumerable<T> source) */
if (method.IsGenericMethod && method.ReturnType == UtilConstants.TypeOfBoolean)
{
Type[] genericArguments = method.GetGenericArguments();
ParameterInfo[] parameters = method.GetParameters();
Type genericType = genericArguments[0];
if (genericArguments.Length == 1 && parameters.Length == 2 && parameters[0].ParameterType == genericType)
{
Type secondParameterType = parameters[1].ParameterType;
if (typeof(IEnumerable<>).MakeGenericType(genericType).IsAssignableFrom(secondParameterType))
{
return true;
}
}
}
return false;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodInfo method = exp.Method;
/* public static bool In<T>(this T obj, IEnumerable<T> source) */
Type[] genericArguments = method.GetGenericArguments();
Type genericType = genericArguments[0];
MethodInfo method_Contains = UtilConstants.MethodInfo_Enumerable_Contains.MakeGenericMethod(genericType);
List<DbExpression> arguments = new List<DbExpression>(2) { exp.Arguments[1], exp.Arguments[0] };
DbMethodCallExpression newExp = new DbMethodCallExpression(null, method_Contains, arguments);
newExp.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class IsNullOrEmpty_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_IsNullOrEmpty)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
DbExpression e = exp.Arguments.First();
DbEqualExpression equalNullExpression = DbExpression.Equal(e, DbExpression.Constant(null, UtilConstants.TypeOfString));
DbEqualExpression equalEmptyExpression = DbExpression.Equal(e, DbExpression.Constant(string.Empty));
DbOrExpression orExpression = DbExpression.Or(equalNullExpression, equalEmptyExpression);
DbCaseWhenExpression.WhenThenExpressionPair whenThenPair = new DbCaseWhenExpression.WhenThenExpressionPair(orExpression, DbConstantExpression.One);
List<DbCaseWhenExpression.WhenThenExpressionPair> whenThenExps = new List<DbCaseWhenExpression.WhenThenExpressionPair>(1);
whenThenExps.Add(whenThenPair);
DbCaseWhenExpression caseWhenExpression = DbExpression.CaseWhen(whenThenExps, DbConstantExpression.Zero, UtilConstants.TypeOfBoolean);
var eqExp = DbExpression.Equal(caseWhenExpression, DbConstantExpression.One);
eqExp.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class LongCount_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_LongCount(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Max_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_Max(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
}
}
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class MethodHandlerHelper
{
public static void EnsureTrimCharArgumentIsSpaces(DbExpression exp)
{
if (!exp.IsEvaluable())
throw new NotSupportedException();
var arg = exp.Evaluate();
if (arg == null)
throw new ArgumentNullException();
var chars = arg as char[];
if (chars.Length != 1 || chars[0] != ' ')
{
throw new NotSupportedException();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Min_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_Min(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class NewGuid_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_Guid_NewGuid)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("NEWID()");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
namespace Chloe.SqlServer.MethodHandlers
{
class NextValueForSequence_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
string sequenceName = (string)exp.Arguments[0].Evaluate();
if (string.IsNullOrEmpty(sequenceName))
throw new ArgumentException("The sequence name cannot be empty.");
generator.SqlBuilder.Append("NEXT VALUE FOR ", sequenceName);
}
}
}
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class NotEquals_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
MethodInfo method = exp.Method;
if (method.DeclaringType != UtilConstants.TypeOfSql)
{
return false;
}
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodInfo method = exp.Method;
DbExpression left = exp.Arguments[0];
DbExpression right = exp.Arguments[1];
left = DbExpressionExtension.StripInvalidConvert(left);
right = DbExpressionExtension.StripInvalidConvert(right);
//明确 left right 其中一边一定为 null
if (DbExpressionExtension.AffirmExpressionRetValueIsNull(right))
{
left.Accept(generator);
generator.SqlBuilder.Append(" IS NOT NULL");
return;
}
if (DbExpressionExtension.AffirmExpressionRetValueIsNull(left))
{
right.Accept(generator);
generator.SqlBuilder.Append(" IS NOT NULL");
return;
}
SqlGenerator.AmendDbInfo(left, right);
left.Accept(generator);
generator.SqlBuilder.Append(" <> ");
right.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Parse_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Arguments.Count != 1)
return false;
DbExpression arg = exp.Arguments[0];
if (arg.Type != UtilConstants.TypeOfString)
return false;
Type retType = exp.Method.ReturnType;
if (exp.Method.DeclaringType != retType)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
DbExpression arg = exp.Arguments[0];
DbExpression e = DbExpression.Convert(arg, exp.Method.ReturnType);
if (exp.Method.ReturnType == UtilConstants.TypeOfBoolean)
{
e.Accept(generator);
generator.SqlBuilder.Append(" = ");
DbConstantExpression.True.Accept(generator);
}
else
e.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Replace_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_Replace)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("REPLACE(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(",");
exp.Arguments[0].Accept(generator);
generator.SqlBuilder.Append(",");
exp.Arguments[1].Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer.MethodHandlers
{
class StartsWith_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_StartsWith)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
exp.Object.Accept(generator);
generator.SqlBuilder.Append(" LIKE ");
exp.Arguments.First().Accept(generator);
generator.SqlBuilder.Append(" + '%'");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Substring_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_Substring_Int32 && exp.Method != UtilConstants.MethodInfo_String_Substring_Int32_Int32)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("SUBSTRING(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(",");
DbExpression arg1 = exp.Arguments[0];
if (arg1.NodeType == DbExpressionType.Constant)
{
int startIndex = (int)(((DbConstantExpression)arg1).Value) + 1;
generator.SqlBuilder.Append(startIndex.ToString());
}
else
{
arg1.Accept(generator);
generator.SqlBuilder.Append(" + 1");
}
generator.SqlBuilder.Append(",");
if (exp.Method == UtilConstants.MethodInfo_String_Substring_Int32)
{
var string_LengthExp = DbExpression.MemberAccess(UtilConstants.PropertyInfo_String_Length, exp.Object);
string_LengthExp.Accept(generator);
}
else if (exp.Method == UtilConstants.MethodInfo_String_Substring_Int32_Int32)
{
exp.Arguments[1].Accept(generator);
}
else
throw UtilExceptions.NotSupportedMethod(exp.Method);
generator.SqlBuilder.Append(")");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Sum_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method.DeclaringType != UtilConstants.TypeOfSql)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
SqlGenerator.Aggregate_Sum(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class ToLower_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_ToLower)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("LOWER(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
namespace Chloe.SqlServer.MethodHandlers
{
class ToString_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Arguments.Count != 0)
{
return false;
}
if (exp.Object.Type == UtilConstants.TypeOfString)
{
return true;
}
if (!SqlGenerator.NumericTypes.ContainsKey(exp.Object.Type.GetUnderlyingType()))
{
return false;
}
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
if (exp.Object.Type == UtilConstants.TypeOfString)
{
exp.Object.Accept(generator);
return;
}
DbConvertExpression c = DbExpression.Convert(exp.Object, UtilConstants.TypeOfString);
c.Accept(generator);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class ToUpper_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_ToUpper)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("UPPER(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class TrimEnd_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_TrimEnd)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodHandlerHelper.EnsureTrimCharArgumentIsSpaces(exp.Arguments[0]);
generator.SqlBuilder.Append("RTRIM(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class TrimStart_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_TrimStart)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
MethodHandlerHelper.EnsureTrimCharArgumentIsSpaces(exp.Arguments[0]);
generator.SqlBuilder.Append("LTRIM(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append(")");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chloe.DbExpressions;
namespace Chloe.SqlServer.MethodHandlers
{
class Trim_Handler : IMethodHandler
{
public bool CanProcess(DbMethodCallExpression exp)
{
if (exp.Method != UtilConstants.MethodInfo_String_Trim)
return false;
return true;
}
public void Process(DbMethodCallExpression exp, SqlGenerator generator)
{
generator.SqlBuilder.Append("RTRIM(LTRIM(");
exp.Object.Accept(generator);
generator.SqlBuilder.Append("))");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
public static class MsSqlContextExtension
{
public static void BulkInsert<TEntity>(this IDbContext dbContext, List<TEntity> entities, string table = null, int? batchSize = null, int? bulkCopyTimeout = null, bool keepIdentity = false)
{
MsSqlContext msSqlContext = (MsSqlContext)dbContext;
msSqlContext.BulkInsert<TEntity>(entities, table, batchSize, bulkCopyTimeout, keepIdentity);
}
}
}
using Chloe.Core;
using Chloe.Core.Visitors;
using Chloe.DbExpressions;
using Chloe.Descriptors;
using Chloe.Entity;
using Chloe.Exceptions;
using Chloe.Infrastructure;
using Chloe.InternalExtensions;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
public partial class MsSqlContext : DbContext
{
static Action<TEntity, IDataReader> GetMapper<TEntity>(PropertyDescriptor propertyDescriptor, int ordinal)
{
Action<TEntity, IDataReader> mapper = (TEntity entity, IDataReader reader) =>
{
object value = reader.GetValue(ordinal);
if (value == null || value == DBNull.Value)
throw new ChloeException("Unable to get the identity/sequence value.");
value = PublicHelper.ConvertObjType(value, propertyDescriptor.PropertyType);
propertyDescriptor.SetValue(entity, value);
};
return mapper;
}
static string AppendInsertRangeSqlTemplate(DbTable table, List<PropertyDescriptor> mappingPropertyDescriptors)
{
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.Append("INSERT INTO ");
sqlBuilder.Append(AppendTableName(table));
sqlBuilder.Append("(");
for (int i = 0; i < mappingPropertyDescriptors.Count; i++)
{
PropertyDescriptor mappingPropertyDescriptor = mappingPropertyDescriptors[i];
if (i > 0)
sqlBuilder.Append(",");
sqlBuilder.Append(Utils.QuoteName(mappingPropertyDescriptor.Column.Name));
}
sqlBuilder.Append(") VALUES");
string sqlTemplate = sqlBuilder.ToString();
return sqlTemplate;
}
static string AppendTableName(DbTable table)
{
if (string.IsNullOrEmpty(table.Schema))
return Utils.QuoteName(table.Name);
return string.Format("{0}.{1}", Utils.QuoteName(table.Schema), Utils.QuoteName(table.Name));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
public enum PagingMode
{
ROW_NUMBER = 1,
OFFSET_FETCH = 2
}
}
using Chloe.Core;
using Chloe.DbExpressions;
using Chloe.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
partial class SqlGenerator : DbExpressionVisitor<DbExpression>
{
static Dictionary<string, Action<DbAggregateExpression, SqlGenerator>> InitAggregateHandlers()
{
var aggregateHandlers = new Dictionary<string, Action<DbAggregateExpression, SqlGenerator>>();
aggregateHandlers.Add("Count", Aggregate_Count);
aggregateHandlers.Add("LongCount", Aggregate_LongCount);
aggregateHandlers.Add("Sum", Aggregate_Sum);
aggregateHandlers.Add("Max", Aggregate_Max);
aggregateHandlers.Add("Min", Aggregate_Min);
aggregateHandlers.Add("Average", Aggregate_Average);
var ret = PublicHelper.Clone(aggregateHandlers);
return ret;
}
static void Aggregate_Count(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_Count(generator);
}
static void Aggregate_LongCount(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_LongCount(generator);
}
static void Aggregate_Sum(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_Sum(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
static void Aggregate_Max(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_Max(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
static void Aggregate_Min(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_Min(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
static void Aggregate_Average(DbAggregateExpression exp, SqlGenerator generator)
{
Aggregate_Average(generator, exp.Arguments.First(), exp.Method.ReturnType);
}
}
}
using Chloe.DbExpressions;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Chloe.SqlServer
{
partial class SqlGenerator : DbExpressionVisitor<DbExpression>
{
static Dictionary<MethodInfo, Action<DbBinaryExpression, SqlGenerator>> InitBinaryWithMethodHandlers()
{
var binaryWithMethodHandlers = new Dictionary<MethodInfo, Action<DbBinaryExpression, SqlGenerator>>();
binaryWithMethodHandlers.Add(UtilConstants.MethodInfo_String_Concat_String_String, StringConcat);
binaryWithMethodHandlers.Add(UtilConstants.MethodInfo_String_Concat_Object_Object, StringConcat);
var ret = PublicHelper.Clone(binaryWithMethodHandlers);
return ret;
}
static void StringConcat(DbBinaryExpression exp, SqlGenerator generator)
{
List<DbExpression> operands = new List<DbExpression>();
operands.Add(exp.Right);
DbExpression left = exp.Left;
DbAddExpression e = null;
while ((e = (left as DbAddExpression)) != null && (e.Method == UtilConstants.MethodInfo_String_Concat_String_String || e.Method == UtilConstants.MethodInfo_String_Concat_Object_Object))
{
operands.Add(e.Right);
left = e.Left;
}
operands.Add(left);
DbExpression whenExp = null;
List<DbExpression> operandExps = new List<DbExpression>(operands.Count);
for (int i = operands.Count - 1; i >= 0; i--)
{
DbExpression operand = operands[i];
DbExpression opBody = operand;
if (opBody.Type != UtilConstants.TypeOfString)
{
// 需要 cast type
opBody = DbExpression.Convert(opBody, UtilConstants.TypeOfString);
}
DbExpression equalNullExp = DbExpression.Equal(opBody, UtilConstants.DbConstant_Null_String);
if (whenExp == null)
whenExp = equalNullExp;
else
whenExp = DbExpression.And(whenExp, equalNullExp);
operandExps.Add(opBody);
}
generator._sqlBuilder.Append("CASE", " WHEN ");
whenExp.Accept(generator);
generator._sqlBuilder.Append(" THEN ");
DbConstantExpression.Null.Accept(generator);
generator._sqlBuilder.Append(" ELSE ");
generator._sqlBuilder.Append("(");
for (int i = 0; i < operandExps.Count; i++)
{
if (i > 0)
generator._sqlBuilder.Append(" + ");
generator._sqlBuilder.Append("ISNULL(");
operandExps[i].Accept(generator);
generator._sqlBuilder.Append(",");
DbConstantExpression.StringEmpty.Accept(generator);
generator._sqlBuilder.Append(")");
}
generator._sqlBuilder.Append(")");
generator._sqlBuilder.Append(" END");
}
}
}
using Chloe.Core;
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
using Chloe.SqlServer.MethodHandlers;
using Chloe.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
partial class SqlGenerator : DbExpressionVisitor<DbExpression>
{
static Dictionary<string, IMethodHandler> GetMethodHandlers()
{
var methodHandlers = new Dictionary<string, IMethodHandler>();
var methodHandlerTypes = Assembly.GetExecutingAssembly().GetTypes().Where(a => a.IsClass && !a.IsAbstract && typeof(IMethodHandler).IsAssignableFrom(a) && a.Name.EndsWith("_Handler") && a.GetConstructor(Type.EmptyTypes) != null);
foreach (Type methodHandlerType in methodHandlerTypes)
{
string handleMethodName = methodHandlerType.Name.Substring(0, methodHandlerType.Name.Length - "_Handler".Length);
methodHandlers.Add(handleMethodName, (IMethodHandler)Activator.CreateInstance(methodHandlerType));
}
var ret = PublicHelper.Clone(methodHandlers);
return ret;
}
}
}
using Chloe.DbExpressions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
class SqlGenerator_OffsetFetch : SqlGenerator
{
protected override void BuildLimitSql(DbExpressions.DbSqlQueryExpression exp)
{
//order by number offset 10 rows fetch next 20 rows only;
this.SqlBuilder.Append("SELECT ");
this.AppendDistinct(exp.IsDistinct);
List<DbColumnSegment> columns = exp.ColumnSegments;
for (int i = 0; i < columns.Count; i++)
{
DbColumnSegment column = columns[i];
if (i > 0)
this.SqlBuilder.Append(",");
this.AppendColumnSegment(column);
}
this.SqlBuilder.Append(" FROM ");
exp.Table.Accept(this);
this.BuildWhereState(exp.Condition);
this.BuildGroupState(exp);
List<DbOrdering> orderings = exp.Orderings;
if (orderings.Count == 0)
{
DbExpression orderingExp = DbExpression.Add(UtilConstants.DbParameter_1, DbConstantExpression.Zero, DbConstantExpression.Zero.Type, null);
DbOrdering ordering = new DbOrdering(orderingExp, DbOrderType.Asc);
orderings = new List<DbOrdering>(1);
orderings.Add(ordering);
}
this.BuildOrderState(orderings);
this.SqlBuilder.Append(" OFFSET ", exp.SkipCount.Value.ToString(), " ROWS");
if (exp.TakeCount != null)
{
this.SqlBuilder.Append(" FETCH NEXT ", exp.TakeCount.Value.ToString(), " ROWS ONLY");
}
}
}
}
using Chloe.DbExpressions;
using Chloe.SqlServer.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
static class UtilConstants
{
public const string ParameterNamePlaceholer = "@";
public static readonly string ParameterNamePrefix = ParameterNamePlaceholer + "P_";
static UtilConstants()
{
Expression<Func<bool>> e = () => Enumerable.Contains((IEnumerable<int>)null, 0);
MethodInfo method_Enumerable_Contains = (e.Body as MethodCallExpression).Method.GetGenericMethodDefinition();
MethodInfo_Enumerable_Contains = method_Enumerable_Contains;
}
public static readonly Type TypeOfTimestamp = typeof(TimestampAttribute);
public static readonly Type TypeOfVoid = typeof(void);
public static readonly Type TypeOfInt16 = typeof(Int16);
public static readonly Type TypeOfInt32 = typeof(Int32);
public static readonly Type TypeOfInt64 = typeof(Int64);
public static readonly Type TypeOfDecimal = typeof(Decimal);
public static readonly Type TypeOfDouble = typeof(Double);
public static readonly Type TypeOfSingle = typeof(Single);
public static readonly Type TypeOfBoolean = typeof(Boolean);
public static readonly Type TypeOfBoolean_Nullable = typeof(Boolean?);
public static readonly Type TypeOfDateTime = typeof(DateTime);
public static readonly Type TypeOfGuid = typeof(Guid);
public static readonly Type TypeOfByte = typeof(Byte);
public static readonly Type TypeOfChar = typeof(Char);
public static readonly Type TypeOfString = typeof(String);
public static readonly Type TypeOfObject = typeof(Object);
public static readonly Type TypeOfTimeSpan = typeof(TimeSpan);
public static readonly Type TypeOfMath = typeof(Math);
public static readonly Type TypeOfSql = typeof(Sql);
#region DbExpression constants
public static readonly DbParameterExpression DbParameter_1 = DbExpression.Parameter(1);
public static readonly DbConstantExpression DbConstant_Null_String = DbExpression.Constant(null, typeof(string));
#endregion
#region MemberInfo constants
public static readonly PropertyInfo PropertyInfo_String_Length = typeof(string).GetProperty("Length");
/* DateTime */
public static readonly PropertyInfo PropertyInfo_DateTime_Now = typeof(DateTime).GetProperty("Now");
public static readonly PropertyInfo PropertyInfo_DateTime_UtcNow = typeof(DateTime).GetProperty("UtcNow");
public static readonly PropertyInfo PropertyInfo_DateTime_Today = typeof(DateTime).GetProperty("Today");
public static readonly PropertyInfo PropertyInfo_DateTime_Date = typeof(DateTime).GetProperty("Date");
public static readonly PropertyInfo PropertyInfo_DateTime_Year = typeof(DateTime).GetProperty("Year");
public static readonly PropertyInfo PropertyInfo_DateTime_Month = typeof(DateTime).GetProperty("Month");
public static readonly PropertyInfo PropertyInfo_DateTime_Day = typeof(DateTime).GetProperty("Day");
public static readonly PropertyInfo PropertyInfo_DateTime_Hour = typeof(DateTime).GetProperty("Hour");
public static readonly PropertyInfo PropertyInfo_DateTime_Minute = typeof(DateTime).GetProperty("Minute");
public static readonly PropertyInfo PropertyInfo_DateTime_Second = typeof(DateTime).GetProperty("Second");
public static readonly PropertyInfo PropertyInfo_DateTime_Millisecond = typeof(DateTime).GetProperty("Millisecond");
public static readonly PropertyInfo PropertyInfo_DateTime_DayOfWeek = typeof(DateTime).GetProperty("DayOfWeek");
/* String */
public static readonly MethodInfo MethodInfo_String_Concat_String_String = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
public static readonly MethodInfo MethodInfo_String_Concat_Object_Object = typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) });
public static readonly MethodInfo MethodInfo_String_Trim = typeof(string).GetMethod("Trim", Type.EmptyTypes);
public static readonly MethodInfo MethodInfo_String_TrimStart = typeof(string).GetMethod("TrimStart", new Type[] { typeof(char[]) });
public static readonly MethodInfo MethodInfo_String_TrimEnd = typeof(string).GetMethod("TrimEnd", new Type[] { typeof(char[]) });
public static readonly MethodInfo MethodInfo_String_StartsWith = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
public static readonly MethodInfo MethodInfo_String_EndsWith = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
public static readonly MethodInfo MethodInfo_String_Contains = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
public static readonly MethodInfo MethodInfo_String_IsNullOrEmpty = typeof(string).GetMethod("IsNullOrEmpty", new Type[] { typeof(string) });
public static readonly MethodInfo MethodInfo_String_ToUpper = typeof(string).GetMethod("ToUpper", Type.EmptyTypes);
public static readonly MethodInfo MethodInfo_String_ToLower = typeof(string).GetMethod("ToLower", Type.EmptyTypes);
public static readonly MethodInfo MethodInfo_String_Substring_Int32 = typeof(string).GetMethod("Substring", new Type[] { typeof(Int32) });
public static readonly MethodInfo MethodInfo_String_Substring_Int32_Int32 = typeof(string).GetMethod("Substring", new Type[] { typeof(Int32), typeof(Int32) });
public static readonly MethodInfo MethodInfo_String_Replace = typeof(string).GetMethod("Replace", new Type[] { typeof(string), typeof(string) });
public static readonly MethodInfo MethodInfo_Guid_NewGuid = typeof(Guid).GetMethod("NewGuid");
public static MethodInfo MethodInfo_Enumerable_Contains { get; private set; }
/* Sql */
public static readonly MethodInfo MethodInfo_Sql_Equals = typeof(Sql).GetMethods().Where(a => a.Name == "Equals" && a.IsStatic && a.IsGenericMethod).First();
public static readonly MethodInfo MethodInfo_Sql_NotEquals = typeof(Sql).GetMethod("NotEquals");
public static readonly MethodInfo MethodInfo_Sql_NextValueForSequence = typeof(Sql).GetMethod("NextValueForSequence");
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Chloe.SqlServer
{
static class UtilExceptions
{
public static NotSupportedException NotSupportedMethod(MethodInfo method)
{
StringBuilder sb = new StringBuilder();
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
ParameterInfo p = parameters[i];
if (i > 0)
sb.Append(",");
string s = null;
if (p.IsOut)
s = "out ";
sb.AppendFormat("{0}{1} {2}", s, p.ParameterType.Name, p.Name);
}
return new NotSupportedException(string.Format("Does not support method '{0}.{1}({2})'.", method.DeclaringType.Name, method.Name, sb.ToString()));
}
}
}
using Chloe.DbExpressions;
using Chloe.InternalExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.SqlServer
{
internal static class Utils
{
static readonly Dictionary<Type, Type> ToStringableNumericTypes;
static Utils()
{
List<Type> toStringableNumericTypes = new List<Type>();
toStringableNumericTypes.Add(typeof(byte));
toStringableNumericTypes.Add(typeof(sbyte));
toStringableNumericTypes.Add(typeof(short));
toStringableNumericTypes.Add(typeof(ushort));
toStringableNumericTypes.Add(typeof(int));
toStringableNumericTypes.Add(typeof(uint));
toStringableNumericTypes.Add(typeof(long));
toStringableNumericTypes.Add(typeof(ulong));
ToStringableNumericTypes = toStringableNumericTypes.ToDictionary(a => a, a => a);
}
public static string QuoteName(string name)
{
return string.Concat("[", name, "]");
}
public static bool IsToStringableNumericType(Type type)
{
type = ReflectionExtension.GetUnderlyingType(type);
return ToStringableNumericTypes.ContainsKey(type);
}
}
}
using System;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class AutoIncrementAttribute : Attribute
{
}
}
using System;
using System.Data;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ColumnAttribute : Attribute
{
public ColumnAttribute() { }
public ColumnAttribute(string name)
{
this.Name = name;
}
public string Name { get; set; }
public bool IsPrimaryKey { get; set; }
/// <summary>
/// -1 表示未指定确切的值,用该属性的时候务必做 -1 判断。
/// </summary>
public DbType DbType { get; set; } = (DbType)(-1); /* -1=Unspecified */
/// <summary>
/// -1 表示未指定确切的值,用该属性的时候务必做 -1 判断。
/// </summary>
public int Size { get; set; } = -1; /* -1=Unspecified */
/// <summary>
/// -1 表示未指定确切的值,用该属性的时候务必做 -1 判断。
/// </summary>
public int Scale { get; set; } = -1; /* -1=Unspecified */
/// <summary>
/// -1 表示未指定确切的值,用该属性的时候务必做 -1 判断。
/// </summary>
public int Precision { get; set; } = -1; /* -1=Unspecified */
public bool HasDbType()
{
return (int)this.DbType != -1;
}
public DbType? GetDbType()
{
if (this.HasDbType())
return this.DbType;
return null;
}
public bool HasSize()
{
return this.Size != -1;
}
public int? GetSize()
{
if (this.HasSize())
return this.Size;
return null;
}
public bool HasScale()
{
return this.Scale != -1;
}
public byte? GetScale()
{
if (this.HasScale())
return Convert.ToByte(this.Scale);
return null;
}
public bool HasPrecision()
{
return this.Precision != -1;
}
public byte? GetPrecision()
{
if (this.HasPrecision())
return Convert.ToByte(this.Precision);
return null;
}
}
}
using System;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DbFunctionAttribute : Attribute
{
public DbFunctionAttribute()
{
}
public DbFunctionAttribute(string name)
{
this.Name = name;
}
public string Name { get; set; }
public string Schema { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class NonAutoIncrementAttribute : Attribute
{
}
}
using System;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class NotMappedAttribute : Attribute
{
}
}
using System;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class SequenceAttribute : Attribute
{
public SequenceAttribute(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
}
using System;
namespace Chloe.Annotations
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class TableAttribute : Attribute
{
public TableAttribute() { }
public TableAttribute(string name)
{
this.Name = name;
}
public string Name { get; set; }
public string Schema { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe
{
/// <summary>
/// usage: Case.When(a.Gender == Gender.Man).Then("Man").When(a.Gender == Gender.Woman).Then("Woman").Else(null)
/// </summary>
public class Case
{
bool _condition;
internal Case(bool condition)
{
this._condition = condition;
}
public static Case When(bool condition)
{
return new Case(condition);
}
public Then<TResult> Then<TResult>(TResult result)
{
return new Then<TResult>(this._condition, result, null);
}
}
public class Case<TResult>
{
bool _condition;
Then<TResult> _prevCase;
internal Case(bool condition, Then<TResult> prevCase)
{
this._condition = condition;
this._prevCase = prevCase;
}
public Then<TResult> Then(TResult result)
{
Then<TResult> ret = new Then<TResult>(this._condition, result, this._prevCase);
return ret;
}
}
public class Then<TResult>
{
bool _condition;
TResult _result;
Then<TResult> _prevCase;
internal Then(bool condition, TResult result, Then<TResult> prevCase)
{
this._condition = condition;
this._result = result;
this._prevCase = prevCase;
}
public Case<TResult> When(bool condition)
{
return new Case<TResult>(condition, this);
}
public TResult Else(TResult result)
{
TResult ret;
if (this.IsMap(out ret))
{
return ret;
}
return result;
}
bool IsMap(out TResult result)
{
result = default(TResult);
if (this._prevCase != null)
{
if (this._prevCase.IsMap(out result))
{
return true;
}
}
if (this._condition)
{
result = this._result;
return true;
}
return false;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--<TargetFramework>netstandard2.0</TargetFramework>-->
<!--<TargetFramework>net40</TargetFramework>-->
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
<Version>3.9.0</Version>
<AssemblyVersion>3.9.0.0</AssemblyVersion>
<FileVersion>3.9.0.0</FileVersion>
<Description>A lightweight and high-performance Object/Relational Mapping(ORM) library.</Description>
<PackageId>Chloe</PackageId>
<Product>Chloe.ORM</Product>
<Authors>Shuxin Qin</Authors>
<Copyright>Copyright 2016-2019.</Copyright>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>NETFX</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
</ItemGroup>
</Project>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe
{
public enum CompareType
{
/// <summary>
/// ==
/// </summary>
eq = 1,
/// <summary>
/// !=
/// </summary>
neq = 2,
/// <summary>
/// &gt;
/// </summary>
gt = 3,
/// <summary>
/// >=
/// </summary>
gte = 4,
/// <summary>
/// &lt;
/// </summary>
lt = 5,
/// <summary>
/// &lt;=
/// </summary>
lte = 6
}
}
using Chloe.Mapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chloe.Core
{
class DbCommandFactor
{
public DbCommandFactor(IObjectActivator objectActivator, string commandText, DbParam[] parameters)
{
this.ObjectActivator = objectActivator;
this.CommandText = commandText;
this.Parameters = parameters;
}
public IObjectActivator ObjectActivator { get; set; }
public string CommandText { get; set; }
public DbParam[] Parameters { get; set; }
}
}
using Chloe.Infrastructure.Interception;
using Chloe.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace Chloe.Core
{
class DbSession : IDbSession
{
DbContext _dbContext;
internal DbSession(DbContext dbContext)
{
this._dbContext = dbContext;
}
public IDbContext DbContext { get { return this._dbContext; } }
public IDbConnection CurrentConnection { get { return this._dbContext.AdoSession.DbConnection; } }
/// <summary>
/// 如果未开启事务,则返回 null
/// </summary>
public IDbTransaction CurrentTransaction { get { return this._dbContext.AdoSession.DbTransaction; } }
public bool IsInTransaction { get { return this._dbContext.AdoSession.IsInTransaction; } }
public int CommandTimeout { get { return this._dbContext.AdoSession.CommandTimeout; } set { this._dbContext.AdoSession.CommandTimeout = value; } }
public int ExecuteNonQuery(string cmdText, params DbParam[] parameters)
{
return this.ExecuteNonQuery(cmdText, CommandType.Text, parameters);
}
public int ExecuteNonQuery(string cmdText, CommandType cmdType, params DbParam[] parameters)
{
Utils.CheckNull(cmdText, "cmdText");
return this._dbContext.AdoSession.ExecuteNonQuery(cmdText, parameters, cmdType);
}
public int ExecuteNonQuery(string cmdText, object parameter)
{
return this.ExecuteNonQuery(cmdText, PublicHelper.BuildParams(this._dbContext, parameter));
}
public int ExecuteNonQuery(string cmdText, CommandType cmdType, object parameter)
{
return this.ExecuteNonQuery(cmdText, cmdType, PublicHelper.BuildParams(this._dbContext, parameter));
}
public object ExecuteScalar(string cmdText, params DbParam[] parameters)
{
return this.ExecuteScalar(cmdText, CommandType.Text, parameters);
}
public object ExecuteScalar(string cmdText, CommandType cmdType, params DbParam[] parameters)
{
Utils.CheckNull(cmdText, "cmdText");
return this._dbContext.AdoSession.ExecuteScalar(cmdText, parameters, cmdType);
}
public object ExecuteScalar(string cmdText, object parameter)
{
return this.ExecuteScalar(cmdText, PublicHelper.BuildParams(this._dbContext, parameter));
}
public object ExecuteScalar(string cmdText, CommandType cmdType, object parameter)
{
return this.ExecuteScalar(cmdText, cmdType, PublicHelper.BuildParams(this._dbContext, parameter));
}
public IDataReader ExecuteReader(string cmdText, params DbParam[] parameters)
{
return this.ExecuteReader(cmdText, CommandType.Text, parameters);
}
public IDataReader ExecuteReader(string cmdText, CommandType cmdType, params DbParam[] parameters)
{
Utils.CheckNull(cmdText, "cmdText");
return this._dbContext.AdoSession.ExecuteReader(cmdText, parameters, cmdType);
}
public IDataReader ExecuteReader(string cmdText, object parameter)
{
return this.ExecuteReader(cmdText, PublicHelper.BuildParams(this._dbContext, parameter));
}
public IDataReader ExecuteReader(string cmdText, CommandType cmdType, object parameter)
{
return this.ExecuteReader(cmdText, cmdType, PublicHelper.BuildParams(this._dbContext, parameter));
}
public void BeginTransaction()
{
this._dbContext.AdoSession.BeginTransaction(null);
}
public void BeginTransaction(IsolationLevel il)
{
this._dbContext.AdoSession.BeginTransaction(il);
}
public void CommitTransaction()
{
this._dbContext.AdoSession.CommitTransaction();
}
public void RollbackTransaction()
{
this._dbContext.AdoSession.RollbackTransaction();
}
public void AddInterceptor(IDbCommandInterceptor interceptor)
{
Utils.CheckNull(interceptor, "interceptor");
this._dbContext.AdoSession.DbCommandInterceptors.Add(interceptor);
}
public void RemoveInterceptor(IDbCommandInterceptor interceptor)
{
Utils.CheckNull(interceptor, "interceptor");
this._dbContext.AdoSession.DbCommandInterceptors.Remove(interceptor);
}
public void Dispose()
{
this._dbContext.Dispose();
}
}
}
using Chloe.Extensions;
using Chloe.InternalExtensions;
using Chloe.Mapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
namespace Chloe.Core.Emit
{
public static class ClassGenerator
{
static readonly Dictionary<Assembly, ModuleBuilder> _moduleBuilders = new Dictionary<Assembly, ModuleBuilder>();
static int _sequenceNumber = 0;
public static Type CreateMRMType(MemberInfo propertyOrField)
{
Type entityType = propertyOrField.DeclaringType;
Assembly assembly = entityType.GetAssembly();
ModuleBuilder moduleBuilder;
if (!_moduleBuilders.TryGetValue(assembly, out moduleBuilder))
{
lock (assembly)
{
if (!_moduleBuilders.TryGetValue(assembly, out moduleBuilder))
{
var assemblyName = new AssemblyName(String.Format(CultureInfo.InvariantCulture, "ChloeMRMs-{0}", assembly.FullName));
assemblyName.Version = new Version(1, 0, 0, 0);
AssemblyBuilder assemblyBuilder;
#if NETCORE
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
#elif NETFX
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
#endif
moduleBuilder = assemblyBuilder.DefineDynamicModule("ChloeMRMModule");
_moduleBuilders.Add(assembly, moduleBuilder);
}
}
}
TypeAttributes typeAttributes = TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.Sealed;
TypeBuilder tb = moduleBuilder.DefineType(string.Format("Chloe.Mapper.MRMs.{0}_{1}_{2}", entityType.Name, propertyOrField.Name, Guid.NewGuid().ToString("N").Substring(0, 5) + System.Threading.Interlocked.Increment(ref _sequenceNumber).ToString()), typeAttributes, null, new Type[] { typeof(IMRM) });
tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName);
MethodBuilder methodBuilder = tb.DefineMethod("Map", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(void), new Type[] { typeof(object), typeof(IDataReader), typeof(int) });
ILGenerator il = methodBuilder.GetILGenerator();
int parameStartIndex = 1;
il.Emit(OpCodes.Ldarg_S, parameStartIndex);//将第一个参数 object 对象加载到栈顶
il.Emit(OpCodes.Castclass, propertyOrField.DeclaringType);//将 object 对象转换为强类型对象 此时栈顶为强类型的对象
var readerMethod = DataReaderConstant.GetReaderMethod(ReflectionExtension.GetMemberType(propertyOrField));
//ordinal
il.Emit(OpCodes.Ldarg_S, parameStartIndex + 1); //加载参数DataReader
il.Emit(OpCodes.Ldarg_S, parameStartIndex + 2); //加载 read ordinal
il.EmitCall(OpCodes.Call, readerMethod, null); //调用对应的 readerMethod 得到 value reader.Getxx(ordinal); 此时栈顶为 value
EmitHelper.SetValueIL(il, propertyOrField); // object.XX = value; 此时栈顶为空
il.Emit(OpCodes.Ret); // 即可 return
Type t = tb.CreateType();
return t;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。 点击展开。
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。 点击展开。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论