升级2.0版本,支持Oracle数据库

This commit is contained in:
falcon 2021-12-04 11:34:01 +08:00
parent c2b8b3ee41
commit 70e1e4cf41
21 changed files with 581 additions and 264 deletions

4
src/.editorconfig Normal file
View File

@ -0,0 +1,4 @@
[*.cs]
# CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
dotnet_diagnostic.CS8618.severity = none

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Faclon.StoredProcedureRunner.Example.Database.sp;
using Microsoft.EntityFrameworkCore;
using Falcon.StoredProcedureRunner;
namespace Faclon.StoredProcedureRunner.Example.Database
{
public class MyDb:DbContext
{
public IRunner SpRunner { get; set; }
public MyDb(DbContextOptions options,IRunner spRunner) : base(options) {
this.SpRunner = spRunner;
}
public IEnumerable<Sp1_Result> RunSp1(Sp1 data) {
return this.SpRunner.Run<Sp1,Sp1_Result>(this,data);
}
public int RunSp1No(Sp1 data) {
return this.SpRunner.Execute(this,data);
}
}
}

View File

@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Falcon.StoredProcedureRunner;
namespace Faclon.StoredProcedureRunner.Example.Database.sp
{
/// <summary>
/// 测试用存储过程
/// </summary>
[FalconSPReturnType(typeof(Sp1_Result))]
[FalconSPProcuderName("TestSp1")]
public class Sp1
{
/// <summary>
/// 整数1
/// </summary>
public int P1 { get; set; } = 1;
/// <summary>
/// 整数2
/// </summary>
public int P2 { get; set; } = 2;
/// <summary>
/// 字符串P3
/// </summary>
[FalconSPPrarmType(System.Data.SqlDbType.VarChar)]
public string P3 { get; set; } = "abcd";
}
/// <summary>
/// 存储过程执行结果
/// </summary>
public class Sp1_Result
{
/// <summary>
/// 结果行号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 求和
/// </summary>
public int Jia { get; set; }
/// <summary>
/// 求差
/// </summary>
public int Jian { get; set; }
/// <summary>
/// 求乘积
/// </summary>
public int Chen { get; set; }
/// <summary>
/// 求除法
/// </summary>
public double Chu { get; set; }
/// <summary>
/// 字符串返回值
/// </summary>
public string s { get; set; }
}
}

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net5;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Falcon.StoredProcedureRunner\Falcon.StoredProcedureRunner.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.4" />
</ItemGroup>
</Project>

View File

@ -1,34 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Faclon.StoredProcedureRunner.Example.Database;
using Falcon.StoredProcedureRunner;
using Microsoft.EntityFrameworkCore;
namespace Faclon.StoredProcedureRunner.Example
{
class Program
{
static void Main(string[] args) {
IRunner runner = new Runner();
var conStr = "Server =.\\SQLSERVER2008R2;Database = test;User ID = sa;Password = 111";
var opb = new DbContextOptionsBuilder();
opb.UseSqlServer(conStr);
var db = new MyDb(opb.Options,runner);
Console.WriteLine("测试调用存储过程,获取返回值");
var r = db.RunSp1(new Database.sp.Sp1());
Console.WriteLine("返回记录数{0},应该为2",r.Count());
var fir = r.First();
Console.WriteLine("Id为{0},应该为1",fir.Id);
Console.WriteLine("Jia{0},应该为3",fir.Jia);
Console.WriteLine("Jian{0},应该为-1",fir.Jian);
Console.WriteLine("Chen{0},应该为2",fir.Chen);
Console.WriteLine("Chu{0},应该为0.5",fir.Chu);
Console.WriteLine("s{0},应该为abc1",fir.s);
Console.WriteLine("测试无返回值调用");
var r1 = db.RunSp1No(new Database.sp.Sp1());
Console.WriteLine("返回结果{0}",r1);
}
}
}

View File

