diff --git a/Sources/DbUtility.sln b/Sources/DbUtility.sln index 3e2bb28..3b57941 100644 --- a/Sources/DbUtility.sln +++ b/Sources/DbUtility.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ivony.Data.Logs", "Ivony.Da EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerformanceTest", "PerformanceTest\PerformanceTest.csproj", "{EF894E7A-779D-483C-89F1-61541833DD34}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ivony.Data.Access", "Ivony.Data.Access\Ivony.Data.Access.csproj", "{B812CDE1-193C-4741-AEDC-D791A6848ABC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {EF894E7A-779D-483C-89F1-61541833DD34}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF894E7A-779D-483C-89F1-61541833DD34}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF894E7A-779D-483C-89F1-61541833DD34}.Release|Any CPU.Build.0 = Release|Any CPU + {B812CDE1-193C-4741-AEDC-D791A6848ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B812CDE1-193C-4741-AEDC-D791A6848ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B812CDE1-193C-4741-AEDC-D791A6848ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B812CDE1-193C-4741-AEDC-D791A6848ABC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sources/Ivony.Data.Access/AccessClient/AccessDbConfiguration.cs b/Sources/Ivony.Data.Access/AccessClient/AccessDbConfiguration.cs new file mode 100644 index 0000000..5d04ee2 --- /dev/null +++ b/Sources/Ivony.Data.Access/AccessClient/AccessDbConfiguration.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ivony.Data; + +namespace Ivony.Data.Access.AccessClient +{ + public class AccessDbConfiguration:DbConfiguration + { + public AccessDbConfiguration() + { + } + } +} diff --git a/Sources/Ivony.Data.Access/AccessClient/AccessDbExecuteContext.cs b/Sources/Ivony.Data.Access/AccessClient/AccessDbExecuteContext.cs new file mode 100644 index 0000000..1e79257 --- /dev/null +++ b/Sources/Ivony.Data.Access/AccessClient/AccessDbExecuteContext.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ivony.Data.Common; +using System.Data.OleDb; + +namespace Ivony.Data.Access.AccessClient +{ + public class AccessDbExecuteContext:DbExecuteContextBase + { + + public AccessDbExecuteContext(OleDbDataReader dataReader, IDbTracing tracing, object sync) + : base(dataReader, tracing, sync: sync) + { + AcccessDataReader = dataReader; + } + + + public OleDbDataReader AcccessDataReader + { + get; + private set; + } + + } +} diff --git a/Sources/Ivony.Data.Access/AccessClient/AccessDbExecutor.cs b/Sources/Ivony.Data.Access/AccessClient/AccessDbExecutor.cs new file mode 100644 index 0000000..a0cf14a --- /dev/null +++ b/Sources/Ivony.Data.Access/AccessClient/AccessDbExecutor.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Data.OleDb; +using Ivony.Data.Common; +using Ivony.Data.Queries; + +namespace Ivony.Data.Access.AccessClient +{ + public class AccessDbExecutor : DbExecutorBase, IDbExecutor + { + + public AccessDbExecutor(string connectionString, AccessDbConfiguration configuration) + : base(configuration) + { + if(string.IsNullOrEmpty(connectionString)) + throw new ArgumentNullException("connectionString"); + if(configuration == null) + throw new ArgumentNullException("configuration"); + + Configuration = configuration; + Connection = new OleDbConnection(connectionString); + } + + + public OleDbConnection Connection { get; private set; } + + + protected AccessDbConfiguration Configuration { get; private set; } + + public object SyncRoot { get; private set; } + + public IDbExecuteContext Execute(ParameterizedQuery query) + { + var tracing = TryCreateTracing(this, query); + var command = new AccessDbParameterizedQueryParser().Parse(query); + return Execue(command, tracing); + } + + private IDbExecuteContext Execue(OleDbCommand command, IDbTracing tracing) + { + try + { + TryExecuteTracing(tracing, t => t.OnExecuting(command)); + + if (Connection.State == ConnectionState.Closed) + Connection.Open(); + command.Connection = Connection; + + if (Configuration.QueryExecutingTimeout.HasValue) + command.CommandTimeout = (int)Configuration.QueryExecutingTimeout.Value.TotalSeconds; + + var context = new AccessDbExecuteContext(command.ExecuteReader(), tracing, SyncRoot); + + TryExecuteTracing(tracing, t => t.OnLoadingData(context)); + return context; + + } + catch (DbException exception) + { + TryExecuteTracing(tracing, t => t.OnException(exception)); + throw; + } + } + + + + } +} diff --git a/Sources/Ivony.Data.Access/AccessClient/AccessDbParameterizedQueryParser.cs b/Sources/Ivony.Data.Access/AccessClient/AccessDbParameterizedQueryParser.cs new file mode 100644 index 0000000..93f1470 --- /dev/null +++ b/Sources/Ivony.Data.Access/AccessClient/AccessDbParameterizedQueryParser.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Data.OleDb; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ivony.Data; +using Ivony.Data.Common; + +namespace Ivony.Data.Access.AccessClient +{ + public class AccessDbParameterizedQueryParser:ParameterizedQueryParser + { + protected override string GetParameterPlaceholder(object value, int index, out OleDbParameter parameter) + { + var name = "?"; + parameter = new OleDbParameter(name, value); + + return name; + } + + protected override OleDbCommand CreateCommand(string commandText, OleDbParameter[] parameters) + { + var command = new OleDbCommand(commandText); + command.Parameters.AddRange(parameters); + + return command; + } + } +} diff --git a/Sources/Ivony.Data.Access/AccessDb.cs b/Sources/Ivony.Data.Access/AccessDb.cs new file mode 100644 index 0000000..0e4e87c --- /dev/null +++ b/Sources/Ivony.Data.Access/AccessDb.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data.OleDb; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ivony.Data.Access.AccessClient; +namespace Ivony.Data.Access +{ + public static class AccessDb + { + static AccessDb() + { + DefaultConfiguration = new AccessDbConfiguration(); + } + + public static AccessDbConfiguration DefaultConfiguration { get; private set; } + + public static AccessDbExecutor ConnectFile(string filePath, bool create = true, AccessDbConfiguration configuration = null) + { + if (string.IsNullOrEmpty(filePath)) + return null; + + if (!File.Exists(filePath)) + { + if (create) + CreateAccessDb(filePath); + else + { + throw new FileNotFoundException("The database file can't exist."); + } + } + var builder = new OleDbConnectionStringBuilder + { + DataSource = filePath, + Provider = "Microsoft.JET.OLEDB.4.0", + PersistSecurityInfo = false, + }; + + return Connect(builder.ConnectionString, configuration ?? DefaultConfiguration); + } + + public static AccessDbExecutor Connect(string connectionString, AccessDbConfiguration configuration = null) + { + return new AccessDbExecutor(connectionString, configuration); + } + + public static bool CreateAccessDb(string filePath, bool overwrite = false) + { + if (string.IsNullOrEmpty(filePath)) + throw new ArgumentNullException(filePath); + + if (File.Exists(filePath)) + { + if(overwrite) + File.Delete(filePath); + else + { + throw new InvalidOperationException("File Already existed."); + } + } + + try + { + + //Reference:http://www.cnblogs.com/DasonKwok/archive/2012/08/02/2620194.html + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + + var stream = assembly.GetManifestResourceStream("Ivony.Data.Access.EmbedResource.emptyDb.mdb"); + if (stream != null) + { + var dataLength = stream.Length; + var buffer = new Byte[dataLength]; + stream.Read(buffer, 0, (int)dataLength); + using (var writer = new FileStream(filePath, FileMode.Create)) + { + writer.Write(buffer, 0, (int)dataLength); + } + } + return true; + } + catch + { + return false; + } + } + } +} diff --git a/Sources/Ivony.Data.Access/EmbedResource/emptyDb.mdb b/Sources/Ivony.Data.Access/EmbedResource/emptyDb.mdb new file mode 100644 index 0000000..d43e8c9 Binary files /dev/null and b/Sources/Ivony.Data.Access/EmbedResource/emptyDb.mdb differ diff --git a/Sources/Ivony.Data.Access/Ivony.Data.Access.csproj b/Sources/Ivony.Data.Access/Ivony.Data.Access.csproj new file mode 100644 index 0000000..5863af2 --- /dev/null +++ b/Sources/Ivony.Data.Access/Ivony.Data.Access.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {B812CDE1-193C-4741-AEDC-D791A6848ABC} + Library + Properties + Ivony.Data.Access + Ivony.Data.Access + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {27d46d02-f7bc-42b2-ae3e-33eb5b1fa3f9} + Ivony.Data + + + + + + + + \ No newline at end of file diff --git a/Sources/Ivony.Data.Access/Properties/AssemblyInfo.cs b/Sources/Ivony.Data.Access/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fa7a4f9 --- /dev/null +++ b/Sources/Ivony.Data.Access/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Ivony.Data.Access")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ivony.Data.Access")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("90dfc4c2-f50c-4d1a-aecd-b31c04397dbc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Sources/Ivony.Data.Test/AccessTest.cs b/Sources/Ivony.Data.Test/AccessTest.cs new file mode 100644 index 0000000..3b10762 --- /dev/null +++ b/Sources/Ivony.Data.Test/AccessTest.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Data.OleDb; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ivony.Data.Access; +using Ivony.Data.Access.AccessClient; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Ivony.Data.Test +{ + [TestClass] + public class AccessTest + { + AccessDbExecutor _accessDbExecutor; + + public AccessTest() + { + _accessDbExecutor = AccessDb.ConnectFile(@"accessTestDb.mdb"); + _accessDbExecutor.T(@" +CREATE TABLE [Test1] +( + [Name] NVARCHAR(50) NOT NULL , + [Content] NTEXT NULL, + [Index] INT NOT NULL +)").ExecuteNonQuery(); + } + + + [TestMethod] + public void StandTest_For_Access() + { + Assert.IsNull(_accessDbExecutor.T("SELECT Name FROM Test1").ExecuteScalar(), "空数据表查询测试失败"); + Assert.IsNull(_accessDbExecutor.T("SELECT Name FROM Test1").ExecuteFirstRow(), "空数据表查询测试失败"); + Assert.AreEqual(_accessDbExecutor.T("SELECT COUNT(*) FROM Test1").ExecuteScalar(), 0, "空数据表查询测试失败"); + Assert.AreEqual(_accessDbExecutor.T("INSERT INTO Test1 ( Name, Content, [Index] ) VALUES ( {...} )", "Ivony", "Test", 1).ExecuteNonQuery(), 1, "插入数据测试失败"); + Assert.AreEqual(_accessDbExecutor.T("SELECT * FROM Test1").ExecuteDynamics().Length, 1, "插入数据后查询测试失败"); + Assert.IsNotNull(_accessDbExecutor.T("SELECT Name FROM Test1").ExecuteFirstRow(), "插入数据后查询测试失败"); + + var dataItem = _accessDbExecutor.T("SELECT * FROM Test1").ExecuteDynamicObject(); + Assert.AreEqual(dataItem.Name, "Ivony", "插入数据后查询测试失败"); + Assert.AreEqual(dataItem["Content"], "Test", "插入数据后查询测试失败"); + } + + [TestCleanup] + public void Shutdown() + { + _accessDbExecutor.Connection.Close(); + OleDbConnection.ReleaseObjectPool(); + } + } +} diff --git a/Sources/Ivony.Data.Test/Ivony.Data.Test.csproj b/Sources/Ivony.Data.Test/Ivony.Data.Test.csproj index d289a0a..6124f09 100644 --- a/Sources/Ivony.Data.Test/Ivony.Data.Test.csproj +++ b/Sources/Ivony.Data.Test/Ivony.Data.Test.csproj @@ -76,6 +76,7 @@ + @@ -85,6 +86,10 @@ + + {b812cde1-193c-4741-aedc-d791a6848abc} + Ivony.Data.Access + {297c6a4c-086b-426d-b146-df352410dcf0} Ivony.Data.MySql