@ -1,11 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Falcon.StoredProcedureRunner", "Falcon.StoredProcedureRunner\Falcon.StoredProcedureRunner.csproj", "{13D3139B-60C2-4785-ADCB-4F839BDEC3C4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Falcon.StoredProcedureRunner", "Falcon.StoredProcedureRunner\Falcon.StoredProcedureRunner.csproj", "{57A72FF8-1FA8-47A1-8F96-30740890C877}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faclon.StoredProcedureRunner.Example", "Faclon.StoredProcedureRunner.Example\Faclon.StoredProcedureRunner.Example.csproj", "{40610016-0C9C-462D-B352-49D6C33DA5FC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Falcon.StoredProcedureRunnerTests", "Falcon.StoredProcedureRunnerTests\Falcon.StoredProcedureRunnerTests.csproj", "{E872783D-5387-49BE-9845-7F755F29696E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C43175B4-F376-4DC3-B46E-CCD1E6ADE67D}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -13,19 +18,19 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{13D3139B-60C2-4785-ADCB-4F839BDEC3C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13D3139B-60C2-4785-ADCB-4F839BDEC3C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13D3139B-60C2-4785-ADCB-4F839BDEC3C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13D3139B-60C2-4785-ADCB-4F839BDEC3C4}.Release|Any CPU.Build.0 = Release|Any CPU
{40610016-0C9C-462D-B352-49D6C33DA5FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40610016-0C9C-462D-B352-49D6C33DA5FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40610016-0C9C-462D-B352-49D6C33DA5FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40610016-0C9C-462D-B352-49D6C33DA5FC}.Release|Any CPU.Build.0 = Release|Any CPU
{57A72FF8-1FA8-47A1-8F96-30740890C877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57A72FF8-1FA8-47A1-8F96-30740890C877}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57A72FF8-1FA8-47A1-8F96-30740890C877}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57A72FF8-1FA8-47A1-8F96-30740890C877}.Release|Any CPU.Build.0 = Release|Any CPU
{E872783D-5387-49BE-9845-7F755F29696E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E872783D-5387-49BE-9845-7F755F29696E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E872783D-5387-49BE-9845-7F755F29696E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E872783D-5387-49BE-9845-7F755F29696E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7ECD6C47-0547-4FB7-A481-829D28302EFD}
SolutionGuid = {19EB0FAF-B61A-422D-90AC-A602956F6875}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,17 @@
using System;
namespace Falcon.StoredProcedureRunner
{
/// <summary>
/// 设置返回对象值时候发生异常
/// </summary>
public class DatabaseNotSupportedException : Exception
{
/// <summary>
/// 实例化不支持的数据库对象异常
/// </summary>
public DatabaseNotSupportedException() : base("仅仅支持Oracle和SqlServer数据库")
{
}
}
}

View File

@ -1,33 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net5;netstandard2.1;netstandard2.0;</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.4.0</Version>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<PackageProjectUrl>https://github.com/FalconWu2017/Falcon.StoredProcedureRunner</PackageProjectUrl>
<RepositoryUrl>https://github.com/FalconWu2017/Falcon.StoredProcedureRunner</RepositoryUrl>
<Description>EF Core 存储过程执行组件可以按照ORM方式执行存储过程</Description>
<Authors>Falcon</Authors>
<TargetFrameworks>net5.0</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.0.0</Version>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<PackageProjectUrl>https://github.com/FalconWu2017/Falcon.StoredProcedureRunner</PackageProjectUrl>
<RepositoryUrl>https://github.com/FalconWu2017/Falcon.StoredProcedureRunner</RepositoryUrl>
<Description>EF Core 存储过程执行组件可以按照ORM方式执行存储过程</Description>
<Authors>Falcon</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.2" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.4" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.13" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.9" />
<PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.4" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,207 @@
namespace Falcon.StoredProcedureRunner
{
/// <summary>
/// 定义数据库数据类型
/// </summary>
public enum FalconSPDbType
{
//
// 摘要:
// System.Int64. A 64-bit signed integer.
SqlServerBigInt = 0,
//
// 摘要:
// System.Array of type System.Byte. A fixed-length stream of binary data ranging
// between 1 and 8,000 bytes.
SqlServerBinary = 1,
//
// 摘要:
// System.Boolean. An unsigned numeric value that can be 0, 1, or null.
SqlServerBit = 2,
//
// 摘要:
// System.String. A fixed-length stream of non-Unicode characters ranging between
// 1 and 8,000 characters.
SqlServerChar = 3,
//
// 摘要:
// System.DateTime. Date and time data ranging in value from January 1, 1753 to
// December 31, 9999 to an accuracy of 3.33 milliseconds.
SqlServerDateTime = 4,
//
// 摘要:
// System.Decimal. A fixed precision and scale numeric value between -10 38 -1 and
// 10 38 -1.
SqlServerDecimal = 5,
//
// 摘要:
// System.Double. A floating point number within the range of -1.79E +308 through
// 1.79E +308.
SqlServerFloat = 6,
//
// 摘要:
// System.Array of type System.Byte. A variable-length stream of binary data ranging
// from 0 to 2 31 -1 (or 2,147,483,647) bytes.
SqlServerImage = 7,
//
// 摘要:
// System.Int32. A 32-bit signed integer.
SqlServerInt = 8,
//
// 摘要:
// System.Decimal. A currency value ranging from -2 63 (or -9,223,372,036,854,775,808)
// to 2 63 -1 (or +9,223,372,036,854,775,807) with an accuracy to a ten-thousandth
// of a currency unit.
SqlServerMoney = 9,
//
// 摘要:
// System.String. A fixed-length stream of Unicode characters ranging between 1
// and 4,000 characters.
SqlServerNChar = 10,
//
// 摘要:
// System.String. A variable-length stream of Unicode data with a maximum length
// of 2 30 - 1 (or 1,073,741,823) characters.
SqlServerNText = 11,
//
// 摘要:
// System.String. A variable-length stream of Unicode characters ranging between
// 1 and 4,000 characters. Implicit conversion fails if the string is greater than
// 4,000 characters. Explicitly set the object when working with strings longer
// than 4,000 characters. Use System.Data.SqlDbType.NVarChar when the database column
// is nvarchar(max).
SqlServerNVarChar = 12,
//
// 摘要:
// System.Single. A floating point number within the range of -3.40E +38 through
// 3.40E +38.
SqlServerReal = 13,
//
// 摘要:
// System.Guid. A globally unique identifier (or GUID).
SqlServerUniqueIdentifier = 14,
//
// 摘要:
// System.DateTime. Date and time data ranging in value from January 1, 1900 to
// June 6, 2079 to an accuracy of one minute.
SqlServerSmallDateTime = 0xF,
//
// 摘要:
// System.Int16. A 16-bit signed integer.
SqlServerSmallInt = 0x10,
//
// 摘要:
// System.Decimal. A currency value ranging from -214,748.3648 to +214,748.3647
// with an accuracy to a ten-thousandth of a currency unit.
SqlServerSmallMoney = 17,
//
// 摘要:
// System.String. A variable-length stream of non-Unicode data with a maximum length
// of 2 31 -1 (or 2,147,483,647) characters.
SqlServerText = 18,
//
// 摘要:
// System.Array of type System.Byte. Automatically generated binary numbers, which
// are guaranteed to be unique within a database. timestamp is used typically as
// a mechanism for version-stamping table rows. The storage size is 8 bytes.
SqlServerTimestamp = 19,
//
// 摘要:
// System.Byte. An 8-bit unsigned integer.
SqlServerTinyInt = 20,
//
// 摘要:
// System.Array of type System.Byte. A variable-length stream of binary data ranging
// between 1 and 8,000 bytes. Implicit conversion fails if the byte array is greater
// than 8,000 bytes. Explicitly set the object when working with byte arrays larger
// than 8,000 bytes.
SqlServerVarBinary = 21,
//
// 摘要:
// System.String. A variable-length stream of non-Unicode characters ranging between
// 1 and 8,000 characters. Use System.Data.SqlDbType.VarChar when the database column
// is varchar(max).
SqlServerVarChar = 22,
//
// 摘要:
// System.Object. A special data type that can contain numeric, string, binary,
// or date data as well as the SQL Server values Empty and Null, which is assumed
// if no other type is declared.
SqlServerVariant = 23,
//
// 摘要:
// An XML value. Obtain the XML as a string using the System.Data.SqlClient.SqlDataReader.GetValue(System.Int32)
// method or System.Data.SqlTypes.SqlXml.Value property, or as an System.Xml.XmlReader
// by calling the System.Data.SqlTypes.SqlXml.CreateReader method.
SqlServerXml = 25,
//
// 摘要:
// A SQL Server user-defined type (UDT).
SqlServerUdt = 29,
//
// 摘要:
// A special data type for specifying structured data contained in table-valued
// parameters.
SqlServerStructured = 30,
//
// 摘要:
// Date data ranging in value from January 1,1 AD through December 31, 9999 AD.
SqlServerDate = 0x1F,
//
// 摘要:
// Time data based on a 24-hour clock. Time value range is 00:00:00 through 23:59:59.9999999
// with an accuracy of 100 nanoseconds. Corresponds to a SQL Server time value.
SqlServerTime = 0x20,
//
// 摘要:
// Date and time data. Date value range is from January 1,1 AD through December
// 31, 9999 AD. Time value range is 00:00:00 through 23:59:59.9999999 with an accuracy
// of 100 nanoseconds.
SqlServerDateTime2 = 33,
//
// 摘要:
// Date and time data with time zone awareness. Date value range is from January
// 1,1 AD through December 31, 9999 AD. Time value range is 00:00:00 through 23:59:59.9999999
// with an accuracy of 100 nanoseconds. Time zone value range is -14:00 through
// +14:00.
SqlServerDateTimeOffset = 34,
OracleBFile = 101,
OracleBlob = 102,
OracleByte = 103,
OracleChar = 104,
OracleClob = 105,
OracleDate = 106,
OracleDecimal = 107,
OracleDouble = 108,
OracleLong = 109,
OracleLongRaw = 110,
OracleInt16 = 111,
OracleInt32 = 112,
OracleInt64 = 113,
OracleIntervalDS = 114,
OracleIntervalYM = 115,
OracleNClob = 116,
OracleNChar = 117,
OracleNVarchar2 = 119,
OracleRaw = 120,
OracleRefCursor = 121,
OracleSingle = 122,
OracleTimeStamp = 123,
OracleTimeStampLTZ = 124,
OracleTimeStampTZ = 125,
OracleVarchar2 = 126,
OracleXmlType = 0x7F,
OracleArray = 0x80,
OracleObject = 129,
OracleRef = 130,
OracleBinaryDouble = 132,
OracleBinaryFloat = 133,
OracleBoolean = 134,
OracleJson = 135
}
}

View File

@ -5,8 +5,8 @@ namespace Falcon.StoredProcedureRunner
/// <summary>
/// 表示调用时候忽略此属性
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class FalconSPIgnoreAttribute:Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FalconSPIgnoreAttribute : Attribute
{
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Data;
namespace Falcon.StoredProcedureRunner
{
/// <summary>
/// 定义存储过程参数方向。默认Input
/// </summary>
[AttributeUsage(AttributeTargets.Property,AllowMultiple =false,Inherited =false)]
public class FalconSPPrarmDirectionAttribute:Attribute
{
/// <summary>
/// 参数方向
/// </summary>
public ParameterDirection Direction { get; }
/// <summary>
/// 定义参数方向
/// </summary>
/// <param name="direction"></param>
public FalconSPPrarmDirectionAttribute(ParameterDirection direction)
=> this.Direction = direction;
}
}

View File

@ -5,6 +5,7 @@ namespace Falcon.StoredProcedureRunner
/// <summary>
/// 定义名称
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FalconSPPrarmNameAttribute:Attribute
{
/// <summary>

View File

@ -1,21 +1,21 @@
using System;
using System.Data;
namespace Falcon.StoredProcedureRunner
{
/// <summary>
/// 定义存储过程参数类型
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FalconSPPrarmTypeAttribute:Attribute
{
/// <summary>
/// 参数名
/// </summary>
public SqlDbType PType { get; set; }
public FalconSPDbType PType { get; set; }
/// <summary>
/// 定于存储过程参数名称
/// </summary>
/// <param name="pType">参数类型</param>
public FalconSPPrarmTypeAttribute(SqlDbType pType) { this.PType = pType; }
/// <param name="pDbType">参数类型.DbType</param>
public FalconSPPrarmTypeAttribute(FalconSPDbType pDbType) { this.PType = pDbType; }
}
}

View File

@ -45,8 +45,8 @@ namespace Falcon.StoredProcedureRunner
return runner.Run(db,typeof(TPrarmType),typeof(TReturnType),data).Cast<TReturnType>();
} catch(InvalidCastException ice) {
throw new ReturnTypeCastException(ice);
} catch(Exception ex) {
throw ex;
} catch(Exception) {
throw;
}
}

View File

@ -6,7 +6,7 @@ namespace Falcon.StoredProcedureRunner
/// <summary>
/// 设置返回对象值时候发生异常
/// </summary>
public class ReturnDataSetValueException:Exception
public class ReturnDataSetValueException : Exception
{
/// <summary>
/// 实例化一个给返回数据设置值的异常
@ -16,7 +16,7 @@ namespace Falcon.StoredProcedureRunner
/// <param name="pi">要设置值的属性</param>
/// <param name="value">要设置的值</param>
/// <param name="innException">内部异常</param>
public ReturnDataSetValueException(int rowId,string cName, PropertyInfo pi,object value,Exception innException)
: base($"存储过程返回第[{rowId}]行[{cName}]列数据值为({value.GetType().FullName})[{value}]无法赋给属性({pi.PropertyType.FullName})[{pi.Name}]。",innException) { }
public ReturnDataSetValueException(int rowId, string cName, PropertyInfo pi, object value, Exception innException)
: base($"存储过程返回第[{rowId}]行[{cName}]列数据值为({value.GetType().FullName})[{value}]无法赋给属性({pi.PropertyType.FullName})[{pi.Name}]。", innException) { }
}
}

View File

@ -1,19 +1,20 @@
using System;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
namespace Falcon.StoredProcedureRunner
{
/// <summary>
/// 存储过程执行
/// </summary>
public partial class Runner:IRunner
public partial class Runner : IRunner
{
/// <summary>
/// 执行无返回值的存储过程
@ -21,12 +22,17 @@ namespace Falcon.StoredProcedureRunner
/// <typeparam name="TPrarmType">参数类型</typeparam>
/// <param name="db">数据上下文</param>
/// <param name="data">参数数据</param>
public int Execute<TPrarmType>(DbContext db,TPrarmType data) {
var parms = getParams(typeof(TPrarmType),data).ToArray();
var pName = getProcuderName<TPrarmType>();
var paramStr = getParamStr(typeof(TPrarmType),data);
var str = $"exec {pName} {paramStr}";
return db.Database.ExecuteSqlRaw(str,parms);
public int Execute<TPrarmType>(DbContext db, TPrarmType data)
{
throw new NotSupportedException();
//var parms = getParams(db, typeof(TPrarmType), data).ToArray();
//var pName = getProcuderName<TPrarmType>();
//var conn = db.Database.GetDbConnection();
//var paramStr = getParamStr(typeof(TPrarmType), data);
//var str = $"exec {pName} {paramStr}";
//return db.Database.ExecuteSqlRaw(str, parms);
}
/// <summary>
@ -37,33 +43,40 @@ namespace Falcon.StoredProcedureRunner
/// <param name="returnType">返回值类型</param>
/// <param name="data">存储过程参数</param>
/// <returns>查询结果枚举</returns>
public IEnumerable<object> Run(DbContext db,Type prarmType,Type returnType,object data) {
public IEnumerable<object> Run(DbContext db, Type prarmType, Type returnType, object data)
{
var pm = getProcuderName(prarmType);
var paras = getParams(prarmType,data).ToArray();
var paras = getParams(db, prarmType, data).ToArray();
var connection = db.Database.GetDbConnection();
using(var cmd = connection.CreateCommand()) {
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = pm;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddRange(paras);
connection.Open();
var dr = cmd.ExecuteReader();
var result = new List<object>();
if(!dr.CanGetColumnSchema())
if (!dr.CanGetColumnSchema())
return result;
int rowId = 0;
while(dr.Read()) {
while (dr.Read())
{
var item = returnType.Assembly.CreateInstance(returnType.FullName);
var columnSchema = dr.GetColumnSchema();
for(var i = 0;i < columnSchema.Count;i++) {
for (var i = 0; i < columnSchema.Count; i++)
{
var name = dr.GetName(i);
var value = dr.IsDBNull(i) ? null : dr.GetValue(i);
var pi = getProperty(returnType,name);
if(pi == null || !pi.CanWrite)
var pi = getProperty(returnType, name);
if (pi == null || !pi.CanWrite)
continue;
try {
pi.SetValue(item,value);
} catch(Exception ex) {
throw new ReturnDataSetValueException(rowId,name,pi,value,ex);
try
{
pi.SetValue(item, value);
}
catch (Exception ex)
{
throw new ReturnDataSetValueException(rowId, name, pi, value, ex);
}
}
result.Add(item);
@ -80,20 +93,24 @@ namespace Falcon.StoredProcedureRunner
/// <param name="db">数据上下文</param>
/// <param name="sql">要执行的sql语句</param>
/// <returns>数据库返回值json格式</returns>
public string RunRaw(DbContext db,string sql) {
public string RunRaw(DbContext db, string sql)
{
var connection = db.Database.GetDbConnection();
using(var cmd = connection.CreateCommand()) {
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandType = System.Data.CommandType.Text;
connection.Open();
var dr = cmd.ExecuteReader();
var result = new StringBuilder();
if(!dr.CanGetColumnSchema())
if (!dr.CanGetColumnSchema())
return "";
while(dr.Read()) {
while (dr.Read())
{
var item = new StringBuilder();
var columnSchema = dr.GetColumnSchema();
for(var i = 0;i < columnSchema.Count;i++) {
for (var i = 0; i < columnSchema.Count; i++)
{
var name = dr.GetName(i);
var value = dr.IsDBNull(i) ? null : dr.GetValue(i);
item.Append($"\"{name}\":\"{value}\",");
@ -115,12 +132,10 @@ namespace Falcon.StoredProcedureRunner
/// 获取存储过程名
/// </summary>
/// <param name="pramType">参数类型</param>
private static string getProcuderName(Type pramType) {
private static string getProcuderName(Type pramType)
{
var attr = pramType.GetCustomAttribute<FalconSPProcuderNameAttribute>();
if(attr != null && attr is FalconSPProcuderNameAttribute pna && !string.IsNullOrEmpty(pna.ProcuderName)) {
return pna.ProcuderName;
}
return pramType.Name;
return attr?.ProcuderName ?? pramType.Name;
}
/// <summary>
@ -128,20 +143,25 @@ namespace Falcon.StoredProcedureRunner
/// </summary>
///<param name="type">数据的类型</param>
/// <param name="data">参数实例</param>
private static IEnumerable<SqlParameter> getParams(Type type,object data) {
if(data == null)
private static IEnumerable<IDataParameter> getParams(DbContext db, Type type, object data)
{
if (data == null)
yield break;
foreach(var p in type.GetProperties()) {
if(!p.CanRead || ignoreProp(p))
var fixC =
db.Database.IsOracle() ? ":" :
db.Database.IsSqlServer() ? "@" :
throw new DatabaseNotSupportedException();
foreach (var p in type.GetProperties())
{
if (!p.CanRead || isIgnoreProp(p))
continue;
var name = getPrarmName(p, fixC);
var val = p.GetValue(data);
var pt = getPrarmType(p);
if(pt.HasValue) {
var np = new SqlParameter($"@{getPrarmName(p)}",pt.Value);
np.Value = p.GetValue(data);
yield return np;
} else {
yield return new SqlParameter($"@{getPrarmName(p)}",p.GetValue(data));
}
var para = CreateDbParameter(db, name, val, pt);
para.Direction = GetParaDirection(p);
yield return para;
}
}
@ -149,19 +169,61 @@ namespace Falcon.StoredProcedureRunner
/// 获取存储过程参数类型
/// </summary>
/// <param name="p">对应的属性</param>
private static SqlDbType? getPrarmType(PropertyInfo p) {
var np = p.GetCustomAttribute<FalconSPPrarmTypeAttribute>(true);
if(np != null && np is FalconSPPrarmTypeAttribute na) {
return na.PType;
private static int? getPrarmType(PropertyInfo p)
{
var np = p.GetCustomAttribute<FalconSPPrarmTypeAttribute>();
if (np != null && np is FalconSPPrarmTypeAttribute na)
{
return (int)np.PType;
}
return null;
}
/// <summary>
/// 创建存储过程参数
/// </summary>
/// <param name="db">数据库上下文</param>
/// <param name="name">参数名称</param>
/// <param name="val">参数值</param>
/// <returns>参数</returns>
private static IDataParameter CreateDbParameter(DbContext db, string name, object val, int? type)
{
var dbf = db.Database;
if (type.HasValue)
{
IDataParameter pra =
dbf.IsOracle() ? new OracleParameter(name, (OracleDbType)type) :
dbf.IsSqlServer() ? new SqlParameter(name, (SqlDbType)type) :
throw new DatabaseNotSupportedException();
pra.Value = val;
return pra;
}
else
{
return
dbf.IsSqlServer() ? new SqlParameter(name, val) :
dbf.IsOracle() ? new OracleParameter(name, val) :
throw new DatabaseNotSupportedException();
}
}
/// <summary>
/// 获取参数的方向。默认Input
/// </summary>
/// <param name="p">参数映射属性</param>
/// <returns>方向或null</returns>
private static ParameterDirection GetParaDirection(PropertyInfo p)
{
var attr = p.GetCustomAttribute<FalconSPPrarmDirectionAttribute>();
return attr == null ? ParameterDirection.Input : attr.Direction;
}
/// <summary>
/// 是否忽略属性
/// </summary>
/// <param name="p">要检查的属性</param>
private static bool ignoreProp(PropertyInfo p) {
private static bool isIgnoreProp(PropertyInfo p)
{
return p.GetCustomAttribute<FalconSPIgnoreAttribute>(true) != null;
}
@ -169,34 +231,29 @@ namespace Falcon.StoredProcedureRunner
/// 获取存储过程参数名称
/// </summary>
/// <param name="p">对应的属性</param>
private static string getPrarmName(PropertyInfo p) {
private static string getPrarmName(PropertyInfo p, string prefixChar)
{
var np = p.GetCustomAttribute<FalconSPPrarmNameAttribute>(true);
if(np != null && np is FalconSPPrarmNameAttribute na) {
return na.Name;
if (np != null && np is FalconSPPrarmNameAttribute na)
{
var name = na.Name;
return name.StartsWith(prefixChar) ? name : prefixChar + name;
}
return p.Name;
return prefixChar + p.Name;
}
/// <summary>
/// 获取存储过程名
/// </summary>
/// <typeparam name="T">参数模型</typeparam>
private static string getProcuderName<T>() {
var attr = typeof(T).GetCustomAttribute<FalconSPProcuderNameAttribute>(true);
if(attr != null && attr is FalconSPProcuderNameAttribute pna && !string.IsNullOrEmpty(pna.ProcuderName)) {
return pna.ProcuderName;
}
return typeof(T).Name;
}
/// <summary>
/// 忽略大小写获取类型的属性
/// </summary>
/// <param name="t">类型</param>
/// <param name="name">属性名称</param>
/// <returns>属性</returns>
private static PropertyInfo getProperty(Type t,string name) {
foreach(var item in t.GetProperties()) {
if(item.Name.ToLower() == name.ToLower()) {
private static PropertyInfo getProperty(Type t, string name)
{
foreach (var item in t.GetProperties())
{
if (item.Name.ToLower() == name.ToLower())
{
return item;
}
}
@ -209,14 +266,14 @@ namespace Falcon.StoredProcedureRunner
/// <param name="type">参数类型</param>
/// <param name="data">参数对象</param>
/// <returns>一个参数字符串。比如@p2=@p4,@p1=@p3</returns>
private static string getParamStr(Type type,object data) {
var paras = getParams(type,data).ToArray();
var result = " ";
for(int i = 0;i < paras.Count();i++) {
result += $"{paras[i].ParameterName}={{{i}}},";
}
return result.TrimEnd(',');
}
//private static string getParamStr(Type type,object data) {
// var paras = getParams(type,data).ToArray();
// var result = " ";
// for(int i = 0;i < paras.Count();i++) {
// result += $"{paras[i].ParameterName}={{{i}}},";
// }
// return result.TrimEnd(',');
//}
}
}

View File

@ -0,0 +1,7 @@
{
"db": {
"ver": "11",
"oracle": "DATA SOURCE=(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST =47.103.62.60)(PORT = 1521)))(CONNECT_DATA = (SERVICE_NAME = orcl)));PASSWORD = harmonyhis;PERSIST SECURITY INFO = True;USER ID = HARMONYHIS;Connection Lifetime = 120;Connection Timeout = 60",
"sqlserver": "Server=.\\SQLSERVER2008R2;Database=test;User ID=sa;Password=111;"
}
}

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net5.0</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.9" />
<PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Falcon.StoredProcedureRunner\Falcon.StoredProcedureRunner.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="AppSettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,20 @@
using Falcon.StoredProcedureRunner;
using System.Data;
namespace Falcon.StoredProcedureRunnerTests
{
internal class GetEmployee
{
public string v_orgaid { get; set; }
[FalconSPPrarmDirection(ParameterDirection.Output)]
[FalconSPPrarmType(FalconSPDbType.OracleRefCursor)]
public object v_data { get; set; }
}
internal class GetEmployeeResult
{
public string empcode { get; set; }
public string empname { get; set; }
public string empactive { get; set; }
}
}

View File

@ -0,0 +1,60 @@
using Falcon.StoredProcedureRunnerTests;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace Falcon.StoredProcedureRunner.Tests
{
[TestClass()]
public class RunnerTests
{
[TestMethod()]
public void RunTest()
{
OracleTest();
SqlserverTest();
}
public void SqlserverTest()
{
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("AppSettings.json");
var config = configurationBuilder.Build();
var sql = config.GetSection("db:sqlserver").Value;
var buider = new DbContextOptionsBuilder();
var db = new DbContext(buider.UseSqlServer(sql).Options);
IRunner runner = new Runner();
var result = runner.Run<SqlserverModel, SqlserverModelResult>(db, new SqlserverModel
{
p1 = 1,
p2 = 2,
p3 = "abc,"
}).ToList();
Assert.IsNotNull(result);
CollectionAssert.AllItemsAreNotNull(result);
Assert.IsTrue(result.Count > 0);
}
public void OracleTest()
{
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("AppSettings.json");
var config = configurationBuilder.Build();
var ora = config.GetSection("db:oracle").Value;
var oraVer = config.GetSection("db:ver").Value;
var buider = new DbContextOptionsBuilder();
var db = new DbContext(buider.UseOracle(ora, o => o.UseOracleSQLCompatibility(oraVer)).Options);
IRunner runner = new Runner();
var result = runner.Run<GetEmployee, GetEmployeeResult>(db, new GetEmployee
{
v_orgaid = "50e3d44d-9ca2-4fbd-9d5d-d32339b1b113",
}).ToList();
Assert.IsNotNull(result);
CollectionAssert.AllItemsAreNotNull(result);
Assert.IsTrue(result.Count > 0);
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Falcon.StoredProcedureRunnerTests
{
[Falcon.StoredProcedureRunner.FalconSPProcuderName("TestSp1")]
public class SqlserverModel
{
public int p1 { get; set; }
public int p2 { get; set; }
public string p3 { get; set; }
}
public class SqlserverModelResult
{
public double Id { get; set; }
public string s { get; set; }
public double jia { get; set; }
public double jian { get; set; }
public double chen { get; set; }
public double chu { get; set; }
}
}