Initial commit of first working version that is used in production environment.
This commit is contained in:
74
DynamORM.Mono.sln
Normal file
74
DynamORM.Mono.sln
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM", "DynamORM\DynamORM.csproj", "{63963ED7-9C78-4672-A4D4-339B6E825503}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM.Tests.Mono", "DynamORM.Tests\DynamORM.Tests.Mono.csproj", "{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = DynamORM\DynamORM.csproj
|
||||
Policies = $0
|
||||
$0.DotNetNamingPolicy = $1
|
||||
$1.DirectoryNamespaceAssociation = None
|
||||
$1.ResourceNamePolicy = FileFormatDefault
|
||||
$0.TextStylePolicy = $2
|
||||
$2.FileWidth = 120
|
||||
$2.RemoveTrailingWhitespace = True
|
||||
$2.EolMarker = Windows
|
||||
$2.inheritsSet = VisualStudio
|
||||
$2.inheritsScope = text/plain
|
||||
$2.scope = text/x-csharp
|
||||
$0.CSharpFormattingPolicy = $3
|
||||
$3.inheritsSet = Mono
|
||||
$3.inheritsScope = text/x-csharp
|
||||
$3.scope = text/x-csharp
|
||||
$0.TextStylePolicy = $4
|
||||
$4.FileWidth = 120
|
||||
$4.RemoveTrailingWhitespace = True
|
||||
$4.EolMarker = Windows
|
||||
$4.inheritsSet = VisualStudio
|
||||
$4.inheritsScope = text/plain
|
||||
$4.scope = text/plain
|
||||
$0.TextStylePolicy = $5
|
||||
$5.FileWidth = 120
|
||||
$5.TabWidth = 2
|
||||
$5.RemoveTrailingWhitespace = True
|
||||
$5.EolMarker = Windows
|
||||
$5.inheritsSet = VisualStudio
|
||||
$5.inheritsScope = text/plain
|
||||
$5.scope = text/microsoft-resx
|
||||
$0.XmlFormattingPolicy = $6
|
||||
$6.inheritsSet = null
|
||||
$6.scope = text/microsoft-resx
|
||||
$0.TextStylePolicy = $7
|
||||
$7.FileWidth = 120
|
||||
$7.TabWidth = 2
|
||||
$7.RemoveTrailingWhitespace = True
|
||||
$7.EolMarker = Windows
|
||||
$7.inheritsSet = VisualStudio
|
||||
$7.inheritsScope = text/plain
|
||||
$7.scope = application/xml
|
||||
$0.XmlFormattingPolicy = $8
|
||||
$8.inheritsSet = Mono
|
||||
$8.inheritsScope = application/xml
|
||||
$8.scope = application/xml
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
87
DynamORM.Tests/DynamORM.Tests.Mono.csproj
Normal file
87
DynamORM.Tests/DynamORM.Tests.Mono.csproj
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DynamORM.Tests</RootNamespace>
|
||||
<AssemblyName>DynamORM.Tests</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;MONO</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;MONO</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="nunit.framework, Version=2.5.10.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
|
||||
<Private>False</Private>
|
||||
<Package>nunit</Package>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Data.Sqlite" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Modify\DynamicModificationTests.cs" />
|
||||
<Compile Include="Modify\DynamicNoSchemaModificationTests.cs" />
|
||||
<Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" />
|
||||
<Compile Include="Select\DynamicNoSchemaAccessTests.cs" />
|
||||
<Compile Include="Select\DynamicTypeSchemaAccessTests.cs" />
|
||||
<Compile Include="Helpers\AttachToDebugger.cs" />
|
||||
<Compile Include="Select\DynamicAccessTests.cs" />
|
||||
<Compile Include="Helpers\Users.cs" />
|
||||
<Compile Include="Helpers\UsersBareBoneClass.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Select\RenamedTypedAccessTests.cs" />
|
||||
<Compile Include="TestsBase.cs" />
|
||||
<Compile Include="Select\TypedAccessTests.cs" />
|
||||
<Compile Include="Helpers\PoolingTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DynamORM\DynamORM.csproj">
|
||||
<Project>{63963ED7-9C78-4672-A4D4-339B6E825503}</Project>
|
||||
<Name>DynamORM</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
88
DynamORM.Tests/DynamORM.Tests.csproj
Normal file
88
DynamORM.Tests/DynamORM.Tests.csproj
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DynamORM.Tests</RootNamespace>
|
||||
<AssemblyName>DynamORM.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite">
|
||||
<HintPath>lib\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Helpers\PoolingTests.cs" />
|
||||
<Compile Include="Modify\DynamicModificationTests.cs" />
|
||||
<Compile Include="Modify\DynamicNoSchemaModificationTests.cs" />
|
||||
<Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" />
|
||||
<Compile Include="Select\DynamicNoSchemaAccessTests.cs" />
|
||||
<Compile Include="Select\DynamicTypeSchemaAccessTests.cs" />
|
||||
<Compile Include="Helpers\AttachToDebugger.cs" />
|
||||
<Compile Include="Select\DynamicAccessTests.cs" />
|
||||
<Compile Include="Helpers\Users.cs" />
|
||||
<Compile Include="Helpers\UsersBareBoneClass.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Select\RenamedTypedAccessTests.cs" />
|
||||
<Compile Include="TestsBase.cs" />
|
||||
<Compile Include="Select\TypedAccessTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DynamORM\DynamORM.csproj">
|
||||
<Project>{63963ED7-9C78-4672-A4D4-339B6E825503}</Project>
|
||||
<Name>DynamORM</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
57
DynamORM.Tests/Helpers/AttachToDebugger.cs
Normal file
57
DynamORM.Tests/Helpers/AttachToDebugger.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Helpers
|
||||
{
|
||||
/// <summary>Class responsible for users operations testing.</summary>
|
||||
[TestFixture]
|
||||
public class AttachToDebugger
|
||||
{
|
||||
/// <summary>Attach to debugger.</summary>
|
||||
[Test]
|
||||
[Explicit("Test for attaching debugger to NUnit test framework")]
|
||||
public void Attach()
|
||||
{
|
||||
if (!Debugger.IsAttached)
|
||||
Debugger.Launch();
|
||||
}
|
||||
|
||||
/// <summary>Test anonymous type compatybility.</summary>
|
||||
[Test]
|
||||
public void TestAnonType()
|
||||
{
|
||||
var a = new { x = 1, y = 2 };
|
||||
var b = new { x = 3, y = 4 };
|
||||
|
||||
Assert.AreEqual(a.GetType(), b.GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
57
DynamORM.Tests/Helpers/AttachToDebugger.cs.bak
Normal file
57
DynamORM.Tests/Helpers/AttachToDebugger.cs.bak
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Helpers
|
||||
{
|
||||
/// <summary>Class responsible for users operations testing.</summary>
|
||||
[TestFixture]
|
||||
public class AttachToDebugger
|
||||
{
|
||||
/// <summary>Attach to debugger.</summary>
|
||||
[Test]
|
||||
[Explicit("Test for attaching debugger to NUnit test framework")]
|
||||
public void Attach()
|
||||
{
|
||||
if (!Debugger.IsAttached)
|
||||
Debugger.Launch();
|
||||
}
|
||||
|
||||
/// <summary>Test anonymous type compatybility.</summary>
|
||||
[Test]
|
||||
public void TestAnonType ()
|
||||
{
|
||||
var a = new { x = 1, y = 2 };
|
||||
var b = new { x = 3, y = 4 };
|
||||
|
||||
Assert.AreEqual (a.GetType (), b.GetType ());
|
||||
}
|
||||
}
|
||||
}
|
||||
101
DynamORM.Tests/Helpers/PoolingTests.cs
Normal file
101
DynamORM.Tests/Helpers/PoolingTests.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Helpers
|
||||
{
|
||||
/// <summary>Pooling tests.</summary>
|
||||
[TestFixture]
|
||||
public class PoolingTests : TestsBase
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public virtual void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Tear down test objects.</summary>
|
||||
[TestFixtureTearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
DestroyDynamicDatabase();
|
||||
DestroyTestDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Test single mode command disposing.</summary>
|
||||
[Test]
|
||||
public void TestSingleModeCommand()
|
||||
{
|
||||
CreateDynamicDatabase();
|
||||
|
||||
var cmd = Database.Open().CreateCommand();
|
||||
|
||||
cmd.SetCommand("SELECT COUNT(0) FROM sqlite_master;");
|
||||
|
||||
Database.Dispose();
|
||||
Database = null;
|
||||
|
||||
Assert.Throws<ObjectDisposedException>(() => cmd.ExecuteScalar());
|
||||
}
|
||||
|
||||
/// <summary>Test single mode transaction disposing.</summary>
|
||||
[Test]
|
||||
public void TestSingleModeTransaction()
|
||||
{
|
||||
try
|
||||
{
|
||||
CreateDynamicDatabase();
|
||||
|
||||
using (var conn = Database.Open())
|
||||
using (var trans = conn.BeginTransaction())
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
Assert.AreEqual(1, cmd.SetCommand("INSERT INTO \"users\" (\"code\") VALUES ('999');").ExecuteNonQuery());
|
||||
|
||||
Database.Dispose();
|
||||
Database = null;
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
// Verify (rollback)
|
||||
CreateDynamicDatabase();
|
||||
Assert.AreEqual(0, Database.Table("users").Count(columns: "id", code: "999"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Remove for next tests
|
||||
Database.Dispose();
|
||||
Database = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
DynamORM.Tests/Helpers/Users.cs
Normal file
73
DynamORM.Tests/Helpers/Users.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Tests.Helpers
|
||||
{
|
||||
/// <summary>Users table representation.</summary>
|
||||
[Table(Name = "users", Override = true)]
|
||||
public class Users
|
||||
{
|
||||
/// <summary>Gets or sets id column value.</summary>
|
||||
[Column("id", true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>Gets or sets code column value.</summary>
|
||||
[Column("code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>Gets or sets login column value.</summary>
|
||||
[Column("login")]
|
||||
public string Login { get; set; }
|
||||
|
||||
/// <summary>Gets or sets first columnvalue.</summary>
|
||||
[Column("first")]
|
||||
public string First { get; set; }
|
||||
|
||||
/// <summary>Gets or sets last column value.</summary>
|
||||
[Column("last")]
|
||||
public string Last { get; set; }
|
||||
|
||||
/// <summary>Gets or sets password column value.</summary>
|
||||
[Column("password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>Gets or sets email column value.</summary>
|
||||
[Column("email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>Gets or sets quote column value.</summary>
|
||||
[Column("quote")]
|
||||
public string Quote { get; set; }
|
||||
|
||||
/// <summary>Gets or sets value of aggregate fields.</summary>
|
||||
[Ignore]
|
||||
public object AggregateField { get; set; }
|
||||
}
|
||||
}
|
||||
67
DynamORM.Tests/Helpers/UsersBareBoneClass.cs
Normal file
67
DynamORM.Tests/Helpers/UsersBareBoneClass.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Tests.Helpers
|
||||
{
|
||||
/// <summary>Users table representation.</summary>
|
||||
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Bare bone table mapping.")]
|
||||
public class users
|
||||
{
|
||||
/// <summary>Gets or sets id column value.</summary>
|
||||
[Column("id", true)]
|
||||
public long id { get; set; }
|
||||
|
||||
/// <summary>Gets or sets code column value.</summary>
|
||||
public string code { get; set; }
|
||||
|
||||
/// <summary>Gets or sets login column value.</summary>
|
||||
public string login { get; set; }
|
||||
|
||||
/// <summary>Gets or sets first columnvalue.</summary>
|
||||
public string first { get; set; }
|
||||
|
||||
/// <summary>Gets or sets last column value.</summary>
|
||||
public string last { get; set; }
|
||||
|
||||
/// <summary>Gets or sets password column value.</summary>
|
||||
public string password { get; set; }
|
||||
|
||||
/// <summary>Gets or sets email column value.</summary>
|
||||
public string email { get; set; }
|
||||
|
||||
/// <summary>Gets or sets quote column value.</summary>
|
||||
public string quote { get; set; }
|
||||
|
||||
/// <summary>Gets or sets value of aggregate fields.</summary>
|
||||
[Ignore]
|
||||
public object aggregatefield { get; set; }
|
||||
}
|
||||
}
|
||||
390
DynamORM.Tests/Modify/DynamicModificationTests.cs
Normal file
390
DynamORM.Tests/Modify/DynamicModificationTests.cs
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Modify
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicModificationTests : TestsBase
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public virtual void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
CreateDynamicDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Tear down test objects.</summary>
|
||||
[TestFixtureTearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
DestroyDynamicDatabase();
|
||||
DestroyTestDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public virtual dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table("users");
|
||||
}
|
||||
|
||||
#region Insert
|
||||
|
||||
/// <summary>Test row insertion by dynamic arguments.</summary>
|
||||
[Test]
|
||||
public void TestInsertByArguments()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Insert(code: 201, first: "Juri", last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla"));
|
||||
|
||||
// Verify
|
||||
var o = GetTestTable().Single(code: 201);
|
||||
Assert.Less(200, o.id);
|
||||
Assert.AreEqual("201", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row insertion by dynamic object.</summary>
|
||||
[Test]
|
||||
public void TestInsertByDynamicObjects()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Insert(values: new { code = 202, first = "Juri", last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
|
||||
|
||||
// Verify
|
||||
var o = GetTestTable().Single(code: 202);
|
||||
Assert.Less(200, o.id);
|
||||
Assert.AreEqual("202", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row insertion by mapped object.</summary>
|
||||
[Test]
|
||||
public void TestInsertByMappedObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Insert(values: new Users
|
||||
{
|
||||
Id = u.Max(columns: "id") + 1,
|
||||
Code = "203",
|
||||
First = "Juri",
|
||||
Last = "Gagarin",
|
||||
Email = "juri.gagarin@megacorp.com",
|
||||
Quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 203);
|
||||
Assert.Less(200, o.id);
|
||||
Assert.AreEqual("203", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row insertion by basic object.</summary>
|
||||
[Test]
|
||||
public void TestInsertByBasicObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Insert(values: new users
|
||||
{
|
||||
id = u.Max(columns: "id") + 1,
|
||||
code = "204",
|
||||
first = "Juri",
|
||||
last = "Gagarin",
|
||||
email = "juri.gagarin@megacorp.com",
|
||||
quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 204);
|
||||
Assert.Less(200, o.id);
|
||||
Assert.AreEqual("204", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
#endregion Insert
|
||||
|
||||
#region Update
|
||||
|
||||
/// <summary>Test row updating by dynamic arguments.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByArguments()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Update(id: 1, code: 201, first: "Juri", last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla"));
|
||||
|
||||
// Verify
|
||||
var o = GetTestTable().Single(code: 201);
|
||||
Assert.AreEqual(1, o.id);
|
||||
Assert.AreEqual("201", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by dynamic objects.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByDynamicObject()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Update(update: new { id = 2, code = 202, first = "Juri", last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
|
||||
|
||||
// Verify
|
||||
var o = GetTestTable().Single(code: 202);
|
||||
Assert.AreEqual(2, o.id);
|
||||
Assert.AreEqual("202", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by mapped object.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByMappedObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Update(update: new Users
|
||||
{
|
||||
Id = 3,
|
||||
Code = "203",
|
||||
First = "Juri",
|
||||
Last = "Gagarin",
|
||||
Email = "juri.gagarin@megacorp.com",
|
||||
Quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 203);
|
||||
Assert.AreEqual(3, o.id);
|
||||
Assert.AreEqual("203", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by basic object.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByBasicObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Update(update: new users
|
||||
{
|
||||
id = 4,
|
||||
code = "204",
|
||||
first = "Juri",
|
||||
last = "Gagarin",
|
||||
email = "juri.gagarin@megacorp.com",
|
||||
quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 204);
|
||||
Assert.AreEqual(4, o.id);
|
||||
Assert.AreEqual("204", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by dynamic objects.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByDynamicObjects()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Update(values: new { code = 205, first = "Juri", last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }, where: new { id = 5 }));
|
||||
|
||||
// Verify
|
||||
var o = GetTestTable().Single(code: 205);
|
||||
Assert.AreEqual(5, o.id);
|
||||
Assert.AreEqual("205", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by mapped objects.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByMappedObjects()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Update(values: new Users
|
||||
{
|
||||
Id = 6,
|
||||
Code = "206",
|
||||
First = "Juri",
|
||||
Last = "Gagarin",
|
||||
Email = "juri.gagarin@megacorp.com",
|
||||
Quote = "bla, bla, bla"
|
||||
}, id: 6));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 206);
|
||||
Assert.AreEqual(6, o.id);
|
||||
Assert.AreEqual("206", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
/// <summary>Test row updating by basic objects.</summary>
|
||||
[Test]
|
||||
public void TestUpdateByBasicObjects()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Update(values: new users
|
||||
{
|
||||
id = 7,
|
||||
code = "207",
|
||||
first = "Juri",
|
||||
last = "Gagarin",
|
||||
email = "juri.gagarin@megacorp.com",
|
||||
quote = "bla, bla, bla"
|
||||
}, id: 7));
|
||||
|
||||
// Verify
|
||||
var o = u.Single(code: 207);
|
||||
Assert.AreEqual(7, o.id);
|
||||
Assert.AreEqual("207", o.code);
|
||||
Assert.AreEqual("Juri", o.first);
|
||||
Assert.AreEqual("Gagarin", o.last);
|
||||
Assert.AreEqual("juri.gagarin@megacorp.com", o.email);
|
||||
Assert.AreEqual("bla, bla, bla", o.quote);
|
||||
Assert.AreEqual(null, o.password);
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
|
||||
#region Delete
|
||||
|
||||
/// <summary>Test row deleting by dynamic arguments.</summary>
|
||||
[Test]
|
||||
public void TestDeleteByArguments()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Delete(code: 10));
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(0, GetTestTable().Count(code: 10));
|
||||
}
|
||||
|
||||
/// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary>
|
||||
[Test]
|
||||
public void TestDeleteyDynamicObject()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Delete(delete: new { id = 11, code = 11, first = "Juri", last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(0, GetTestTable().Count(id: 11));
|
||||
}
|
||||
|
||||
/// <summary>Test row deleting by mapped object.</summary>
|
||||
[Test]
|
||||
public void TestDeleteByMappedObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Delete(delete: new Users
|
||||
{
|
||||
Id = 12,
|
||||
Code = "12",
|
||||
First = "Juri",
|
||||
Last = "Gagarin",
|
||||
Email = "juri.gagarin@megacorp.com",
|
||||
Quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(0, GetTestTable().Count(id: 12));
|
||||
}
|
||||
|
||||
/// <summary>Test row deleting by basic object.</summary>
|
||||
[Test]
|
||||
public void TestDeleteByBasicObject()
|
||||
{
|
||||
var u = GetTestTable();
|
||||
|
||||
Assert.AreEqual(1, u.Delete(delete: new users
|
||||
{
|
||||
id = 13,
|
||||
code = "13",
|
||||
first = "Juri",
|
||||
last = "Gagarin",
|
||||
email = "juri.gagarin@megacorp.com",
|
||||
quote = "bla, bla, bla"
|
||||
}));
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(0, GetTestTable().Count(id: 13));
|
||||
}
|
||||
|
||||
/// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary>
|
||||
[Test]
|
||||
public void TestDeleteyDynamicObjectWhere()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Delete(where: new { id = 14, code = 14 }));
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(0, GetTestTable().Count(id: 14));
|
||||
}
|
||||
|
||||
#endregion Delete
|
||||
}
|
||||
}
|
||||
55
DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs
Normal file
55
DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Modify
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicNoSchemaModificationTests : DynamicModificationTests
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public override void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
CreateDynamicDatabase(
|
||||
DynamicDatabaseOptions.SingleConnection |
|
||||
DynamicDatabaseOptions.SingleTransaction |
|
||||
DynamicDatabaseOptions.SupportLimitOffset);
|
||||
}
|
||||
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public override dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table("users", new string[] { "id" });
|
||||
}
|
||||
}
|
||||
}
|
||||
45
DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs
Normal file
45
DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Modify
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicTypeSchemaModificationTests : DynamicModificationTests
|
||||
{
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public override dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table<users>();
|
||||
}
|
||||
}
|
||||
}
|
||||
65
DynamORM.Tests/Properties/AssemblyInfo.cs
Normal file
65
DynamORM.Tests/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* See: http://opensource.org/licenses/bsd-license.php
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
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("DynamORM.Tests")]
|
||||
[assembly: AssemblyDescription("Dynamic Object-Relational Mapping tests library.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("RUSSEK Software")]
|
||||
[assembly: AssemblyProduct("DynamORM")]
|
||||
[assembly: AssemblyCopyright("Copyright © RUSSEK Software 2012")]
|
||||
[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("1d8b751b-b3ec-481d-9f7f-14d6e6eb0fde")]
|
||||
|
||||
// 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.1")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.1")]
|
||||
75
DynamORM.Tests/Properties/Resources.Designer.cs
generated
Normal file
75
DynamORM.Tests/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.269
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace DynamORM.Tests.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DynamORM.Tests.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to CREATE TABLE users (id INTEGER NOT NULL PRIMARY KEY, code, login text, first text, last text, password text, email text, quote text);
|
||||
///INSERT INTO users (code,first,last,email,quote) VALUES ('1','Clarke','Jarvis','eu.accumsan@nonarcuVivamus.org','non leo. Vivamus');
|
||||
///INSERT INTO users (code,first,last,email,quote) VALUES ('2','Marny','Fry','Cras.convallis.convallis@nisiCumsociis.ca','aliquam eu, accumsan sed, facilisis vitae, orci. Phasellus');
|
||||
///INSERT INTO users (code,first,last,email,quote) VALUES ('3',' [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string UsersTable {
|
||||
get {
|
||||
return ResourceManager.GetString("UsersTable", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
324
DynamORM.Tests/Properties/Resources.resx
Normal file
324
DynamORM.Tests/Properties/Resources.resx
Normal file
@@ -0,0 +1,324 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="UsersTable" xml:space="preserve">
|
||||
<value>CREATE TABLE users (id INTEGER NOT NULL PRIMARY KEY, code, login text, first text, last text, password text, email text, quote text);
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('1','Clarke','Jarvis','eu.accumsan@nonarcuVivamus.org','non leo. Vivamus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('2','Marny','Fry','Cras.convallis.convallis@nisiCumsociis.ca','aliquam eu, accumsan sed, facilisis vitae, orci. Phasellus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('3','Dai','Marks','dictum.augue@venenatis.ca','nulla ante, iaculis nec, eleifend non, dapibus rutrum, justo. Praesent');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('4','Forrest','Hendricks','justo.sit.amet@odioa.edu','auctor. Mauris vel turpis. Aliquam adipiscing lobortis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('5','Blossom','Dunlap','libero.mauris@Phasellusfermentumconvallis.ca','luctus sit amet, faucibus ut, nulla. Cras eu tellus eu');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('6','George','Rios','vitae@sodales.ca','elit. Aliquam auctor, velit eget laoreet');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('7','Ivory','Henderson','elit.Aliquam.auctor@Nullamvelitdui.ca','Fusce diam nunc, ullamcorper');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('8','Inez','Goodwin','consectetuer.mauris@nibhPhasellus.edu','eu, placerat eget, venenatis a, magna.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('9','Sigourney','Gonzales','lectus.pede.ultrices@sagittislobortismauris.org','egestas hendrerit');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('10','Fulton','Terrell','penatibus@euaugue.com','Nulla interdum. Curabitur dictum.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('11','Logan','Freeman','malesuada.malesuada@nullaIntegervulputate.edu','dui, semper et, lacinia');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('12','Anne','Irwin','lorem.ut.aliquam@ligula.org','erat, in consectetuer ipsum nunc id enim.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('13','Alexandra','Church','sit@sempererat.org','lorem, luctus ut, pellentesque eget, dictum placerat, augue. Sed');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('14','Adena','Branch','sit.amet@accumsanlaoreetipsum.org','natoque penatibus et');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('15','Lionel','Hoover','ac@Donectempor.ca','at pede. Cras vulputate');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('16','Aimee','Strickland','ornare.lectus@tinciduntduiaugue.ca','vitae odio sagittis semper. Nam');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('17','Selma','Williamson','metus.In.nec@quamquisdiam.org','id nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('18','Lara','Trujillo','lacus@convallisest.edu','Integer sem elit, pharetra ut,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('19','Ori','Ellis','egestas@at.ca','odio. Nam interdum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('20','Macey','Carey','sed.consequat@ametorciUt.org','magna');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('21','Quynn','Randall','Cras.dictum@malesuada.org','egestas. Fusce aliquet magna a neque.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('22','Alec','Robles','Fusce.feugiat@mollisdui.com','a');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('23','Jakeem','Bell','ante@laoreetlectusquis.edu','eget massa. Suspendisse eleifend. Cras');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('24','Katelyn','Cannon','sit.amet@PhasellusornareFusce.org','nisi dictum augue malesuada malesuada.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('25','Christian','Alford','per@vulputate.ca','turpis.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('26','Leila','Forbes','nec.ante@idblanditat.ca','ac ipsum. Phasellus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('27','Hadley','Gillespie','Lorem.ipsum@Nullamvitaediam.com','vestibulum lorem, sit amet ultricies sem magna nec quam.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('28','Julian','Keith','facilisis@loremvitaeodio.edu','nulla at sem molestie sodales. Mauris blandit enim consequat purus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('29','Allen','Ramos','neque@lobortis.ca','amet diam eu dolor egestas rhoncus. Proin nisl sem, consequat');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('30','Hermione','Walsh','dictum.magna@tincidunt.edu','scelerisque');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('31','Xena','Graves','eu.dui@tinciduntaliquamarcu.ca','nunc interdum feugiat. Sed nec metus facilisis lorem tristique aliquet.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('32','Tanisha','Blackburn','aliquam.eu.accumsan@dui.edu','fringilla mi lacinia mattis. Integer eu');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('33','Norman','Hobbs','eu.euismod.ac@tinciduntDonecvitae.com','pulvinar arcu et pede. Nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('34','Guy','Molina','non@rutrumurna.org','Vivamus euismod urna.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('35','Rama','Albert','nunc@laciniavitaesodales.com','eu augue porttitor interdum. Sed auctor odio a purus. Duis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('36','Owen','Combs','Nullam.enim.Sed@magnaPhasellusdolor.com','mollis vitae, posuere at, velit. Cras lorem lorem, luctus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('37','Ashely','Graham','eget.odio@enimsitamet.com','commodo at, libero. Morbi accumsan laoreet ipsum. Curabitur consequat,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('38','Paul','Levy','nec@leo.com','augue scelerisque mollis. Phasellus libero mauris, aliquam eu, accumsan');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('39','Octavia','Calderon','eu@maurissitamet.edu','est, mollis non, cursus non,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('40','Lenore','Pugh','eu.metus.In@Cumsociisnatoque.com','scelerisque mollis. Phasellus libero mauris, aliquam eu, accumsan sed, facilisis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('41','Regan','Clemons','eu.neque.pellentesque@Integerinmagna.ca','Curae;');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('42','Zachary','Haynes','eu.erat@ipsum.edu','quis lectus. Nullam');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('43','Dane','Hyde','rhoncus@auctor.com','magna et ipsum cursus vestibulum. Mauris magna. Duis dignissim');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('44','Mara','Hansen','Nunc.commodo@ultricies.org','magna. Ut tincidunt orci quis lectus. Nullam suscipit, est');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('45','Zelda','Parrish','turpis.In@rutrummagnaCras.com','Suspendisse aliquet, sem ut cursus luctus, ipsum leo');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('46','Amaya','Richmond','lacinia.at@in.org','ac, fermentum vel, mauris.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('47','Hedda','Murray','ac.fermentum.vel@ipsum.com','tincidunt, neque vitae semper egestas, urna justo faucibus lectus, a');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('48','Brendan','Macdonald','dignissim@leoMorbi.com','vestibulum lorem, sit');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('49','Gray','Mccall','risus.Donec@atsem.ca','libero est, congue');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('50','Shoshana','Tran','nunc.In@aliquet.org','magna sed dui.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('51','Sylvester','Parks','Mauris.molestie@ipsumdolorsit.org','nec, eleifend non, dapibus rutrum, justo.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('52','Kennan','Stokes','nonummy.ut.molestie@varius.org','Ut nec urna et arcu imperdiet ullamcorper. Duis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('53','Quin','Park','porttitor@vulputateeu.com','scelerisque, lorem ipsum sodales');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('54','Madison','Bailey','nec.orci.Donec@vestibulumnequesed.org','augue. Sed');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('55','Kenyon','Reilly','ultrices.iaculis.odio@sit.ca','enim. Curabitur massa. Vestibulum accumsan neque');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('56','Drew','Brooks','molestie.orci@aliquetdiamSed.org','at risus. Nunc ac sem ut dolor dapibus gravida.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('57','Omar','Dunn','vel@Donecsollicitudinadipiscing.ca','ultrices posuere cubilia Curae; Phasellus ornare. Fusce mollis. Duis sit');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('58','Glenna','Lambert','Proin.non@Phasellus.com','neque. In');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('59','Aspen','Bailey','in.dolor.Fusce@ipsum.org','a, arcu. Sed et libero. Proin');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('60','Adele','Carlson','velit.justo.nec@vehicularisusNulla.edu','risus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('61','Kerry','Zimmerman','luctus.aliquet.odio@urnajusto.edu','purus. Duis elementum, dui quis accumsan convallis, ante lectus convallis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('62','Hedda','Guthrie','vulputate.risus@Phaselluselit.ca','ac mattis velit justo nec');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('63','Wyoming','Blackburn','nec.ante@lorem.org','ultricies');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('64','Palmer','Dennis','venenatis.lacus@Donecnonjusto.org','a, arcu. Sed et libero. Proin');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('65','Wesley','Reeves','massa.Suspendisse.eleifend@nec.edu','consequat');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('66','Mallory','Todd','Duis@Crasloremlorem.edu','nascetur ridiculus mus. Proin vel arcu eu odio');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('67','Perry','Kirk','tincidunt.adipiscing@mauris.ca','ullamcorper viverra. Maecenas iaculis aliquet diam. Sed diam lorem,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('68','Justina','Horne','enim.nec.tempus@magnanec.com','ipsum ac mi eleifend egestas. Sed pharetra, felis eget');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('69','Noel','Santana','Duis.elementum.dui@Nullamvitae.org','Phasellus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('70','Sylvester','Bridges','Sed.neque@ornarelectusante.org','Maecenas libero');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('71','Cailin','Baldwin','eu@nibhenim.com','consectetuer');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('72','Beatrice','Henson','risus.Nunc.ac@Etiam.ca','nec, imperdiet nec, leo. Morbi neque');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('73','Kellie','Curry','quis.turpis.vitae@Quisque.org','ipsum. Suspendisse non leo.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('74','Justine','Stewart','Curabitur@dui.org','natoque penatibus et magnis dis parturient');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('75','Dean','Waters','quis.turpis@morbi.ca','Nulla interdum. Curabitur dictum. Phasellus in felis. Nulla tempor augue');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('76','Helen','Porter','molestie.dapibus.ligula@ipsum.com','enim non nisi. Aenean eget');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('77','Janna','Acosta','lectus.a@tempusrisus.com','lectus justo');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('78','Libby','Vaughn','nisl.sem.consequat@convallis.ca','purus mauris a nunc.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('79','Winifred','Cooke','aliquet.sem.ut@etrutrum.ca','metus facilisis lorem tristique aliquet. Phasellus fermentum convallis ligula. Donec');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('80','Taylor','Glass','sit@maurissitamet.com','orci, consectetuer euismod');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('81','Melyssa','Palmer','pharetra.sed.hendrerit@fermentum.ca','neque tellus, imperdiet non, vestibulum nec,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('82','Kuame','Holman','Vivamus@Donecnibh.edu','cursus non, egestas a, dui. Cras');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('83','Martin','Hughes','magna@nonbibendum.org','et ultrices posuere cubilia');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('84','Roanna','Potter','amet.dapibus@aenim.com','est tempor bibendum. Donec');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('85','Cleo','Carson','Curabitur.dictum.Phasellus@liberoIntegerin.com','mauris');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('86','Adele','Daugherty','vulputate.ullamcorper@elitfermentumrisus.edu','consequat purus. Maecenas');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('87','Macon','Todd','et.malesuada@Crasloremlorem.com','montes, nascetur ridiculus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('88','Ira','Merritt','risus@eunullaat.ca','metus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('89','Dustin','Landry','nec.orci.Donec@vulputateeu.com','Nunc pulvinar arcu et pede. Nunc sed');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('90','Debra','Shepherd','dolor.elit@ornareFusce.ca','Suspendisse non leo. Vivamus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('91','Channing','Mcknight','tellus@laoreet.ca','non ante bibendum ullamcorper. Duis cursus, diam at pretium aliquet,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('92','Abraham','Rodgers','tincidunt.nibh@ipsum.ca','Cum sociis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('93','Abel','Mcintyre','et@turpisvitaepurus.com','at pretium aliquet,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('94','Lysandra','Cotton','malesuada.malesuada.Integer@gravidamolestie.org','commodo hendrerit. Donec');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('95','Kane','Bennett','ante.Vivamus@Donec.ca','consectetuer rhoncus. Nullam velit dui, semper et, lacinia vitae, sodales');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('96','Timothy','Rivas','hendrerit.consectetuer@nonarcuVivamus.ca','Suspendisse non leo. Vivamus nibh dolor, nonummy ac, feugiat');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('97','Arden','Cote','magnis@sedestNunc.org','purus mauris a nunc.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('98','Brynn','Britt','ac@nibhQuisque.edu','Duis gravida. Praesent eu nulla at sem molestie');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('99','Jerome','Kirkland','ac@nibhPhasellus.com','neque');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('100','Hoyt','Tran','ullamcorper.viverra@parturientmontesnascetur.org','ac tellus. Suspendisse sed dolor. Fusce mi');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('101','Abraham','Downs','velit.eu.sem@neceuismod.ca','suscipit,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('102','Vivien','Fletcher','Nunc.ut@quamPellentesquehabitant.edu','lobortis. Class aptent taciti sociosqu ad');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('103','Azalia','Turner','scelerisque@at.edu','odio sagittis semper. Nam tempor diam dictum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('104','Tate','Ellis','velit.Sed.malesuada@Cras.com','sed');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('105','Dennis','Walls','Nullam.scelerisque@amifringilla.edu','arcu. Vestibulum ut eros non enim commodo hendrerit. Donec porttitor');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('106','Amela','Collins','Quisque@magna.org','Proin');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('107','Olivia','Dejesus','scelerisque@vitae.org','Duis cursus, diam at pretium aliquet,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('108','Mechelle','Russo','Fusce.aliquet.magna@Praesent.org','penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('109','Hall','Burke','Vivamus.nibh@pellentesque.edu','et libero. Proin mi. Aliquam');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('110','Chanda','Ayers','magna.Nam.ligula@NullafacilisiSed.org','dui, semper et, lacinia vitae, sodales at,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('111','Abdul','Dominguez','pretium.aliquet.metus@vellectusCum.com','vitae erat vel pede blandit congue. In scelerisque scelerisque dui.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('112','Wynter','Lynn','tellus.Aenean@ligulatortordictum.ca','adipiscing fringilla, porttitor vulputate, posuere vulputate, lacus. Cras interdum.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('113','Molly','Willis','montes.nascetur@sed.org','sem. Nulla interdum. Curabitur dictum. Phasellus in felis.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('114','Shafira','Harper','Phasellus.in.felis@ategestas.edu','Vivamus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('115','Otto','Gentry','in.molestie.tortor@Fusce.edu','est. Mauris eu turpis. Nulla aliquet. Proin velit.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('116','Todd','Riddle','et@nislsem.com','Nulla');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('117','Mufutau','Pollard','sit@ridiculusmus.org','accumsan neque et nunc. Quisque ornare tortor at');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('118','Noah','Sears','tristique.neque.venenatis@luctuslobortis.org','dictum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('119','Amanda','Clarke','in.consequat@non.org','nisi dictum augue malesuada malesuada. Integer id magna et ipsum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('120','Vladimir','Colon','velit.dui@scelerisquenequeNullam.com','pharetra sed, hendrerit a, arcu. Sed et libero.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('121','Aaron','Hernandez','Quisque.ornare.tortor@magna.ca','sit amet ante. Vivamus non lorem vitae odio');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('122','Bert','Gonzales','fermentum@Nullamvelit.ca','quis massa. Mauris vestibulum, neque sed dictum eleifend, nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('123','Bevis','Leblanc','viverra.Donec@dictumaugue.com','neque sed dictum eleifend, nunc risus varius orci, in');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('124','Noble','Fisher','Cum@eu.com','Nunc quis arcu');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('125','Xaviera','Barton','non.arcu@sagittis.com','ultrices posuere cubilia Curae; Phasellus ornare. Fusce mollis. Duis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('126','Logan','Roy','Nulla@hendreritconsectetuercursus.com','sed, facilisis vitae, orci. Phasellus dapibus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('127','Wilma','Sweet','Nullam.nisl.Maecenas@gravidasagittis.org','ut, nulla. Cras');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('128','Candace','Olsen','sit.amet@lobortisnisi.com','habitant morbi tristique senectus et netus et malesuada');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('129','Claire','Alvarado','risus.varius@interdumSed.com','a felis ullamcorper viverra. Maecenas iaculis aliquet');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('130','Aurelia','Bean','diam.dictum.sapien@eu.edu','libero. Integer in magna. Phasellus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('131','Carly','Wilcox','massa.non.ante@Aliquam.com','vehicula risus. Nulla eget metus eu erat semper rutrum. Fusce');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('132','Xanthus','Graves','vulputate.velit.eu@vitaerisus.com','Cras sed leo. Cras vehicula aliquet libero. Integer in magna.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('133','Uta','Justice','adipiscing@consequatdolor.edu','Nam tempor diam dictum sapien. Aenean massa.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('134','Alika','Parker','faucibus.ut@Fuscemilorem.edu','vel, venenatis vel, faucibus id,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('135','Kasimir','Pugh','sed.turpis@FuscefeugiatLorem.com','justo. Praesent luctus. Curabitur egestas nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('136','Brock','Acevedo','dapibus.rutrum@convallisconvallisdolor.org','eu enim. Etiam');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('137','Orla','Hogan','in@Aliquamauctor.com','ac turpis egestas. Aliquam fringilla cursus purus. Nullam scelerisque neque');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('138','Tatyana','Bean','molestie.arcu@sempercursus.edu','pellentesque, tellus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('139','Cadman','Humphrey','auctor@Aeneangravida.edu','eget, dictum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('140','Delilah','Quinn','Pellentesque.habitant@liberoMorbi.edu','lobortis quam a felis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('141','Briar','Prince','euismod@Aeneangravida.com','at, libero.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('142','Hedda','Garrett','eleifend@sitamet.org','ac turpis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('143','Sage','Hardy','semper@acfeugiat.org','Nunc laoreet lectus quis massa.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('144','Iris','Meyers','Duis.a.mi@Donecnibhenim.edu','vitae aliquam eros turpis non enim. Mauris quis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('145','Hayes','Bates','molestie@magnaSuspendisse.com','fringilla. Donec feugiat metus sit amet ante.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('146','Rana','Cain','malesuada@loremsitamet.edu','mi');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('147','acqueline','Mays','est.Nunc.laoreet@est.edu','odio. Phasellus at augue id ante dictum cursus. Nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('148','Nichole','Suarez','cursus.purus.Nullam@ac.edu','Sed malesuada augue ut lacus. Nulla');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('149','Sasha','Sparks','fermentum@nonenim.edu','Sed dictum. Proin eget odio.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('150','Timon','Lowery','suscipit@Donecat.edu','pede blandit congue. In scelerisque scelerisque dui. Suspendisse ac metus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('151','Ivor','Charles','augue.eu@odiovelest.org','quis urna. Nunc quis arcu vel quam dignissim');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('152','Joelle','Trevino','eget@diamdictumsapien.ca','tortor, dictum eu, placerat eget, venenatis a,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('153','Aristotle','Wall','at@Pellentesqueutipsum.com','quis,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('154','Amena','Boyd','elit.Etiam@vehiculaet.com','molestie dapibus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('155','Rashad','Osborn','ac@aliquam.ca','sed');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('156','Theodore','Williamson','dignissim.magna@volutpat.ca','Fusce fermentum fermentum');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('157','Rajah','Logan','enim@Aliquamerat.com','nunc. Quisque ornare tortor');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('158','Zane','Perez','aliquet@aliquetPhasellus.com','pede.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('159','Jena','Rios','urna@velitegetlaoreet.org','eu erat semper rutrum.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('160','Amber','Gallagher','conubia@elit.org','Maecenas ornare egestas');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('161','Veda','Pittman','habitant.morbi.tristique@aliquamenimnec.ca','risus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('162','Nathan','Lowe','dui.Cum.sociis@Sed.org','sed, est. Nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('163','Matthew','Townsend','commodo.auctor.velit@egestasadui.ca','ligula. Aenean euismod');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('164','Oscar','Richards','vulputate.ullamcorper@eueleifendnec.ca','laoreet ipsum. Curabitur consequat, lectus sit');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('165','Gareth','Jackson','nec.diam.Duis@nisl.com','iaculis nec, eleifend non, dapibus rutrum, justo. Praesent luctus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('166','Alice','Hyde','Sed.auctor.odio@tortor.edu','id, libero. Donec consectetuer mauris id sapien. Cras dolor');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('167','Giacomo','Ramos','et.ipsum.cursus@massanon.edu','auctor non, feugiat nec, diam. Duis');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('168','Ciara','Jacobson','Donec.egestas.Aliquam@Aeneangravidanunc.edu','molestie tellus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('169','Logan','Hendricks','luctus@vulputatedui.ca','in, cursus et, eros. Proin ultrices. Duis volutpat nunc');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('170','MacKenzie','Campos','luctus.ut.pellentesque@pellentesquea.edu','erat,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('171','Nina','Best','purus.sapien@aliquet.ca','dolor sit amet, consectetuer');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('172','Chester','Howe','Cum.sociis.natoque@Duis.ca','dui, nec tempus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('173','Nora','Callahan','in.hendrerit@ametconsectetueradipiscing.com','tempus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('174','Molly','Bray','consectetuer@velitSedmalesuada.edu','lorem fringilla ornare placerat, orci lacus vestibulum lorem, sit');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('175','Ariel','Osborn','et@Aeneanegestashendrerit.ca','enim. Sed nulla ante, iaculis nec,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('176','Arsenio','Leblanc','Pellentesque.ut.ipsum@nibh.com','elit pede, malesuada vel, venenatis vel, faucibus id, libero.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('177','Deborah','Bowman','enim.Etiam@primisinfaucibus.ca','eu nibh vulputate mauris');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('178','Delilah','Horton','tincidunt.nunc@arcuet.ca','nec ante. Maecenas mi');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('179','Isaiah','Buckley','Fusce.feugiat@massa.org','ut');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('180','Logan','Jacobs','Phasellus@utsemNulla.ca','ullamcorper eu, euismod');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('181','Lesley','Brown','fringilla@erateget.com','nostra, per inceptos');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('182','Kay','Dodson','a.purus@velpedeblandit.ca','tortor at risus. Nunc ac sem ut');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('183','Yeo','Hayes','vitae.posuere.at@scelerisque.com','a, dui. Cras');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('184','Keegan','Brock','molestie.tellus@convallisestvitae.ca','mi eleifend egestas. Sed pharetra, felis eget varius ultrices,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('185','Kim','Foley','at@acrisusMorbi.com','scelerisque sed, sapien.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('186','Celeste','Delacruz','ipsum.non.arcu@vulputate.edu','Donec fringilla. Donec feugiat metus');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('187','Hilda','Rowe','gravida.sit@nisi.ca','eu nulla at sem molestie sodales. Mauris blandit enim');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('188','Fuller','Mclaughlin','purus.gravida.sagittis@arcu.com','erat. Sed nunc est, mollis non, cursus non, egestas a,');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('189','Madeline','Henderson','lorem.fringilla@cursusdiam.com','Sed pharetra, felis eget varius ultrices, mauris');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('190','Josephine','Osborn','metus@tincidunt.ca','a sollicitudin orci sem eget massa. Suspendisse');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('191','Ivana','Jimenez','justo@egestasSedpharetra.org','Duis risus odio, auctor vitae, aliquet nec, imperdiet nec, leo.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('192','Stephanie','Dickerson','aliquet.nec.imperdiet@Aliquamrutrumlorem.com','nec ante. Maecenas mi felis, adipiscing');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('193','Yardley','Trevino','lacinia.mattis@porttitoreros.edu','lacus.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('194','Carol','Acosta','Donec@aliquetmolestie.ca','arcu');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('195','Lysandra','Mosley','imperdiet@Suspendissesed.org','viverra. Maecenas iaculis aliquet diam.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('196','Tamara','Solis','eleifend.egestas.Sed@duiinsodales.com','sit amet lorem semper auctor. Mauris vel');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('197','Palmer','Perez','nibh@nonduinec.edu','lacus vestibulum lorem, sit amet');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('198','Maia','Donaldson','gravida.Aliquam.tincidunt@volutpatNulladignissim.edu','sit amet luctus vulputate, nisi');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('199','Murphy','Wright','et.pede@aptenttacitisociosqu.ca','non arcu. Vivamus sit amet risus. Donec egestas.');
|
||||
INSERT INTO users (code,first,last,email,quote) VALUES ('200','Omar','Campos','nunc.ac.mattis@luctussitamet.edu','parturient');
|
||||
UPDATE users SET login = lower(first || '.' || last);</value>
|
||||
</data>
|
||||
</root>
|
||||
322
DynamORM.Tests/Select/DynamicAccessTests.cs
Normal file
322
DynamORM.Tests/Select/DynamicAccessTests.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Select
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicAccessTests : TestsBase
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public virtual void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
CreateDynamicDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Tear down test objects.</summary>
|
||||
[TestFixtureTearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
DestroyDynamicDatabase();
|
||||
DestroyTestDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public virtual dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table("users");
|
||||
}
|
||||
|
||||
#region Select
|
||||
|
||||
/// <summary>Test unknown op.</summary>
|
||||
[Test]
|
||||
public void TestUnknownOperation()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(with: "cheese"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public void TestCount()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Count(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public void TestSelectInEnumerableCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }.Take(3)
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public void TestSelectInArrayCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>First</c> method.</summary>
|
||||
[Test]
|
||||
public void TestFirst()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().First(columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Last</c> method.</summary>
|
||||
[Test]
|
||||
public void TestLast()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Last(columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public void TestCountSpecificRecord()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Count(first: "Ori"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public void TestMin()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Min(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public void TestMax()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Max(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public void TesttAvg()
|
||||
{
|
||||
Assert.AreEqual(100.5, GetTestTable().Avg(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Sum</c> method.</summary>
|
||||
[Test]
|
||||
public void TestSum()
|
||||
{
|
||||
Assert.AreEqual(20100, GetTestTable().Sum(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Scalar</c> method for invalid operation exception.</summary>
|
||||
[Test]
|
||||
public void TestScalarException()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar(id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Scalar</c> method.</summary>
|
||||
[Test]
|
||||
public void TestScalar()
|
||||
{
|
||||
Assert.AreEqual("Ori", GetTestTable().Scalar(columns: "first", id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate.</summary>
|
||||
[Test]
|
||||
public void TestScalarGroupConcat()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat("first") AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar(columns: "first:first:group_concat", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
|
||||
[Test]
|
||||
public void TestScalarGroupConcatNoAggregateField()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat(first) AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar(columns: "group_concat(first):first", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test something fancy... like: <code>select "first", count("first") occurs from "users" group by "first" order by 2 desc;</code>.</summary>
|
||||
[Test]
|
||||
public void TestFancyAggregateQuery()
|
||||
{
|
||||
var v = (GetTestTable().Query(columns: "first,first:occurs:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
|
||||
|
||||
Assert.IsNotNull(v);
|
||||
Assert.AreEqual(187, v.Count());
|
||||
Assert.AreEqual(4, v.First().occurs);
|
||||
Assert.AreEqual("Logan", v.First().first);
|
||||
Assert.AreEqual(2, v.Take(10).Last().occurs);
|
||||
Assert.AreEqual(1, v.Take(11).Last().occurs);
|
||||
Assert.AreEqual(1, v.Last().occurs);
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public void TestAggregateInAggregate()
|
||||
{
|
||||
Assert.AreEqual(12.77, GetTestTable().Scalar(columns: @"length(""login""):len:avg"));
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public void TestAggregateInAggregateMark2()
|
||||
{
|
||||
Assert.AreEqual(27.7, GetTestTable().Avg(columns: @"length(""email""):len"));
|
||||
}
|
||||
|
||||
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
|
||||
public void TestFunctionInWhere()
|
||||
{
|
||||
Assert.AreEqual(97,
|
||||
GetTestTable().Count(condition1:
|
||||
new DynamicColumn()
|
||||
{
|
||||
ColumnName = "email",
|
||||
Aggregate = "length",
|
||||
Operator = DynamicColumn.CompareOperator.Gt,
|
||||
Value = 27
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic <c>Single</c> multi.</summary>
|
||||
[Test]
|
||||
public void TestSingleObject()
|
||||
{
|
||||
var exp = new { id = 19, first = "Ori", last = "Ellis" };
|
||||
var o = GetTestTable().Single(columns: "id,first,last", id: 19);
|
||||
|
||||
Assert.AreEqual(exp.id, o.id);
|
||||
Assert.AreEqual(exp.first, o.first);
|
||||
Assert.AreEqual(exp.last, o.last);
|
||||
}
|
||||
|
||||
#endregion Select
|
||||
|
||||
#region Where
|
||||
|
||||
/// <summary>Test dynamic where expression equal.</summary>
|
||||
[Test]
|
||||
public void TestWhereEq()
|
||||
{
|
||||
Assert.AreEqual("hoyt.tran", GetTestTable().Single(where: new DynamicColumn("id").Eq(100)).login);
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression not equal.</summary>
|
||||
[Test]
|
||||
public void TestWhereNot()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("id").Not(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression like.</summary>
|
||||
[Test]
|
||||
public void TestWhereLike()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Single(where: new DynamicColumn("login").Like("Hoyt.%")).id);
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression not like.</summary>
|
||||
[Test]
|
||||
public void TestWhereNotLike()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("login").NotLike("Hoyt.%")));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression greater.</summary>
|
||||
[Test]
|
||||
public void TestWhereGt()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").Greater(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression greater or equal.</summary>
|
||||
[Test]
|
||||
public void TestWhereGte()
|
||||
{
|
||||
Assert.AreEqual(101, GetTestTable().Count(where: new DynamicColumn("id").GreaterOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression less.</summary>
|
||||
[Test]
|
||||
public void TestWhereLt()
|
||||
{
|
||||
Assert.AreEqual(99, GetTestTable().Count(where: new DynamicColumn("id").Less(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression less or equal.</summary>
|
||||
[Test]
|
||||
public void TestWhereLte()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").LessOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression between.</summary>
|
||||
[Test]
|
||||
public void TestWhereBetween()
|
||||
{
|
||||
Assert.AreEqual(26, GetTestTable().Count(where: new DynamicColumn("id").Between(75, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression in params.</summary>
|
||||
[Test]
|
||||
public void TestWhereIn1()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(75, 99, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test dynamic where expression in array.</summary>
|
||||
[Test]
|
||||
public void TestWhereIn2()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));
|
||||
}
|
||||
|
||||
#endregion Where
|
||||
}
|
||||
}
|
||||
55
DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs
Normal file
55
DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Select
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicNoSchemaAccessTests : DynamicAccessTests
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public override void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
CreateDynamicDatabase(
|
||||
DynamicDatabaseOptions.SingleConnection |
|
||||
DynamicDatabaseOptions.SingleTransaction |
|
||||
DynamicDatabaseOptions.SupportLimitOffset);
|
||||
}
|
||||
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public override dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table("users", new string[] { "id" });
|
||||
}
|
||||
}
|
||||
}
|
||||
45
DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs
Normal file
45
DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Select
|
||||
{
|
||||
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
|
||||
[TestFixture]
|
||||
public class DynamicTypeSchemaAccessTests : DynamicNoSchemaAccessTests
|
||||
{
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public override dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table<users>();
|
||||
}
|
||||
}
|
||||
}
|
||||
149
DynamORM.Tests/Select/RenamedTypedAccessTests.cs
Normal file
149
DynamORM.Tests/Select/RenamedTypedAccessTests.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Select
|
||||
{
|
||||
/// <summary>Test typed ORM.</summary>
|
||||
public class RenamedTypedAccessTests : TypedAccessTests<Users>
|
||||
{
|
||||
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
|
||||
[Test]
|
||||
public override void TestTypedFancyAggregateQuery()
|
||||
{
|
||||
var v = (GetTestTable().Query(type: typeof(Users), columns: "first,first:AggregateField:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
|
||||
|
||||
Assert.IsNotNull(v);
|
||||
Assert.AreEqual(187, v.Count());
|
||||
Assert.AreEqual(4, v.First().AggregateField);
|
||||
Assert.AreEqual("Logan", v.First().First);
|
||||
Assert.AreEqual(2, v.Take(10).Last().AggregateField);
|
||||
Assert.AreEqual(1, v.Take(11).Last().AggregateField);
|
||||
Assert.AreEqual(1, v.Last().AggregateField);
|
||||
}
|
||||
|
||||
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
|
||||
[Test]
|
||||
public override void TestGenericFancyAggregateQuery()
|
||||
{
|
||||
var v = (GetTestTable().Query<Users>(columns: "first,first:AggregateField:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
|
||||
|
||||
Assert.IsNotNull(v);
|
||||
Assert.AreEqual(187, v.Count());
|
||||
Assert.AreEqual(4, v.First().AggregateField);
|
||||
Assert.AreEqual("Logan", v.First().First);
|
||||
Assert.AreEqual(2, v.Take(10).Last().AggregateField);
|
||||
Assert.AreEqual(1, v.Take(11).Last().AggregateField);
|
||||
Assert.AreEqual(1, v.Last().AggregateField);
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>First</c> method.</summary>
|
||||
[Test]
|
||||
public override void TestTypedFirst()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().First(type: typeof(Users), columns: "id").Id);
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Last</c> method.</summary>
|
||||
[Test]
|
||||
public override void TestTypedLast()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Last(type: typeof(Users), columns: "id").Id);
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Single</c> multi.</summary>
|
||||
[Test]
|
||||
public override void TestTypedSingleObject()
|
||||
{
|
||||
var exp = new { id = 19, first = "Ori", last = "Ellis" };
|
||||
var o = GetTestTable().Single(type: typeof(Users), columns: "id,first,last", id: 19);
|
||||
|
||||
Assert.AreEqual(exp.id, o.Id);
|
||||
Assert.AreEqual(exp.first, o.First);
|
||||
Assert.AreEqual(exp.last, o.Last);
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression equal.</summary>
|
||||
[Test]
|
||||
public override void TestTypedWhereEq()
|
||||
{
|
||||
Assert.AreEqual("hoyt.tran", GetTestTable().Single(type: typeof(Users), where: new DynamicColumn("id").Eq(100)).Login);
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression like.</summary>
|
||||
[Test]
|
||||
public override void TestTypedWhereLike()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Single(type: typeof(Users), where: new DynamicColumn("login").Like("Hoyt.%")).Id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>First</c> method.</summary>
|
||||
[Test]
|
||||
public override void TestGenericFirst()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().First<Users>(columns: "id").Id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Last</c> method.</summary>
|
||||
[Test]
|
||||
public override void TestGenericLast()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Last<Users>(columns: "id").Id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Single</c> multi.</summary>
|
||||
[Test]
|
||||
public override void TestGenericSingleObject()
|
||||
{
|
||||
var exp = new { id = 19, first = "Ori", last = "Ellis" };
|
||||
var o = GetTestTable().Single<Users>(columns: "id,first,last", id: 19);
|
||||
|
||||
Assert.AreEqual(exp.id, o.Id);
|
||||
Assert.AreEqual(exp.first, o.First);
|
||||
Assert.AreEqual(exp.last, o.Last);
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression equal.</summary>
|
||||
[Test]
|
||||
public override void TestGenericWhereEq()
|
||||
{
|
||||
Assert.AreEqual("hoyt.tran", GetTestTable().Single<Users>(where: new DynamicColumn("id").Eq(100)).Login);
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression like.</summary>
|
||||
[Test]
|
||||
public override void TestGenericWhereLike()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Single<Users>(where: new DynamicColumn("login").Like("Hoyt.%")).Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
604
DynamORM.Tests/Select/TypedAccessTests.cs
Normal file
604
DynamORM.Tests/Select/TypedAccessTests.cs
Normal file
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DynamORM.Tests.Select
|
||||
{
|
||||
/// <summary>Test typed ORM.</summary>
|
||||
/// <typeparam name="T">Type to test.</typeparam>
|
||||
[TestFixture(typeof(users))]
|
||||
public class TypedAccessTests<T> : TestsBase
|
||||
{
|
||||
/// <summary>Setup test parameters.</summary>
|
||||
[TestFixtureSetUp]
|
||||
public virtual void SetUp()
|
||||
{
|
||||
CreateTestDatabase();
|
||||
CreateDynamicDatabase();
|
||||
|
||||
// Cache table (profiler freaks out)
|
||||
GetTestTable();
|
||||
}
|
||||
|
||||
/// <summary>Tear down test objects.</summary>
|
||||
[TestFixtureTearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
DestroyDynamicDatabase();
|
||||
DestroyTestDatabase();
|
||||
}
|
||||
|
||||
/// <summary>Create table using specified method.</summary>
|
||||
/// <returns>Dynamic table.</returns>
|
||||
public virtual dynamic GetTestTable()
|
||||
{
|
||||
return Database.Table();
|
||||
}
|
||||
|
||||
#region Select typed
|
||||
|
||||
/// <summary>Test load all rows into mapped list alternate way.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedGetAll()
|
||||
{
|
||||
var list = (GetTestTable().Query(type: typeof(T)) as IEnumerable<object>).Cast<T>().ToList();
|
||||
|
||||
Assert.AreEqual(200, list.Count);
|
||||
}
|
||||
|
||||
/// <summary>Test unknown op.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedUnknownOperation()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(type: typeof(T), with: "cheese"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedCount()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Count(type: typeof(T), columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedSelectInEnumerableCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }.Take(3)
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedSelectInArrayCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>First</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedFirst()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().First(type: typeof(T), columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Last</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedLast()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Last(type: typeof(T), columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedCountSpecificRecord()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Count(type: typeof(T), first: "Ori"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedMin()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Min(type: typeof(T), columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedMax()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Max(type: typeof(T), columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedtAvg()
|
||||
{
|
||||
Assert.AreEqual(100.5, GetTestTable().Avg(type: typeof(T), columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Sum</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedSum()
|
||||
{
|
||||
Assert.AreEqual(20100, GetTestTable().Sum(type: typeof(T), columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Scalar</c> method for invalid operation exception.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedScalarException()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar(type: typeof(T), id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Scalar</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedScalar()
|
||||
{
|
||||
Assert.AreEqual("Ori", GetTestTable().Scalar(type: typeof(T), columns: "first", id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedScalarGroupConcat()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat("first") AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar(type: typeof(T), columns: "first:first:group_concat", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedScalarGroupConcatNoAggregateField()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat(first) AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar(type: typeof(T), columns: "group_concat(first):first", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedFancyAggregateQuery()
|
||||
{
|
||||
var v = (GetTestTable().Query(type: typeof(T), columns: "first,first:aggregatefield:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
|
||||
|
||||
Assert.IsNotNull(v);
|
||||
Assert.AreEqual(187, v.Count());
|
||||
Assert.AreEqual(4, v.First().aggregatefield);
|
||||
Assert.AreEqual("Logan", v.First().first);
|
||||
Assert.AreEqual(2, v.Take(10).Last().aggregatefield);
|
||||
Assert.AreEqual(1, v.Take(11).Last().aggregatefield);
|
||||
Assert.AreEqual(1, v.Last().aggregatefield);
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedAggregateInAggregate()
|
||||
{
|
||||
Assert.AreEqual(12.77, GetTestTable().Scalar(type: typeof(T), columns: @"length(""login""):len:avg"));
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedAggregateInAggregateMark2()
|
||||
{
|
||||
Assert.AreEqual(27.7, GetTestTable().Avg(type: typeof(T), columns: @"length(""email""):len"));
|
||||
}
|
||||
|
||||
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
|
||||
public virtual void TestTypedFunctionInWhere()
|
||||
{
|
||||
Assert.AreEqual(97,
|
||||
GetTestTable().Count(type: typeof(T), condition1:
|
||||
new DynamicColumn()
|
||||
{
|
||||
ColumnName = "email",
|
||||
Aggregate = "length",
|
||||
Operator = DynamicColumn.CompareOperator.Gt,
|
||||
Value = 27
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test typed <c>Single</c> multi.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedSingleObject()
|
||||
{
|
||||
var exp = new { id = 19, first = "Ori", last = "Ellis" };
|
||||
var o = GetTestTable().Single(type: typeof(T), columns: "id,first,last", id: 19);
|
||||
|
||||
Assert.AreEqual(exp.id, o.id);
|
||||
Assert.AreEqual(exp.first, o.first);
|
||||
Assert.AreEqual(exp.last, o.last);
|
||||
}
|
||||
|
||||
#endregion Select typed
|
||||
|
||||
#region Where typed
|
||||
|
||||
/// <summary>Test typed where expression equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereEq()
|
||||
{
|
||||
Assert.AreEqual("hoyt.tran", GetTestTable().Single(type: typeof(T), where: new DynamicColumn("id").Eq(100)).login);
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression not equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereNot()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Not(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression like.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereLike()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Single(type: typeof(T), where: new DynamicColumn("login").Like("Hoyt.%")).id);
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression not like.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereNotLike()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("login").NotLike("Hoyt.%")));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression greater.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereGt()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Greater(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression greater or equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereGte()
|
||||
{
|
||||
Assert.AreEqual(101, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").GreaterOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression less.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereLt()
|
||||
{
|
||||
Assert.AreEqual(99, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Less(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression less or equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereLte()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").LessOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression between.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereBetween()
|
||||
{
|
||||
Assert.AreEqual(26, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Between(75, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression in params.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereIn1()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(75, 99, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test typed where expression in array.</summary>
|
||||
[Test]
|
||||
public virtual void TestTypedWhereIn2()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));
|
||||
}
|
||||
|
||||
#endregion Where typed
|
||||
|
||||
#region Select generic
|
||||
|
||||
/// <summary>Test load all rows into mapped list alternate way.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericGetAll()
|
||||
{
|
||||
var list = (GetTestTable().Query<T>() as IEnumerable<object>).Cast<T>().ToList();
|
||||
|
||||
Assert.AreEqual(200, list.Count);
|
||||
}
|
||||
|
||||
/// <summary>Test unknown op.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericUnknownOperation()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch<T>(with: "cheese"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericCount()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Count<T>(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericSelectInEnumerableCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }.Take(3)
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test count with in steatement.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericSelectInArrayCount()
|
||||
{
|
||||
Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn
|
||||
{
|
||||
Operator = DynamicColumn.CompareOperator.In,
|
||||
Value = new object[] { "Hendricks", "Goodwin", "Freeman" }
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>First</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericFirst()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().First<T>(columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Last</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericLast()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Last<T>(columns: "id").id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Count</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericCountSpecificRecord()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Count<T>(first: "Ori"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericMin()
|
||||
{
|
||||
Assert.AreEqual(1, GetTestTable().Min<T>(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericMax()
|
||||
{
|
||||
Assert.AreEqual(200, GetTestTable().Max<T>(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Min</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenerictAvg()
|
||||
{
|
||||
Assert.AreEqual(100.5, GetTestTable().Avg<T>(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Sum</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericSum()
|
||||
{
|
||||
Assert.AreEqual(20100, GetTestTable().Sum<T>(columns: "id"));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Scalar</c> method for invalid operation exception.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericScalarException()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar<T>(id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Scalar</c> method.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericScalar()
|
||||
{
|
||||
Assert.AreEqual("Ori", GetTestTable().Scalar<T>(columns: "first", id: 19));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericScalarGroupConcat()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat("first") AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar<T>(columns: "first:first:group_concat", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericScalarGroupConcatNoAggregateField()
|
||||
{
|
||||
// This test should produce something like this:
|
||||
// select group_concat(first) AS first from "users" where "id" < 20;
|
||||
Assert.AreEqual("Clarke,Marny,Dai,Forrest,Blossom,George,Ivory,Inez,Sigourney,Fulton,Logan,Anne,Alexandra,Adena,Lionel,Aimee,Selma,Lara,Ori",
|
||||
GetTestTable().Scalar<T>(columns: "group_concat(first):first", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 }));
|
||||
}
|
||||
|
||||
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericFancyAggregateQuery()
|
||||
{
|
||||
var v = (GetTestTable().Query<T>(columns: "first,first:aggregatefield:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
|
||||
|
||||
Assert.IsNotNull(v);
|
||||
Assert.AreEqual(187, v.Count());
|
||||
Assert.AreEqual(4, v.First().aggregatefield);
|
||||
Assert.AreEqual("Logan", v.First().first);
|
||||
Assert.AreEqual(2, v.Take(10).Last().aggregatefield);
|
||||
Assert.AreEqual(1, v.Take(11).Last().aggregatefield);
|
||||
Assert.AreEqual(1, v.Last().aggregatefield);
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericAggregateInAggregate()
|
||||
{
|
||||
Assert.AreEqual(12.77, GetTestTable().Scalar<T>(columns: @"length(""login""):len:avg"));
|
||||
}
|
||||
|
||||
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericAggregateInAggregateMark2()
|
||||
{
|
||||
Assert.AreEqual(27.7, GetTestTable().Avg<T>(columns: @"length(""email""):len"));
|
||||
}
|
||||
|
||||
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
|
||||
public virtual void TestGenericFunctionInWhere()
|
||||
{
|
||||
Assert.AreEqual(97,
|
||||
GetTestTable().Count<T>(condition1:
|
||||
new DynamicColumn()
|
||||
{
|
||||
ColumnName = "email",
|
||||
Aggregate = "length",
|
||||
Operator = DynamicColumn.CompareOperator.Gt,
|
||||
Value = 27
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>Test generic <c>Single</c> multi.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericSingleObject()
|
||||
{
|
||||
var exp = new { id = 19, first = "Ori", last = "Ellis" };
|
||||
var o = GetTestTable().Single<T>(columns: "id,first,last", id: 19);
|
||||
|
||||
Assert.AreEqual(exp.id, o.id);
|
||||
Assert.AreEqual(exp.first, o.first);
|
||||
Assert.AreEqual(exp.last, o.last);
|
||||
}
|
||||
|
||||
#endregion Select generic
|
||||
|
||||
#region Where generic
|
||||
|
||||
/// <summary>Test generic where expression equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereEq()
|
||||
{
|
||||
Assert.AreEqual("hoyt.tran", GetTestTable().Single<T>(where: new DynamicColumn("id").Eq(100)).login);
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression not equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereNot()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("id").Not(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression like.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereLike()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Single<T>(where: new DynamicColumn("login").Like("Hoyt.%")).id);
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression not like.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereNotLike()
|
||||
{
|
||||
Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("login").NotLike("Hoyt.%")));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression greater.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereGt()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").Greater(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression greater or equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereGte()
|
||||
{
|
||||
Assert.AreEqual(101, GetTestTable().Count<T>(where: new DynamicColumn("id").GreaterOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression less.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereLt()
|
||||
{
|
||||
Assert.AreEqual(99, GetTestTable().Count<T>(where: new DynamicColumn("id").Less(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression less or equal.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereLte()
|
||||
{
|
||||
Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").LessOrEqual(100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression between.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereBetween()
|
||||
{
|
||||
Assert.AreEqual(26, GetTestTable().Count<T>(where: new DynamicColumn("id").Between(75, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression in params.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereIn1()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(75, 99, 100)));
|
||||
}
|
||||
|
||||
/// <summary>Test generic where expression in array.</summary>
|
||||
[Test]
|
||||
public virtual void TestGenericWhereIn2()
|
||||
{
|
||||
Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));
|
||||
}
|
||||
|
||||
#endregion Where generic
|
||||
}
|
||||
}
|
||||
119
DynamORM.Tests/TestsBase.cs
Normal file
119
DynamORM.Tests/TestsBase.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using SQLiteFactory =
|
||||
#if MONO
|
||||
|
||||
Mono.Data.Sqlite.SqliteFactory;
|
||||
|
||||
#else
|
||||
|
||||
System.Data.SQLite.SQLiteFactory;
|
||||
|
||||
#endif
|
||||
|
||||
namespace DynamORM.Tests
|
||||
{
|
||||
/// <summary>Basic test utilities.</summary>
|
||||
public class TestsBase
|
||||
{
|
||||
private string _dbpath = Path.GetTempFileName();
|
||||
|
||||
/// <summary>Gets or sets <see cref="DynamicDatabase"/> instance.</summary>
|
||||
public DynamicDatabase Database { get; set; }
|
||||
|
||||
#region ADO.NET initialization
|
||||
|
||||
/// <summary>Prepare database with some fixed data for tests using plain old ADO.NET.</summary>
|
||||
public void CreateTestDatabase()
|
||||
{
|
||||
Console.Out.Write("Creating database at '{0}'...", _dbpath);
|
||||
|
||||
using (IDbConnection conn = SQLiteFactory.Instance.CreateConnection())
|
||||
{
|
||||
conn.ConnectionString = string.Format("Data Source={0};", _dbpath);
|
||||
conn.Open();
|
||||
|
||||
using (IDbTransaction trans = conn.BeginTransaction())
|
||||
{
|
||||
using (IDbCommand cmd = conn.CreateCommand()
|
||||
.SetCommand(Properties.Resources.UsersTable)
|
||||
.SetTransaction(trans))
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
Console.Out.WriteLine(" Done.");
|
||||
}
|
||||
|
||||
/// <summary>Delete test database file.</summary>
|
||||
public void DestroyTestDatabase()
|
||||
{
|
||||
File.Delete(_dbpath);
|
||||
}
|
||||
|
||||
#endregion ADO.NET initialization
|
||||
|
||||
#region DynamORM Initialization
|
||||
|
||||
/// <summary>Create <see cref="DynamicDatabase"/> with default otions for SQLite.</summary>
|
||||
public void CreateDynamicDatabase()
|
||||
{
|
||||
CreateDynamicDatabase(
|
||||
DynamicDatabaseOptions.SingleConnection |
|
||||
DynamicDatabaseOptions.SingleTransaction |
|
||||
DynamicDatabaseOptions.SupportLimitOffset |
|
||||
DynamicDatabaseOptions.SupportSchema);
|
||||
}
|
||||
|
||||
/// <summary>Create <see cref="DynamicDatabase"/> with specified options.</summary>
|
||||
/// <param name="options">Database options.</param>
|
||||
public void CreateDynamicDatabase(DynamicDatabaseOptions options)
|
||||
{
|
||||
Database = new DynamicDatabase(SQLiteFactory.Instance,
|
||||
string.Format("Data Source={0};", _dbpath), options)
|
||||
{
|
||||
DumpCommands = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Dispose <see cref="DynamicDatabase"/> (and rollback if transaction exist).</summary>
|
||||
public void DestroyDynamicDatabase()
|
||||
{
|
||||
if (Database != null)
|
||||
Database.Dispose();
|
||||
}
|
||||
|
||||
#endregion DynamORM Initialization
|
||||
}
|
||||
}
|
||||
27
DynamORM.sln
Normal file
27
DynamORM.sln
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
# SharpDevelop 4.2.0.8774-RC
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM", "DynamORM\DynamORM.csproj", "{63963ED7-9C78-4672-A4D4-339B6E825503}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM.Tests", "DynamORM.Tests\DynamORM.Tests.csproj", "{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
65
DynamORM/Builders/DynamicDeleteQueryBuilder.cs
Normal file
65
DynamORM/Builders/DynamicDeleteQueryBuilder.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Delete query builder.</summary>
|
||||
public class DynamicDeleteQueryBuilder : DynamicQueryBuilder<DynamicDeleteQueryBuilder>
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicDeleteQueryBuilder"/> class.</summary>
|
||||
/// <param name="table">Parent dynamic table.</param>
|
||||
public DynamicDeleteQueryBuilder(DynamicTable table)
|
||||
: base(table)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
public override IDbCommand FillCommand(IDbCommand command)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat("DELETE FROM {0}", TableName);
|
||||
|
||||
FillWhere(command, sb);
|
||||
|
||||
return command.SetCommand(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public override dynamic Execute()
|
||||
{
|
||||
return DynamicTable.Execute(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
192
DynamORM/Builders/DynamicInsertQueryBuilder.cs
Normal file
192
DynamORM/Builders/DynamicInsertQueryBuilder.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Insert query builder.</summary>
|
||||
public class DynamicInsertQueryBuilder : DynamicQueryBuilder<DynamicInsertQueryBuilder>
|
||||
{
|
||||
/// <summary>Gets list of columns that will be seected.</summary>
|
||||
public IDictionary<string, DynamicColumn> ValueColumns { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicInsertQueryBuilder"/> class.</summary>
|
||||
/// <param name="table">Parent dynamic table.</param>
|
||||
public DynamicInsertQueryBuilder(DynamicTable table)
|
||||
: base(table)
|
||||
{
|
||||
ValueColumns = new Dictionary<string, DynamicColumn>();
|
||||
}
|
||||
|
||||
/// <summary>Add insert fields.</summary>
|
||||
/// <param name="column">Insert column and value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicInsertQueryBuilder Insert(DynamicColumn column)
|
||||
{
|
||||
if (ValueColumns.ContainsKey(column.ColumnName.ToLower()))
|
||||
ValueColumns[column.ColumnName.ToLower()] = column;
|
||||
else
|
||||
ValueColumns.Add(column.ColumnName.ToLower(), column);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add insert fields.</summary>
|
||||
/// <param name="column">Insert column.</param>
|
||||
/// <param name="value">Insert value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicInsertQueryBuilder Insert(string column, object value)
|
||||
{
|
||||
if (value is DynamicColumn)
|
||||
{
|
||||
var v = (DynamicColumn)value;
|
||||
|
||||
if (string.IsNullOrEmpty(v.ColumnName))
|
||||
v.ColumnName = column;
|
||||
|
||||
return Insert(v);
|
||||
}
|
||||
|
||||
if (ValueColumns.ContainsKey(column.ToLower()))
|
||||
ValueColumns[column.ToLower()].Value = value;
|
||||
else
|
||||
ValueColumns.Add(column.ToLower(), new DynamicColumn
|
||||
{
|
||||
ColumnName = column,
|
||||
Value = value
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add insert fields.</summary>
|
||||
/// <param name="o">Set insert value as properties and values of an object.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicInsertQueryBuilder Insert(object o)
|
||||
{
|
||||
var dict = o.ToDictionary();
|
||||
var mapper = DynamicMapperCache.GetMapper(o.GetType());
|
||||
|
||||
if (mapper != null)
|
||||
{
|
||||
foreach (var con in dict)
|
||||
if (!mapper.Ignored.Contains(con.Key))
|
||||
Insert(mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key, con.Value);
|
||||
}
|
||||
else
|
||||
foreach (var con in dict)
|
||||
Insert(con.Key, con.Value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column with operator and value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public override DynamicInsertQueryBuilder Where(DynamicColumn column)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column.</param>
|
||||
/// <param name="op">Condition operator.</param>
|
||||
/// <param name="value">Condition value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public override DynamicInsertQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column.</param>
|
||||
/// <param name="value">Condition value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public override DynamicInsertQueryBuilder Where(string column, object value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="conditions">Set conditions as properties and values of an object.</param>
|
||||
/// <param name="schema">If <c>true</c> use schema to determine key columns and ignore those which
|
||||
/// aren't keys.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public override DynamicInsertQueryBuilder Where(object conditions, bool schema = false)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
public override IDbCommand FillCommand(IDbCommand command)
|
||||
{
|
||||
if (ValueColumns.Count == 0)
|
||||
throw new InvalidOperationException("Insert query should contain columns to change.");
|
||||
|
||||
StringBuilder builderColumns = new StringBuilder();
|
||||
StringBuilder builderValues = new StringBuilder();
|
||||
|
||||
bool first = true;
|
||||
var db = DynamicTable.Database;
|
||||
|
||||
foreach (var v in ValueColumns)
|
||||
{
|
||||
int pos = command.Parameters.Count;
|
||||
|
||||
if (!first)
|
||||
{
|
||||
builderColumns.Append(", ");
|
||||
builderValues.Append(", ");
|
||||
}
|
||||
|
||||
db.DecorateName(builderColumns, v.Value.ColumnName);
|
||||
db.GetParameterName(builderValues, pos);
|
||||
|
||||
command.AddParameter(this, v.Value);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
return command.SetCommand("INSERT INTO {0} ({1}) VALUES ({2})", TableName, builderColumns, builderValues);
|
||||
}
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public override dynamic Execute()
|
||||
{
|
||||
return DynamicTable.Execute(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
381
DynamORM/Builders/DynamicQueryBuilder.cs
Normal file
381
DynamORM/Builders/DynamicQueryBuilder.cs
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Base query builder.</summary>
|
||||
/// <typeparam name="T">Return type of methods that should return self.</typeparam>
|
||||
public abstract class DynamicQueryBuilder<T> : IDynamicQueryBuilder where T : class
|
||||
{
|
||||
/// <summary>Gets <see cref="DynamicTable"/> instance.</summary>
|
||||
public DynamicTable DynamicTable { get; private set; }
|
||||
|
||||
/// <summary>Gets where conditions.</summary>
|
||||
public List<DynamicColumn> WhereConditions { get; private set; }
|
||||
|
||||
/// <summary>Gets table schema.</summary>
|
||||
public Dictionary<string, DynamicSchemaColumn> Schema { get; private set; }
|
||||
|
||||
/// <summary>Gets a value indicating whether database supports standard schema.</summary>
|
||||
public bool SupportSchema { get; private set; }
|
||||
|
||||
/// <summary>Gets table name.</summary>
|
||||
public string TableName { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the DynamicQueryBuilder class.</summary>
|
||||
/// <param name="table">Parent dynamic table.</param>
|
||||
public DynamicQueryBuilder(DynamicTable table)
|
||||
{
|
||||
DynamicTable = table;
|
||||
TableName = table.TableName;
|
||||
|
||||
WhereConditions = new List<DynamicColumn>();
|
||||
|
||||
SupportSchema = (DynamicTable.Database.Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema;
|
||||
|
||||
Schema = DynamicTable.Schema;
|
||||
}
|
||||
|
||||
/// <summary>Set table name.</summary>
|
||||
/// <param name="name">Name of table.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Table(string name)
|
||||
{
|
||||
if (TableName.ToLower() != name.ToLower())
|
||||
{
|
||||
TableName = name;
|
||||
|
||||
Schema = DynamicTable.Database.GetSchema(TableName);
|
||||
|
||||
if (Schema == null)
|
||||
throw new InvalidOperationException("Can't assign type as a table for which schema can't be build.");
|
||||
}
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>Set table name.</summary>
|
||||
/// <typeparam name="Y">Type representing table.</typeparam>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Table<Y>()
|
||||
{
|
||||
return Table(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>Set table name.</summary>
|
||||
/// <param name="type">Type representing table.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Table(Type type)
|
||||
{
|
||||
var mapper = DynamicMapperCache.GetMapper(type);
|
||||
string name = string.Empty;
|
||||
|
||||
if (mapper == null)
|
||||
throw new InvalidOperationException("Cant assign unmapable type as a table.");
|
||||
else
|
||||
name = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
|
||||
mapper.Type.Name : mapper.Table.Name;
|
||||
|
||||
if (TableName.ToLower() != name.ToLower())
|
||||
{
|
||||
TableName = name;
|
||||
|
||||
Schema = DynamicTable.Database.GetSchema(type);
|
||||
}
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column with operator and value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Where(DynamicColumn column)
|
||||
{
|
||||
WhereConditions.Add(column);
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column.</param>
|
||||
/// <param name="op">Condition operator.</param>
|
||||
/// <param name="value">Condition value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Where(string column, DynamicColumn.CompareOperator op, object value)
|
||||
{
|
||||
if (value is DynamicColumn)
|
||||
{
|
||||
var v = (DynamicColumn)value;
|
||||
|
||||
if (string.IsNullOrEmpty(v.ColumnName))
|
||||
v.ColumnName = column;
|
||||
|
||||
return Where(v);
|
||||
}
|
||||
else if (value is IEnumerable<DynamicColumn>)
|
||||
{
|
||||
foreach (var v in (IEnumerable<DynamicColumn>)value)
|
||||
Where(v);
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
WhereConditions.Add(new DynamicColumn
|
||||
{
|
||||
ColumnName = column,
|
||||
Operator = op,
|
||||
Value = value
|
||||
});
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="column">Condition column.</param>
|
||||
/// <param name="value">Condition value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Where(string column, object value)
|
||||
{
|
||||
return Where(column, DynamicColumn.CompareOperator.Eq, value);
|
||||
}
|
||||
|
||||
/// <summary>Add where condition.</summary>
|
||||
/// <param name="conditions">Set conditions as properties and values of an object.</param>
|
||||
/// <param name="schema">If <c>true</c> use schema to determine key columns and ignore those which
|
||||
/// aren't keys.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual T Where(object conditions, bool schema = false)
|
||||
{
|
||||
if (conditions is DynamicColumn)
|
||||
return Where((DynamicColumn)conditions);
|
||||
|
||||
var dict = conditions.ToDictionary();
|
||||
var mapper = DynamicMapperCache.GetMapper(conditions.GetType());
|
||||
|
||||
foreach (var con in dict)
|
||||
{
|
||||
if (mapper.Ignored.Contains(con.Key))
|
||||
continue;
|
||||
|
||||
string colName = mapper != null ? mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key : con.Key;
|
||||
|
||||
DynamicSchemaColumn? col = null;
|
||||
|
||||
if (schema)
|
||||
{
|
||||
col = Schema.TryGetNullable(colName.ToLower());
|
||||
|
||||
if (!col.HasValue)
|
||||
throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", con.Key));
|
||||
|
||||
if (!col.Value.IsKey)
|
||||
continue;
|
||||
|
||||
colName = col.Value.Name;
|
||||
}
|
||||
|
||||
Where(colName, con.Value);
|
||||
}
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>Get string representation of operator.</summary>
|
||||
/// <param name="op">Operator object.</param>
|
||||
/// <returns>String representation of operator.</returns>
|
||||
public string ToOperator(DynamicColumn.CompareOperator op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case DynamicColumn.CompareOperator.Eq: return "=";
|
||||
case DynamicColumn.CompareOperator.Not: return "<>";
|
||||
case DynamicColumn.CompareOperator.Like: return "LIKE";
|
||||
case DynamicColumn.CompareOperator.NotLike: return "NOT LIKE";
|
||||
case DynamicColumn.CompareOperator.Lt: return "<";
|
||||
case DynamicColumn.CompareOperator.Lte: return "<=";
|
||||
case DynamicColumn.CompareOperator.Gt: return ">";
|
||||
case DynamicColumn.CompareOperator.Gte: return ">=";
|
||||
case DynamicColumn.CompareOperator.Between:
|
||||
case DynamicColumn.CompareOperator.In:
|
||||
default:
|
||||
throw new ArgumentException(string.Format("This operator ('{0}') requires more than conversion to string.", op));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Fill where part of a query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <param name="sb">String builder.</param>
|
||||
public virtual void FillWhere(IDbCommand command, StringBuilder sb)
|
||||
{
|
||||
// Yes, this method qualifies fo refactoring... but it's fast
|
||||
bool first = true;
|
||||
var db = DynamicTable.Database;
|
||||
|
||||
foreach (var v in WhereConditions)
|
||||
{
|
||||
var col = Schema.TryGetNullable(v.ColumnName);
|
||||
|
||||
string column = col.HasValue ? col.Value.Name : v.ColumnName;
|
||||
|
||||
if ((column.IndexOf(db.LeftDecorator) == -1 || column.IndexOf(db.LeftDecorator) == -1) &&
|
||||
(column.IndexOf('(') == -1 || column.IndexOf(')') == -1))
|
||||
column = db.DecorateName(column);
|
||||
|
||||
if (v.Value == null)
|
||||
{
|
||||
#region Null operators
|
||||
|
||||
if (v.Operator == DynamicColumn.CompareOperator.Not || v.Operator == DynamicColumn.CompareOperator.Eq)
|
||||
sb.AppendFormat(" {0} {1} IS{2} NULL",
|
||||
first ? "WHERE" : "AND", column,
|
||||
v.Operator == DynamicColumn.CompareOperator.Not ? " NOT" : string.Empty);
|
||||
else
|
||||
throw new InvalidOperationException("NULL can only be compared by IS or IS NOT operator.");
|
||||
|
||||
#endregion
|
||||
}
|
||||
else if (v.Operator != DynamicColumn.CompareOperator.In &&
|
||||
v.Operator != DynamicColumn.CompareOperator.Between)
|
||||
{
|
||||
#region Standard operators
|
||||
|
||||
int pos = command.Parameters.Count;
|
||||
|
||||
sb.AppendFormat(" {0} {1} {2} ",
|
||||
first ? "WHERE" : "AND", column,
|
||||
ToOperator(v.Operator));
|
||||
|
||||
db.GetParameterName(sb, pos);
|
||||
|
||||
command.AddParameter(this, v);
|
||||
|
||||
#endregion
|
||||
}
|
||||
else if (((object)v.Value).GetType().IsCollection() || v.Value is IEnumerable<object>)
|
||||
{
|
||||
#region In or Between operator
|
||||
|
||||
if (v.Operator == DynamicColumn.CompareOperator.Between)
|
||||
{
|
||||
#region Between operator
|
||||
|
||||
var vals = (v.Value as IEnumerable<object>).Take(2).ToList();
|
||||
|
||||
if (vals == null && v.Value is Array)
|
||||
vals = ((Array)v.Value).Cast<object>().ToList();
|
||||
|
||||
if (vals.Count == 2)
|
||||
{
|
||||
sb.AppendFormat(" {0} {1} BETWEEN ",
|
||||
first ? "WHERE" : "AND", column);
|
||||
|
||||
// From parameter
|
||||
db.GetParameterName(sb, command.Parameters.Count);
|
||||
v.Value = vals[0];
|
||||
command.AddParameter(this, v);
|
||||
|
||||
sb.Append(" AND ");
|
||||
|
||||
// To parameter
|
||||
db.GetParameterName(sb, command.Parameters.Count);
|
||||
v.Value = vals[1];
|
||||
command.AddParameter(this, v);
|
||||
|
||||
// Reset value
|
||||
v.Value = vals;
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("BETWEEN must have two values.");
|
||||
|
||||
#endregion
|
||||
}
|
||||
else if (v.Operator == DynamicColumn.CompareOperator.In)
|
||||
{
|
||||
#region In operator
|
||||
|
||||
sb.AppendFormat(" {0} {1} IN(",
|
||||
first ? "WHERE" : "AND", column);
|
||||
|
||||
bool firstParam = true;
|
||||
|
||||
var vals = v.Value as IEnumerable<object>;
|
||||
|
||||
if (vals == null && v.Value is Array)
|
||||
vals = ((Array)v.Value).Cast<object>() as IEnumerable<object>;
|
||||
|
||||
foreach (var val in vals)
|
||||
{
|
||||
int pos = command.Parameters.Count;
|
||||
|
||||
if (!firstParam)
|
||||
sb.Append(", ");
|
||||
|
||||
db.GetParameterName(sb, pos);
|
||||
v.Value = val;
|
||||
|
||||
command.AddParameter(this, v);
|
||||
|
||||
firstParam = false;
|
||||
}
|
||||
|
||||
v.Value = vals;
|
||||
|
||||
sb.Append(")");
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
throw new Exception("BAZINGA. You have reached unreachable code.");
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Operator was {0}, but value wasn't enumerable. Column: '{1}'", v.Operator.ToString().ToUpper(), col));
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
public abstract IDbCommand FillCommand(IDbCommand command);
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Result of an execution..</returns>
|
||||
public abstract dynamic Execute();
|
||||
}
|
||||
}
|
||||
272
DynamORM/Builders/DynamicSelectQueryBuilder.cs
Normal file
272
DynamORM/Builders/DynamicSelectQueryBuilder.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Select query builder.</summary>
|
||||
public class DynamicSelectQueryBuilder : DynamicQueryBuilder<DynamicSelectQueryBuilder>
|
||||
{
|
||||
/// <summary>Gets dictionary of columns that will be seected.</summary>
|
||||
public List<DynamicColumn> Columns { get; private set; }
|
||||
|
||||
/// <summary>Gets dictionary of columns that will be used to group query.</summary>
|
||||
public List<DynamicColumn> Group { get; private set; }
|
||||
|
||||
/// <summary>Gets dictionary of columns that will be used to order query.</summary>
|
||||
public List<DynamicColumn> Order { get; private set; }
|
||||
|
||||
private int? _top = null;
|
||||
private int? _limit = null;
|
||||
private int? _offset = null;
|
||||
private bool _distinct = false;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicSelectQueryBuilder" /> class.</summary>
|
||||
/// <param name="table">Parent dynamic table.</param>
|
||||
public DynamicSelectQueryBuilder(DynamicTable table)
|
||||
: base(table)
|
||||
{
|
||||
Columns = new List<DynamicColumn>();
|
||||
Group = new List<DynamicColumn>();
|
||||
Order = new List<DynamicColumn>();
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to add to object.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Select(params DynamicColumn[] columns)
|
||||
{
|
||||
foreach (var col in columns)
|
||||
Columns.Add(col);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to add to object.</param>
|
||||
/// <remarks>Column format consist of <c>Column Name</c>, <c>Alias</c> and
|
||||
/// <c>Aggregate function</c> in this order separated by '<c>:</c>'.</remarks>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Select(params string[] columns)
|
||||
{
|
||||
return Select(columns.Select(c => DynamicColumn.ParseSelectColumn(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to group by.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder GroupBy(params DynamicColumn[] columns)
|
||||
{
|
||||
foreach (var col in columns)
|
||||
Group.Add(col);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to group by.</param>
|
||||
/// <remarks>Column format consist of <c>Column Name</c> and
|
||||
/// <c>Alias</c> in this order separated by '<c>:</c>'.</remarks>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder GroupBy(params string[] columns)
|
||||
{
|
||||
return GroupBy(columns.Select(c => DynamicColumn.ParseSelectColumn(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to order by.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder OrderBy(params DynamicColumn[] columns)
|
||||
{
|
||||
foreach (var col in columns)
|
||||
Order.Add(col);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add select columns.</summary>
|
||||
/// <param name="columns">Columns to order by.</param>
|
||||
/// <remarks>Column format consist of <c>Column Name</c> and
|
||||
/// <c>Alias</c> in this order separated by '<c>:</c>'.</remarks>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder OrderBy(params string[] columns)
|
||||
{
|
||||
return OrderBy(columns.Select(c => DynamicColumn.ParseOrderByColumn(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Set top if database support it.</summary>
|
||||
/// <param name="top">How many objects select.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Top(int? top)
|
||||
{
|
||||
if ((DynamicTable.Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop)
|
||||
throw new NotSupportedException("Database doesn't support TOP clause.");
|
||||
|
||||
_top = top;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Set top if database support it.</summary>
|
||||
/// <param name="limit">How many objects select.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Limit(int? limit)
|
||||
{
|
||||
if ((DynamicTable.Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset)
|
||||
throw new NotSupportedException("Database doesn't support LIMIT clause.");
|
||||
|
||||
_limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Set top if database support it.</summary>
|
||||
/// <param name="offset">How many objects skip selecting.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Offset(int? offset)
|
||||
{
|
||||
if ((DynamicTable.Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset)
|
||||
throw new NotSupportedException("Database doesn't support OFFSET clause.");
|
||||
|
||||
_offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Set distinct mode.</summary>
|
||||
/// <param name="distinct">Distinct mode.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public DynamicSelectQueryBuilder Distinct(bool distinct = true)
|
||||
{
|
||||
_distinct = distinct;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
public override IDbCommand FillCommand(IDbCommand command)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var db = DynamicTable.Database;
|
||||
|
||||
sb.AppendFormat("SELECT{0}{1} ",
|
||||
_distinct ? " DISTINCT" : string.Empty,
|
||||
_top.HasValue ? string.Format(" TOP {0}", _top.Value) : string.Empty);
|
||||
|
||||
BuildColumns(sb, db);
|
||||
|
||||
sb.Append(" FROM ");
|
||||
db.DecorateName(sb, TableName);
|
||||
|
||||
FillWhere(command, sb);
|
||||
|
||||
BuildGroup(sb, db);
|
||||
BuildOrder(sb, db);
|
||||
|
||||
if (_limit.HasValue)
|
||||
sb.AppendFormat(" LIMIT {0}", _limit.Value);
|
||||
|
||||
if (_offset.HasValue)
|
||||
sb.AppendFormat(" OFFSET {0}", _offset.Value);
|
||||
|
||||
return command.SetCommand(sb.ToString());
|
||||
}
|
||||
|
||||
private void BuildColumns(StringBuilder sb, DynamicDatabase db)
|
||||
{
|
||||
if (Columns.Count > 0)
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
// Not pretty but blazing fast
|
||||
Columns.ForEach(c =>
|
||||
{
|
||||
if (!first)
|
||||
sb.Append(", ");
|
||||
|
||||
c.ToSQLSelectColumn(db, sb);
|
||||
first = false;
|
||||
});
|
||||
}
|
||||
else
|
||||
sb.Append("*");
|
||||
}
|
||||
|
||||
private void BuildGroup(StringBuilder sb, DynamicDatabase db)
|
||||
{
|
||||
if (Group.Count > 0)
|
||||
{
|
||||
sb.Append(" GROUP BY ");
|
||||
bool first = true;
|
||||
|
||||
// Not pretty but blazing fast
|
||||
Group.ForEach(c =>
|
||||
{
|
||||
if (!first)
|
||||
sb.Append(", ");
|
||||
|
||||
c.ToSQLGroupByColumn(db, sb);
|
||||
first = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildOrder(StringBuilder sb, DynamicDatabase db)
|
||||
{
|
||||
if (Order.Count > 0)
|
||||
{
|
||||
sb.Append(" ORDER BY ");
|
||||
bool first = true;
|
||||
|
||||
// Not pretty but blazing fast
|
||||
Order.ForEach(c =>
|
||||
{
|
||||
if (!first)
|
||||
sb.Append(", ");
|
||||
|
||||
c.ToSQLOrderByColumn(db, sb);
|
||||
first = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Enumerator of objects expanded from query.</returns>
|
||||
public override dynamic Execute()
|
||||
{
|
||||
if (Columns.Count <= 1 && ((_top.HasValue && _top.Value == 1) || (_limit.HasValue && _limit.Value == 1)))
|
||||
return DynamicTable.Scalar(this);
|
||||
else
|
||||
return DynamicTable.Query(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
DynamORM/Builders/DynamicUpdateQueryBuilder.cs
Normal file
238
DynamORM/Builders/DynamicUpdateQueryBuilder.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Update query builder.</summary>
|
||||
public class DynamicUpdateQueryBuilder : DynamicQueryBuilder<DynamicUpdateQueryBuilder>
|
||||
{
|
||||
/// <summary>Gets list of columns that will be seected.</summary>
|
||||
public IDictionary<string, DynamicColumn> ValueColumns { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicUpdateQueryBuilder" /> class.</summary>
|
||||
/// <param name="table">Parent dynamic table.</param>
|
||||
public DynamicUpdateQueryBuilder(DynamicTable table)
|
||||
: base(table)
|
||||
{
|
||||
ValueColumns = new Dictionary<string, DynamicColumn>();
|
||||
}
|
||||
|
||||
/// <summary>Add update value or where condition using schema.</summary>
|
||||
/// <param name="column">Update or where column name and value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Update(DynamicColumn column)
|
||||
{
|
||||
var col = Schema.TryGetNullable(column.ColumnName.ToLower());
|
||||
|
||||
if (!col.HasValue && SupportSchema)
|
||||
throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", column));
|
||||
|
||||
if (col.HasValue && col.Value.IsKey)
|
||||
Where(column);
|
||||
else
|
||||
Values(column.ColumnName, column.Value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add update value or where condition using schema.</summary>
|
||||
/// <param name="column">Update or where column name.</param>
|
||||
/// <param name="value">Column value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Update(string column, object value)
|
||||
{
|
||||
var col = Schema.TryGetNullable(column.ToLower());
|
||||
|
||||
if (!col.HasValue && SupportSchema)
|
||||
throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", column));
|
||||
|
||||
if (col.HasValue && col.Value.IsKey)
|
||||
Where(column, value);
|
||||
else
|
||||
Values(column, value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add update values and where condition columns using schema.</summary>
|
||||
/// <param name="conditions">Set values or conditions as properties and values of an object.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Update(object conditions)
|
||||
{
|
||||
if (conditions is DynamicColumn)
|
||||
return Update((DynamicColumn)conditions);
|
||||
|
||||
var dict = conditions.ToDictionary();
|
||||
var mapper = DynamicMapperCache.GetMapper(conditions.GetType());
|
||||
|
||||
foreach (var con in dict)
|
||||
{
|
||||
if (mapper.Ignored.Contains(con.Key))
|
||||
continue;
|
||||
|
||||
string colName = mapper != null ? mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key : con.Key;
|
||||
var col = Schema.TryGetNullable(colName.ToLower());
|
||||
|
||||
if (!col.HasValue && SupportSchema)
|
||||
throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", colName));
|
||||
|
||||
if (col.HasValue)
|
||||
{
|
||||
colName = col.Value.Name;
|
||||
|
||||
if (col.Value.IsKey)
|
||||
{
|
||||
Where(colName, con.Value);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Values(colName, con.Value);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add update fields.</summary>
|
||||
/// <param name="column">Update column and value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Values(DynamicColumn column)
|
||||
{
|
||||
if (ValueColumns.ContainsKey(column.ColumnName.ToLower()))
|
||||
ValueColumns[column.ColumnName.ToLower()] = column;
|
||||
else
|
||||
ValueColumns.Add(column.ColumnName.ToLower(), column);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add update fields.</summary>
|
||||
/// <param name="column">Update column.</param>
|
||||
/// <param name="value">Update value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Values(string column, object value)
|
||||
{
|
||||
if (value is DynamicColumn)
|
||||
{
|
||||
var v = (DynamicColumn)value;
|
||||
|
||||
if (string.IsNullOrEmpty(v.ColumnName))
|
||||
v.ColumnName = column;
|
||||
|
||||
return Values(v);
|
||||
}
|
||||
|
||||
if (ValueColumns.ContainsKey(column.ToLower()))
|
||||
ValueColumns[column.ToLower()].Value = value;
|
||||
else
|
||||
ValueColumns.Add(column.ToLower(), new DynamicColumn
|
||||
{
|
||||
ColumnName = column,
|
||||
Value = value
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Add update fields.</summary>
|
||||
/// <param name="values">Set update value as properties and values of an object.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual DynamicUpdateQueryBuilder Values(object values)
|
||||
{
|
||||
if (values is DynamicColumn)
|
||||
return Values((DynamicColumn)values);
|
||||
|
||||
var dict = values.ToDictionary();
|
||||
var mapper = DynamicMapperCache.GetMapper(values.GetType());
|
||||
|
||||
if (mapper != null)
|
||||
{
|
||||
foreach (var con in dict)
|
||||
if (!mapper.Ignored.Contains(con.Key))
|
||||
Values(mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key, con.Value);
|
||||
}
|
||||
else
|
||||
foreach (var con in dict)
|
||||
Values(con.Key, con.Value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
public override IDbCommand FillCommand(IDbCommand command)
|
||||
{
|
||||
if (ValueColumns.Count == 0)
|
||||
throw new InvalidOperationException("Update query should contain columns to change.");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var db = DynamicTable.Database;
|
||||
|
||||
sb.Append("UPDATE ");
|
||||
db.DecorateName(sb, TableName);
|
||||
sb.Append(" SET ");
|
||||
|
||||
bool first = true;
|
||||
|
||||
foreach (var v in ValueColumns)
|
||||
{
|
||||
int pos = command.Parameters.Count;
|
||||
|
||||
if (!first)
|
||||
sb.Append(", ");
|
||||
|
||||
db.DecorateName(sb, v.Value.ColumnName);
|
||||
sb.Append(" = ");
|
||||
db.GetParameterName(sb, pos);
|
||||
|
||||
command.AddParameter(this, v.Value);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
FillWhere(command, sb);
|
||||
|
||||
return command.SetCommand(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public override dynamic Execute()
|
||||
{
|
||||
return DynamicTable.Execute(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
DynamORM/Builders/IDynamicQueryBuilder.cs
Normal file
55
DynamORM/Builders/IDynamicQueryBuilder.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Base query builder interface.</summary>
|
||||
public interface IDynamicQueryBuilder
|
||||
{
|
||||
/// <summary>Gets <see cref="DynamicTable"/> instance.</summary>
|
||||
DynamicTable DynamicTable { get; }
|
||||
|
||||
/// <summary>Gets table schema.</summary>
|
||||
Dictionary<string, DynamicSchemaColumn> Schema { get; }
|
||||
|
||||
/// <summary>Gets a value indicating whether database supports standard schema.</summary>
|
||||
bool SupportSchema { get; }
|
||||
|
||||
/// <summary>Fill command with query.</summary>
|
||||
/// <param name="command">Command to fill.</param>
|
||||
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
|
||||
IDbCommand FillCommand(IDbCommand command);
|
||||
|
||||
/// <summary>Execute this builder.</summary>
|
||||
/// <returns>Result of an execution..</returns>
|
||||
dynamic Execute();
|
||||
}
|
||||
}
|
||||
79
DynamORM/DynamORM.csproj
Normal file
79
DynamORM/DynamORM.csproj
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{63963ED7-9C78-4672-A4D4-339B6E825503}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DynamORM</RootNamespace>
|
||||
<AssemblyName>DynamORM</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Builders\DynamicDeleteQueryBuilder.cs" />
|
||||
<Compile Include="Builders\DynamicInsertQueryBuilder.cs" />
|
||||
<Compile Include="Builders\DynamicQueryBuilder.cs" />
|
||||
<Compile Include="Builders\DynamicSelectQueryBuilder.cs" />
|
||||
<Compile Include="Builders\DynamicUpdateQueryBuilder.cs" />
|
||||
<Compile Include="Builders\IDynamicQueryBuilder.cs" />
|
||||
<Compile Include="DynamicColumn.cs" />
|
||||
<Compile Include="DynamicCommand.cs" />
|
||||
<Compile Include="DynamicConnection.cs" />
|
||||
<Compile Include="DynamicDatabase.cs" />
|
||||
<Compile Include="DynamicDatabaseOptions.cs" />
|
||||
<Compile Include="DynamicExtensions.cs" />
|
||||
<Compile Include="DynamicSchemaColumn.cs" />
|
||||
<Compile Include="DynamicTable.cs" />
|
||||
<Compile Include="DynamicTransaction.cs" />
|
||||
<Compile Include="Helpers\CollectionComparer.cs" />
|
||||
<Compile Include="Helpers\FrameworkTools.cs" />
|
||||
<Compile Include="Mapper\ColumnAttribute.cs" />
|
||||
<Compile Include="Mapper\DynamicMapperCache.cs" />
|
||||
<Compile Include="Mapper\DynamicPropertyInvoker.cs" />
|
||||
<Compile Include="Mapper\DynamicTypeMap.cs" />
|
||||
<Compile Include="Mapper\IgnoreAttribute.cs" />
|
||||
<Compile Include="Mapper\TableAttribute.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
423
DynamORM/DynamicColumn.cs
Normal file
423
DynamORM/DynamicColumn.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Small utility class to manage single columns.</summary>
|
||||
public class DynamicColumn
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>Order By Order.</summary>
|
||||
public enum SortOrder
|
||||
{
|
||||
/// <summary>Ascending order.</summary>
|
||||
Asc,
|
||||
|
||||
/// <summary>Descending order.</summary>
|
||||
Desc
|
||||
}
|
||||
|
||||
/// <summary>Dynamic query operators.</summary>
|
||||
public enum CompareOperator
|
||||
{
|
||||
/// <summary>Equals operator (default).</summary>
|
||||
Eq,
|
||||
|
||||
/// <summary>Not equal operator.</summary>
|
||||
Not,
|
||||
|
||||
/// <summary>Like operator.</summary>
|
||||
Like,
|
||||
|
||||
/// <summary>Not like operator.</summary>
|
||||
NotLike,
|
||||
|
||||
/// <summary>In operator.</summary>
|
||||
In,
|
||||
|
||||
/// <summary>Less than operator.</summary>
|
||||
Lt,
|
||||
|
||||
/// <summary>Less or equal operator.</summary>
|
||||
Lte,
|
||||
|
||||
/// <summary>Greather than operator.</summary>
|
||||
Gt,
|
||||
|
||||
/// <summary>Greather or equal operator.</summary>
|
||||
Gte,
|
||||
|
||||
/// <summary>Between two values.</summary>
|
||||
Between,
|
||||
}
|
||||
|
||||
#endregion Enums
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicColumn" /> class.</summary>
|
||||
public DynamicColumn() { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicColumn" /> class.</summary>
|
||||
/// <remarks>Constructor provided for easier object creation in qeries.</remarks>
|
||||
/// <param name="columnName">Name of column to set.</param>
|
||||
public DynamicColumn(string columnName)
|
||||
{
|
||||
ColumnName = columnName;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicColumn" /> class.</summary>
|
||||
/// <remarks>Constructor provided for easier object creation in qeries.</remarks>
|
||||
/// <param name="columnName">Name of column to set.</param>
|
||||
/// <param name="oper">Compare column to value(s) operator.</param>
|
||||
/// <param name="value">Parameter value(s).</param>
|
||||
public DynamicColumn(string columnName, CompareOperator oper, object value)
|
||||
: this(columnName)
|
||||
{
|
||||
Operator = oper;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>Gets or sets column name.</summary>
|
||||
public string ColumnName { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column alias.</summary>
|
||||
/// <remarks>Select specific.</remarks>
|
||||
public string Alias { get; set; }
|
||||
|
||||
/// <summary>Gets or sets aggregate function used on column.</summary>
|
||||
/// <remarks>Select specific.</remarks>
|
||||
public string Aggregate { get; set; }
|
||||
|
||||
/// <summary>Gets or sets order direction.</summary>
|
||||
public SortOrder Order { get; set; }
|
||||
|
||||
/// <summary>Gets or sets value for parameters.</summary>
|
||||
public object Value { get; set; }
|
||||
|
||||
/// <summary>Gets or sets condition operator.</summary>
|
||||
public CompareOperator Operator { get; set; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Query creation helpers
|
||||
|
||||
#region Operators
|
||||
|
||||
private DynamicColumn SetOperatorAndValue(CompareOperator c, object v)
|
||||
{
|
||||
Operator = c;
|
||||
Value = v;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Eq"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Eq(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Eq, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Not"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Not(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Not, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Like"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Like(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Like, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.NotLike"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn NotLike(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.NotLike, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Gt"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Greater(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Gt, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Lt"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Less(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Lt, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Gte"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn GreaterOrEqual(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Gte, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Lte"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided <c>value</c>.</summary>
|
||||
/// <param name="value">Value of parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn LessOrEqual(object value)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Lte, value);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.Between"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided values.</summary>
|
||||
/// <param name="from">Value of from parameter to set.</param>
|
||||
/// <param name="to">Value of to parameter to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Between(object from, object to)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.Between, new[] { from, to });
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.In"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided values.</summary>
|
||||
/// <param name="values">Values of parameters to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn In(IEnumerable<object> values)
|
||||
{
|
||||
return SetOperatorAndValue(CompareOperator.In, values);
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Operator"/>
|
||||
/// to <see cref="CompareOperator.In"/> and
|
||||
/// <see cref="DynamicColumn.Value"/> to provided values.</summary>
|
||||
/// <param name="values">Values of parameters to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn In(params object[] values)
|
||||
{
|
||||
if (values.Length == 1 && (values[0].GetType().IsCollection() || values[0] is IEnumerable<object>))
|
||||
return SetOperatorAndValue(CompareOperator.In, values[0]);
|
||||
|
||||
return SetOperatorAndValue(CompareOperator.In, values);
|
||||
}
|
||||
|
||||
#endregion Operators
|
||||
|
||||
#region Order
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Order"/>
|
||||
/// to <see cref="SortOrder.Asc"/>..</summary>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Asc()
|
||||
{
|
||||
Order = SortOrder.Asc;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting <see cref="DynamicColumn.Order"/>
|
||||
/// to <see cref="SortOrder.Desc"/>..</summary>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn Desc()
|
||||
{
|
||||
Order = SortOrder.Desc;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Order
|
||||
|
||||
/// <summary>Helper method setting
|
||||
/// <see cref="DynamicColumn.ColumnName"/>
|
||||
/// to provided <c>name</c>.</summary>
|
||||
/// <param name="name">Name to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn SetName(string name)
|
||||
{
|
||||
ColumnName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting
|
||||
/// <see cref="DynamicColumn.Alias"/>
|
||||
/// to provided <c>alias</c>.</summary>
|
||||
/// <param name="alias">Alias to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn SetAlias(string alias)
|
||||
{
|
||||
Alias = alias;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Helper method setting
|
||||
/// <see cref="DynamicColumn.Aggregate"/>
|
||||
/// to provided <c>aggregate</c>.</summary>
|
||||
/// <param name="aggregate">Aggregate to set.</param>
|
||||
/// <returns>Returns self.</returns>
|
||||
public DynamicColumn SetAggregate(string aggregate)
|
||||
{
|
||||
Aggregate = aggregate;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Query creation helpers
|
||||
|
||||
#region Parsing
|
||||
|
||||
/// <summary>Parse column for select query.</summary>
|
||||
/// <remarks>Column format consist of <c>Column Name</c>, <c>Alias</c> and
|
||||
/// <c>Aggregate function</c> in this order separated by '<c>:</c>'.</remarks>
|
||||
/// <param name="column">Column string.</param>
|
||||
/// <returns>Instance of <see cref="DynamicColumn"/>.</returns>
|
||||
public static DynamicColumn ParseSelectColumn(string column)
|
||||
{
|
||||
// Split column description
|
||||
var parts = column.Split(':');
|
||||
|
||||
if (parts.Length > 0)
|
||||
{
|
||||
DynamicColumn ret = new DynamicColumn() { ColumnName = parts[0] };
|
||||
|
||||
if (parts.Length > 1)
|
||||
ret.Alias = parts[1];
|
||||
|
||||
if (parts.Length > 2)
|
||||
ret.Aggregate = parts[2];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Parse column for order by in query.</summary>
|
||||
/// <remarks>Column format consist of <c>Column Name</c> and
|
||||
/// <c>Direction</c> in this order separated by '<c>:</c>'.</remarks>
|
||||
/// <param name="column">Column string.</param>
|
||||
/// <returns>Instance of <see cref="DynamicColumn"/>.</returns>
|
||||
public static DynamicColumn ParseOrderByColumn(string column)
|
||||
{
|
||||
// Split column description
|
||||
var parts = column.Split(':');
|
||||
|
||||
if (parts.Length > 0)
|
||||
{
|
||||
DynamicColumn ret = new DynamicColumn() { ColumnName = parts[0] };
|
||||
|
||||
if (parts.Length > 1)
|
||||
ret.Order = parts[1].ToLower() == "d" || parts[1].ToLower() == "desc" ? SortOrder.Desc : SortOrder.Asc;
|
||||
|
||||
if (parts.Length > 2)
|
||||
ret.Alias = parts[2];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion Parsing
|
||||
|
||||
#region ToSQL
|
||||
|
||||
internal void ToSQLSelectColumn(DynamicDatabase db, StringBuilder sb)
|
||||
{
|
||||
string column = ColumnName == "*" ? "*" : ColumnName;
|
||||
|
||||
if (column != "*" &&
|
||||
(column.IndexOf(db.LeftDecorator) == -1 || column.IndexOf(db.LeftDecorator) == -1) &&
|
||||
(column.IndexOf('(') == -1 || column.IndexOf(')') == -1))
|
||||
column = db.DecorateName(column);
|
||||
|
||||
string alias = Alias;
|
||||
|
||||
if (!string.IsNullOrEmpty(Aggregate))
|
||||
{
|
||||
sb.AppendFormat("{0}({1})", Aggregate, column);
|
||||
|
||||
alias = string.IsNullOrEmpty(alias) ?
|
||||
ColumnName == "*" ? Guid.NewGuid().ToString() : ColumnName :
|
||||
alias;
|
||||
}
|
||||
else
|
||||
sb.Append(column);
|
||||
|
||||
if (!string.IsNullOrEmpty(alias))
|
||||
sb.AppendFormat(" AS {0}", alias);
|
||||
}
|
||||
|
||||
internal void ToSQLGroupByColumn(DynamicDatabase db, StringBuilder sb)
|
||||
{
|
||||
sb.Append(db.DecorateName(ColumnName));
|
||||
}
|
||||
|
||||
internal void ToSQLOrderByColumn(DynamicDatabase db, StringBuilder sb)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Alias))
|
||||
sb.Append(Alias);
|
||||
else
|
||||
sb.Append(db.DecorateName(ColumnName));
|
||||
|
||||
sb.AppendFormat(" {0}", Order.ToString().ToUpper());
|
||||
}
|
||||
|
||||
#endregion ToSQL
|
||||
}
|
||||
}
|
||||
205
DynamORM/DynamicCommand.cs
Normal file
205
DynamORM/DynamicCommand.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Helper class to easy manage command.</summary>
|
||||
public class DynamicCommand : IDbCommand
|
||||
{
|
||||
private IDbCommand _command;
|
||||
private int? _commandTimeout = null;
|
||||
private DynamicConnection _con;
|
||||
private DynamicDatabase _db;
|
||||
private long _poolStamp = 0;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicCommand"/> class.</summary>
|
||||
/// <param name="con">The connection.</param>
|
||||
/// <param name="db">The databas manager.</param>
|
||||
internal DynamicCommand(DynamicConnection con, DynamicDatabase db)
|
||||
{
|
||||
_con = con;
|
||||
_db = db;
|
||||
|
||||
lock (_db.SyncLock)
|
||||
{
|
||||
if (!_db.CommandsPool.ContainsKey(_con.Connection))
|
||||
throw new InvalidOperationException("Can't create transaction using disposed connection.");
|
||||
else
|
||||
{
|
||||
_command = _con.Connection.CreateCommand();
|
||||
_db.CommandsPool[_con.Connection].Add(_command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Prepare command for execution.</summary>
|
||||
/// <returns>Returns edited <see cref="System.Data.IDbCommand"/> instance.</returns>
|
||||
private IDbCommand PrepareForExecution()
|
||||
{
|
||||
if (_poolStamp < _db.PoolStamp)
|
||||
{
|
||||
_command.CommandTimeout = _commandTimeout ?? _db.CommandTimeout ?? _command.CommandTimeout;
|
||||
|
||||
if (_db.TransactionPool[_command.Connection].Count > 0)
|
||||
_command.Transaction = _db.TransactionPool[_command.Connection].Peek();
|
||||
|
||||
_poolStamp = _db.PoolStamp;
|
||||
}
|
||||
|
||||
return _db.DumpCommands ? _command.Dump(Console.Out) : _command;
|
||||
}
|
||||
|
||||
#region IDbCommand Members
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to cancels the execution of an <see cref="T:System.Data.IDbCommand"/>.
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
_command.Cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text command to run against the data source.
|
||||
/// </summary>
|
||||
/// <returns>The text command to execute. The default value is an empty string ("").</returns>
|
||||
public string CommandText { get { return _command.CommandText; } set { _command.CommandText = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the wait time before terminating the attempt to execute a command and generating an error.
|
||||
/// </summary>
|
||||
/// <returns>The time (in seconds) to wait for the command to execute. The default value is 30 seconds.</returns>
|
||||
/// <exception cref="T:System.ArgumentException">The property value assigned is less than 0. </exception>
|
||||
public int CommandTimeout { get { return _commandTimeout ?? _command.CommandTimeout; } set { _commandTimeout = value; } }
|
||||
|
||||
/// <summary>Gets or sets how the <see cref="P:System.Data.IDbCommand.CommandText"/> property is interpreted.</summary>
|
||||
public CommandType CommandType { get { return _command.CommandType; } set { _command.CommandType = value; } }
|
||||
|
||||
/// <summary>Gets or sets the <see cref="T:System.Data.IDbConnection"/>
|
||||
/// used by this instance of the <see cref="T:System.Data.IDbCommand"/>.</summary>
|
||||
/// <returns>The connection to the data source.</returns>
|
||||
public IDbConnection Connection { get { return _con; } set { _con = (DynamicConnection)value; } }
|
||||
|
||||
/// <summary>Creates a new instance of an
|
||||
/// <see cref="T:System.Data.IDbDataParameter"/> object.</summary>
|
||||
/// <returns>An <see cref="IDbDataParameter"/> object.</returns>
|
||||
public IDbDataParameter CreateParameter()
|
||||
{
|
||||
return _command.CreateParameter();
|
||||
}
|
||||
|
||||
/// <summary>Executes an SQL statement against the Connection object of a
|
||||
/// data provider, and returns the number of rows affected.</summary>
|
||||
/// <returns>The number of rows affected.</returns>
|
||||
public int ExecuteNonQuery()
|
||||
{
|
||||
return PrepareForExecution().ExecuteNonQuery();
|
||||
}
|
||||
|
||||
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
|
||||
/// against the <see cref="P:System.Data.IDbCommand.Connection"/>,
|
||||
/// and builds an <see cref="T:System.Data.IDataReader"/> using one
|
||||
/// of the <see cref="T:System.Data.CommandBehavior"/> values.
|
||||
/// </summary><param name="behavior">One of the
|
||||
/// <see cref="T:System.Data.CommandBehavior"/> values.</param>
|
||||
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
|
||||
public IDataReader ExecuteReader(CommandBehavior behavior)
|
||||
{
|
||||
return PrepareForExecution().ExecuteReader(behavior);
|
||||
}
|
||||
|
||||
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
|
||||
/// against the <see cref="P:System.Data.IDbCommand.Connection"/> and
|
||||
/// builds an <see cref="T:System.Data.IDataReader"/>.</summary>
|
||||
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
|
||||
public IDataReader ExecuteReader()
|
||||
{
|
||||
return PrepareForExecution().ExecuteReader();
|
||||
}
|
||||
|
||||
/// <summary>Executes the query, and returns the first column of the
|
||||
/// first row in the resultset returned by the query. Extra columns or
|
||||
/// rows are ignored.</summary>
|
||||
/// <returns>The first column of the first row in the resultset.</returns>
|
||||
public object ExecuteScalar()
|
||||
{
|
||||
return PrepareForExecution().ExecuteScalar();
|
||||
}
|
||||
|
||||
/// <summary>Gets the <see cref="T:System.Data.IDataParameterCollection"/>.</summary>
|
||||
public IDataParameterCollection Parameters
|
||||
{
|
||||
get { return _command.Parameters; }
|
||||
}
|
||||
|
||||
/// <summary>Creates a prepared (or compiled) version of the command on the data source.</summary>
|
||||
public void Prepare()
|
||||
{
|
||||
_command.Prepare();
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the transaction within which the Command
|
||||
/// object of a data provider executes.</summary>
|
||||
/// <remarks>It's does nothing, transaction is peeked from transaction
|
||||
/// pool of a connection.</remarks>
|
||||
public IDbTransaction Transaction { get { return null; } set { } }
|
||||
|
||||
/// <summary>Gets or sets how command results are applied to the <see cref="T:System.Data.DataRow"/>
|
||||
/// when used by the <see cref="M:System.Data.IDataAdapter.Update(System.Data.DataSet)"/>
|
||||
/// method of a <see cref="T:System.Data.Common.DbDataAdapter"/>.</summary>
|
||||
/// <returns>One of the <see cref="T:System.Data.UpdateRowSource"/> values. The default is
|
||||
/// Both unless the command is automatically generated. Then the default is None.</returns>
|
||||
/// <exception cref="T:System.ArgumentException">The value entered was not one of the
|
||||
/// <see cref="T:System.Data.UpdateRowSource"/> values. </exception>
|
||||
public UpdateRowSource UpdatedRowSource { get { return _command.UpdatedRowSource; } set { _command.UpdatedRowSource = value; } }
|
||||
|
||||
#endregion IDbCommand Members
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with
|
||||
/// freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_db.SyncLock)
|
||||
{
|
||||
var pool = _db.CommandsPool.TryGetValue(_con.Connection);
|
||||
|
||||
if (pool != null)
|
||||
pool.Remove(_command);
|
||||
|
||||
_command.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion IDisposable Members
|
||||
}
|
||||
}
|
||||
153
DynamORM/DynamicConnection.cs
Normal file
153
DynamORM/DynamicConnection.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Connection wrapper.</summary>
|
||||
/// <remarks>This class is only connection holder conection is managed by
|
||||
/// <see cref="DynamicDatabase"/> instance.</remarks>
|
||||
public class DynamicConnection : IDbConnection, IDisposable
|
||||
{
|
||||
private DynamicDatabase _db;
|
||||
private bool _singleTransaction;
|
||||
|
||||
/// <summary>Gets underlaying connection.</summary>
|
||||
internal IDbConnection Connection { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicConnection" /> class.</summary>
|
||||
/// <param name="db">Database connection manager.</param>
|
||||
/// <param name="con">Active connection.</param>
|
||||
/// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param>
|
||||
internal DynamicConnection(DynamicDatabase db, IDbConnection con, bool singleTransaction)
|
||||
{
|
||||
_db = db;
|
||||
Connection = con;
|
||||
_singleTransaction = singleTransaction;
|
||||
}
|
||||
|
||||
/// <summary>Begins a database transaction.</summary>
|
||||
/// <param name="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param>
|
||||
/// <param name="disposed">This action is invoked when transaction is disposed.</param>
|
||||
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
|
||||
internal DynamicTransaction BeginTransaction(IsolationLevel? il, Action disposed)
|
||||
{
|
||||
return new DynamicTransaction(_db, this, _singleTransaction, il, disposed);
|
||||
}
|
||||
|
||||
#region IDbConnection Members
|
||||
|
||||
/// <summary>Creates and returns a Command object associated with the connection.</summary>
|
||||
/// <returns>A Command object associated with the connection.</returns>
|
||||
public IDbCommand CreateCommand()
|
||||
{
|
||||
return new DynamicCommand(this, _db);
|
||||
}
|
||||
|
||||
/// <summary>Begins a database transaction.</summary>
|
||||
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
|
||||
public IDbTransaction BeginTransaction()
|
||||
{
|
||||
return BeginTransaction(null, null);
|
||||
}
|
||||
|
||||
/// <summary>Begins a database transaction with the specified
|
||||
/// <see cref="System.Data.IsolationLevel"/> value.</summary>
|
||||
/// <param name="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param>
|
||||
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
|
||||
public IDbTransaction BeginTransaction(IsolationLevel il)
|
||||
{
|
||||
return BeginTransaction(il, null);
|
||||
}
|
||||
|
||||
/// <summary>Changes the current database for an open Connection object.</summary>
|
||||
/// <param name="databaseName">The name of the database to use in place of the current database.</param>
|
||||
/// <remarks>This operation is not supported in DynamORM. and will throw <see cref="NotSupportedException"/>.</remarks>
|
||||
/// <exception cref="NotSupportedException">Thrown always.</exception>
|
||||
public void ChangeDatabase(string databaseName)
|
||||
{
|
||||
throw new NotSupportedException("This operation is not supported in DynamORM.");
|
||||
}
|
||||
|
||||
/// <summary>Opens a database connection with the settings specified by
|
||||
/// the ConnectionString property of the provider-specific
|
||||
/// Connection object.</summary>
|
||||
/// <remarks>Does nothing. <see cref="DynamicDatabase"/> handles
|
||||
/// opening connections.</remarks>
|
||||
public void Open() { }
|
||||
|
||||
/// <summary>Closes the connection to the database.</summary>
|
||||
/// <remarks>Does nothing. <see cref="DynamicDatabase"/> handles
|
||||
/// closing connections. Only way to close it is to dispose connection.
|
||||
/// It will close if this is multi connection configuration, otherwise
|
||||
/// it will stay open untill <see cref="DynamicDatabase"/> is not
|
||||
/// disposed.</remarks>
|
||||
public void Close() { }
|
||||
|
||||
/// <summary>Gets or sets the string used to open a database.</summary>
|
||||
/// <remarks>Changing connection string operation is not supported in DynamORM.
|
||||
/// and will throw <see cref="NotSupportedException"/>.</remarks>
|
||||
/// <exception cref="NotSupportedException">Thrown always when set is attempted.</exception>
|
||||
public string ConnectionString
|
||||
{
|
||||
get { return Connection.ConnectionString; }
|
||||
set { throw new NotSupportedException("This operation is not supported in DynamORM."); }
|
||||
}
|
||||
|
||||
/// <summary>Gets the time to wait while trying to establish a connection
|
||||
/// before terminating the attempt and generating an error.</summary>
|
||||
public int ConnectionTimeout
|
||||
{
|
||||
get { return Connection.ConnectionTimeout; }
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the current database or the database
|
||||
/// to be used after a connection is opened.</summary>
|
||||
public string Database
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>Gets the current state of the connection.</summary>
|
||||
public ConnectionState State
|
||||
{
|
||||
get { return Connection.State; }
|
||||
}
|
||||
|
||||
#endregion IDbConnection Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing,
|
||||
/// releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_db.Close(Connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
566
DynamORM/DynamicDatabase.cs
Normal file
566
DynamORM/DynamicDatabase.cs
Normal file
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Dynamic database is a class responsible for managing database.</summary>
|
||||
public class DynamicDatabase : IDisposable
|
||||
{
|
||||
#region Internal fields and properties
|
||||
|
||||
private DbProviderFactory _provider;
|
||||
private string _connectionString;
|
||||
private bool _singleConnection;
|
||||
private bool _singleTransaction;
|
||||
private string _leftDecorator = "\"";
|
||||
private string _rightDecorator = "\"";
|
||||
private string _parameterFormat = "@{0}";
|
||||
private int? _commandTimeout = null;
|
||||
private long _poolStamp = 0;
|
||||
|
||||
private DynamicConnection _tempConn = null;
|
||||
|
||||
/// <summary>Provides lock object for this database instance.</summary>
|
||||
internal readonly object SyncLock = new object();
|
||||
|
||||
/// <summary>Gets or sets timestamp of last transaction pool or configuration change.</summary>
|
||||
/// <remarks>This property is used to allow commands to determine if
|
||||
/// they need to update transaction object or not.</remarks>
|
||||
internal long PoolStamp { get { return _poolStamp; } set { lock (SyncLock) _poolStamp = value; } }
|
||||
|
||||
/// <summary>Gets pool of connections and transactions.</summary>
|
||||
internal Dictionary<IDbConnection, Stack<IDbTransaction>> TransactionPool { get; private set; }
|
||||
|
||||
/// <summary>Gets pool of connections and commands.</summary>
|
||||
internal Dictionary<IDbConnection, List<IDbCommand>> CommandsPool { get; private set; }
|
||||
|
||||
/// <summary>Gets schema columns cache.</summary>
|
||||
internal Dictionary<string, Dictionary<string, DynamicSchemaColumn>> Schema { get; private set; }
|
||||
|
||||
/// <summary>Gets tables cache for this database instance.</summary>
|
||||
internal Dictionary<string, DynamicTable> TablesCache { get; private set; }
|
||||
|
||||
#endregion Internal fields and properties
|
||||
|
||||
#region Properties and Constructors
|
||||
|
||||
/// <summary>Gets database options.</summary>
|
||||
public DynamicDatabaseOptions Options { get; private set; }
|
||||
|
||||
/// <summary>Gets or sets command timeout.</summary>
|
||||
public int? CommandTimeout { get { return _commandTimeout; } set { _commandTimeout = value; _poolStamp = DateTime.Now.Ticks; } }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether
|
||||
/// dump commands to console or not.</summary>
|
||||
public bool DumpCommands { get; set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicDatabase" /> class.</summary>
|
||||
/// <param name="provider">Database proider by name.</param>
|
||||
/// <param name="connectionString">Connection string to provided database.</param>
|
||||
/// <param name="options">Connection options.</param>
|
||||
public DynamicDatabase(string provider, string connectionString, DynamicDatabaseOptions options)
|
||||
: this(DbProviderFactories.GetFactory(provider), connectionString, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicDatabase" /> class.</summary>
|
||||
/// <param name="provider">Database proider.</param>
|
||||
/// <param name="connectionString">Connection string to provided database.</param>
|
||||
/// <param name="options">Connection options.</param>
|
||||
public DynamicDatabase(DbProviderFactory provider, string connectionString, DynamicDatabaseOptions options)
|
||||
{
|
||||
_provider = provider;
|
||||
|
||||
InitCommon(connectionString, options);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicDatabase" /> class.</summary>
|
||||
/// <param name="connection">Active database connection.</param>
|
||||
/// <param name="options">Connection options. <see cref="DynamicDatabaseOptions.SingleConnection"/> required.</param>
|
||||
public DynamicDatabase(IDbConnection connection, DynamicDatabaseOptions options)
|
||||
{
|
||||
InitCommon(connection.ConnectionString, options);
|
||||
TransactionPool.Add(connection, new Stack<IDbTransaction>());
|
||||
|
||||
if (!_singleConnection)
|
||||
throw new InvalidOperationException("This constructor accepts only connections with DynamicDatabaseOptions.SingleConnection option.");
|
||||
}
|
||||
|
||||
private void InitCommon(string connectionString, DynamicDatabaseOptions options)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
Options = options;
|
||||
|
||||
_singleConnection = (options & DynamicDatabaseOptions.SingleConnection) == DynamicDatabaseOptions.SingleConnection;
|
||||
_singleTransaction = (options & DynamicDatabaseOptions.SingleTransaction) == DynamicDatabaseOptions.SingleTransaction;
|
||||
|
||||
TransactionPool = new Dictionary<IDbConnection, Stack<IDbTransaction>>();
|
||||
CommandsPool = new Dictionary<IDbConnection, List<IDbCommand>>();
|
||||
Schema = new Dictionary<string, Dictionary<string, DynamicSchemaColumn>>();
|
||||
TablesCache = new Dictionary<string, DynamicTable>();
|
||||
}
|
||||
|
||||
#endregion Properties and Constructors
|
||||
|
||||
#region Table
|
||||
|
||||
/// <summary>Gets dynamic table which is a simple ORM using dynamic objects.</summary>
|
||||
/// <param name="table">Table name.</param>
|
||||
/// <param name="keys">Override keys in schema.</param>
|
||||
/// <returns>Instance of <see cref="DynamicTable"/>.</returns>
|
||||
public dynamic Table(string table = "", string[] keys = null)
|
||||
{
|
||||
string key = string.Concat(
|
||||
table == null ? string.Empty : table,
|
||||
keys == null ? string.Empty : string.Join("_|_", keys));
|
||||
|
||||
DynamicTable dt = null;
|
||||
lock (SyncLock)
|
||||
dt = TablesCache.TryGetValue(key) ??
|
||||
TablesCache.AddAndPassValue(key,
|
||||
new DynamicTable(this, table, keys));
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/// <summary>Gets dynamic table which is a simple ORM using dynamic objects.</summary>
|
||||
/// <typeparam name="T">Type used to determine table name.</typeparam>
|
||||
/// <param name="keys">Override keys in schema.</param>
|
||||
/// <returns>Instance of <see cref="DynamicTable"/>.</returns>
|
||||
public dynamic Table<T>(string[] keys = null)
|
||||
{
|
||||
Type table = typeof(T);
|
||||
string key = string.Concat(
|
||||
table.FullName,
|
||||
keys == null ? string.Empty : string.Join("_|_", keys));
|
||||
|
||||
DynamicTable dt = null;
|
||||
lock (SyncLock)
|
||||
dt = TablesCache.TryGetValue(key) ??
|
||||
TablesCache.AddAndPassValue(key,
|
||||
new DynamicTable(this, table, keys));
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/// <summary>Removes cached table.</summary>
|
||||
/// <param name="dynamicTable">Disposed dynamic table.</param>
|
||||
internal void RemoveFromCache(DynamicTable dynamicTable)
|
||||
{
|
||||
foreach (var item in TablesCache.Where(kvp => kvp.Value == dynamicTable).ToList())
|
||||
TablesCache.Remove(item.Key);
|
||||
}
|
||||
|
||||
#endregion Table
|
||||
|
||||
#region Schema
|
||||
|
||||
/// <summary>Builds table cache if nessesary and returns it.</summary>
|
||||
/// <param name="table">Name of table for which build schema.</param>
|
||||
/// <returns>Table chema.</returns>
|
||||
public Dictionary<string, DynamicSchemaColumn> GetSchema(string table)
|
||||
{
|
||||
Dictionary<string, DynamicSchemaColumn> schema = null;
|
||||
|
||||
lock (SyncLock)
|
||||
schema = Schema.TryGetValue(table.GetType().FullName) ??
|
||||
BuildAndCacheSchema(table, null);
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
/// <summary>Builds table cache if nessesary and returns it.</summary>
|
||||
/// <typeparam name="T">Type of table for which build schema.</typeparam>
|
||||
/// <returns>Table schema or null if type was anonymous.</returns>
|
||||
public Dictionary<string, DynamicSchemaColumn> GetSchema<T>()
|
||||
{
|
||||
if (typeof(T).IsAnonymous())
|
||||
return null;
|
||||
|
||||
Dictionary<string, DynamicSchemaColumn> schema = null;
|
||||
|
||||
lock (SyncLock)
|
||||
schema = Schema.TryGetValue(typeof(T).GetType().FullName) ??
|
||||
BuildAndCacheSchema(null, DynamicMapperCache.GetMapper<T>());
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
/// <summary>Builds table cache if nessesary and returns it.</summary>
|
||||
/// <param name="table">Type of table for which build schema.</param>
|
||||
/// <returns>Table schema or null if type was anonymous.</returns>
|
||||
public Dictionary<string, DynamicSchemaColumn> GetSchema(Type table)
|
||||
{
|
||||
if (table == null || table.IsAnonymous() || table.IsValueType)
|
||||
return null;
|
||||
|
||||
Dictionary<string, DynamicSchemaColumn> schema = null;
|
||||
|
||||
lock (SyncLock)
|
||||
schema = Schema.TryGetValue(table.FullName) ??
|
||||
BuildAndCacheSchema(null, DynamicMapperCache.GetMapper(table));
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
/// <summary>Get schema describing objects from reader.</summary>
|
||||
/// <param name="table">Table from which extract column info.</param>
|
||||
/// <returns>List of <see cref="DynamicSchemaColumn"/> objects .
|
||||
/// If your database doesn't get those values in upper case (like most of the databases) you should override this method.</returns>
|
||||
protected virtual IEnumerable<DynamicSchemaColumn> ReadSchema(string table)
|
||||
{
|
||||
using (var con = Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
using (var rdr = cmd
|
||||
.SetCommand(string.Format("SELECT * FROM {0} WHERE 1 = 0", DecorateName(table)))
|
||||
.ExecuteReader(CommandBehavior.SchemaOnly))
|
||||
foreach (DataRow col in rdr.GetSchemaTable().Rows)
|
||||
{
|
||||
var c = col.RowToDynamicUpper();
|
||||
|
||||
yield return new DynamicSchemaColumn
|
||||
{
|
||||
Name = c.COLUMNNAME,
|
||||
Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String,
|
||||
IsKey = c.ISKEY ?? false,
|
||||
IsUnique = c.ISUNIQUE ?? false,
|
||||
Size = (int)(c.COLUMNSIZE ?? 0),
|
||||
Precision = (byte)(c.NUMERICPRECISION ?? 0),
|
||||
Scale = (byte)(c.NUMERICSCALE ?? 0)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, DynamicSchemaColumn> BuildAndCacheSchema(string tableName, DynamicTypeMap mapper)
|
||||
{
|
||||
Dictionary<string, DynamicSchemaColumn> schema = null;
|
||||
|
||||
if (mapper != null)
|
||||
tableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
|
||||
mapper.Type.Name : mapper.Table.Name;
|
||||
|
||||
bool databaseSchemaSupport = !string.IsNullOrEmpty(tableName) &&
|
||||
(Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema;
|
||||
bool mapperSchema = mapper != null && mapper.Table != null && (mapper.Table.Override || !databaseSchemaSupport);
|
||||
|
||||
#region Database schema
|
||||
|
||||
if (databaseSchemaSupport && !Schema.ContainsKey(tableName.ToLower()))
|
||||
{
|
||||
schema = ReadSchema(tableName)
|
||||
.ToDictionary(k => k.Name.ToLower(), k => k);
|
||||
|
||||
Schema[tableName.ToLower()] = schema;
|
||||
}
|
||||
|
||||
#endregion Database schema
|
||||
|
||||
#region Type schema
|
||||
|
||||
if (mapperSchema && !Schema.ContainsKey(mapper.Type.FullName))
|
||||
{
|
||||
// TODO: Ged rid of this monster below...
|
||||
if (databaseSchemaSupport)
|
||||
{
|
||||
#region Merge with db schema
|
||||
|
||||
schema = mapper.ColumnsMap.ToDictionary(k => k.Key, (v) =>
|
||||
{
|
||||
DynamicSchemaColumn? col = Schema[tableName.ToLower()].TryGetNullable(v.Key);
|
||||
|
||||
return new DynamicSchemaColumn
|
||||
{
|
||||
Name = DynamicExtensions.Coalesce<string>(
|
||||
v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) ? null : v.Value.Column.Name,
|
||||
col.HasValue && !string.IsNullOrEmpty(col.Value.Name) ? col.Value.Name : null,
|
||||
v.Value.Name),
|
||||
IsKey = DynamicExtensions.CoalesceNullable<bool>(
|
||||
v.Value.Column != null ? v.Value.Column.IsKey : false,
|
||||
col.HasValue ? col.Value.IsKey : false).Value,
|
||||
Type = DynamicExtensions.CoalesceNullable<DbType>(
|
||||
v.Value.Column != null ? v.Value.Column.Type : null,
|
||||
col.HasValue ? col.Value.Type : DbType.String).Value,
|
||||
IsUnique = DynamicExtensions.CoalesceNullable<bool>(
|
||||
v.Value.Column != null ? v.Value.Column.IsUnique : null,
|
||||
col.HasValue ? col.Value.IsUnique : false).Value,
|
||||
Size = DynamicExtensions.CoalesceNullable<int>(
|
||||
v.Value.Column != null ? v.Value.Column.Size : null,
|
||||
col.HasValue ? col.Value.Size : 0).Value,
|
||||
Precision = DynamicExtensions.CoalesceNullable<byte>(
|
||||
v.Value.Column != null ? v.Value.Column.Precision : null,
|
||||
col.HasValue ? col.Value.Precision : (byte)0).Value,
|
||||
Scale = DynamicExtensions.CoalesceNullable<byte>(
|
||||
v.Value.Column != null ? v.Value.Column.Scale : null,
|
||||
col.HasValue ? col.Value.Scale : (byte)0).Value,
|
||||
};
|
||||
});
|
||||
|
||||
#endregion Merge with db schema
|
||||
}
|
||||
else
|
||||
{
|
||||
#region MapEnumerable based only on type
|
||||
|
||||
schema = mapper.ColumnsMap.ToDictionary(k => k.Key,
|
||||
v => new DynamicSchemaColumn
|
||||
{
|
||||
Name = DynamicExtensions.Coalesce<string>(v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) ? null : v.Value.Column.Name, v.Value.Name),
|
||||
IsKey = DynamicExtensions.CoalesceNullable<bool>(v.Value.Column != null ? v.Value.Column.IsKey : false, false).Value,
|
||||
Type = DynamicExtensions.CoalesceNullable<DbType>(v.Value.Column != null ? v.Value.Column.Type : null, DbType.String).Value,
|
||||
IsUnique = DynamicExtensions.CoalesceNullable<bool>(v.Value.Column != null ? v.Value.Column.IsUnique : null, false).Value,
|
||||
Size = DynamicExtensions.CoalesceNullable<int>(v.Value.Column != null ? v.Value.Column.Size : null, 0).Value,
|
||||
Precision = DynamicExtensions.CoalesceNullable<byte>(v.Value.Column != null ? v.Value.Column.Precision : null, 0).Value,
|
||||
Scale = DynamicExtensions.CoalesceNullable<byte>(v.Value.Column != null ? v.Value.Column.Scale : null, 0).Value,
|
||||
});
|
||||
|
||||
#endregion MapEnumerable based only on type
|
||||
}
|
||||
}
|
||||
|
||||
if (mapper != null && schema != null)
|
||||
Schema[mapper.Type.FullName] = schema;
|
||||
|
||||
#endregion Type schema
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
#endregion Schema
|
||||
|
||||
#region Decorators
|
||||
|
||||
/// <summary>Gets or sets left side decorator for database objects.</summary>
|
||||
public string LeftDecorator { get { return _leftDecorator; } set { _leftDecorator = value; } }
|
||||
|
||||
/// <summary>Gets or sets right side decorator for database objects.</summary>
|
||||
public string RightDecorator { get { return _rightDecorator; } set { _rightDecorator = value; } }
|
||||
|
||||
/// <summary>Gets or sets parameter name format.</summary>
|
||||
public string ParameterFormat { get { return _parameterFormat; } set { _parameterFormat = value; } }
|
||||
|
||||
/// <summary>Decorate string representing name of database object.</summary>
|
||||
/// <param name="name">Name of database object.</param>
|
||||
/// <returns>Decorated name of database object.</returns>
|
||||
public string DecorateName(string name)
|
||||
{
|
||||
return String.Concat(_leftDecorator, name, _rightDecorator);
|
||||
}
|
||||
|
||||
/// <summary>Decorate string representing name of database object.</summary>
|
||||
/// <param name="sb">String builder to which add decorated name.</param>
|
||||
/// <param name="name">Name of database object.</param>
|
||||
public void DecorateName(StringBuilder sb, string name)
|
||||
{
|
||||
sb.Append(_leftDecorator);
|
||||
sb.Append(name);
|
||||
sb.Append(_rightDecorator);
|
||||
}
|
||||
|
||||
/// <summary>Get database parameter name.</summary>
|
||||
/// <param name="parameter">Friendly parameter name or number.</param>
|
||||
/// <returns>Formatted parameter name.</returns>
|
||||
public string GetParameterName(object parameter)
|
||||
{
|
||||
return String.Format(_parameterFormat, parameter).Replace(" ", "_");
|
||||
}
|
||||
|
||||
/// <summary>Get database parameter name.</summary>
|
||||
/// <param name="sb">String builder to which add parameter name.</param>
|
||||
/// <param name="parameter">Friendly parameter name or number.</param>
|
||||
public void GetParameterName(StringBuilder sb, object parameter)
|
||||
{
|
||||
sb.AppendFormat(_parameterFormat, parameter.ToString().Replace(" ", "_"));
|
||||
}
|
||||
|
||||
#endregion Decorators
|
||||
|
||||
#region Connection
|
||||
|
||||
/// <summary>Open managed connection.</summary>
|
||||
/// <returns>Opened connection.</returns>
|
||||
public IDbConnection Open()
|
||||
{
|
||||
IDbConnection conn = null;
|
||||
DynamicConnection ret = null;
|
||||
|
||||
lock (SyncLock)
|
||||
{
|
||||
if (_tempConn == null)
|
||||
{
|
||||
if (TransactionPool.Count == 0 || !_singleConnection)
|
||||
{
|
||||
conn = _provider.CreateConnection();
|
||||
conn.ConnectionString = _connectionString;
|
||||
conn.Open();
|
||||
|
||||
TransactionPool.Add(conn, new Stack<IDbTransaction>());
|
||||
CommandsPool.Add(conn, new List<IDbCommand>());
|
||||
}
|
||||
else
|
||||
{
|
||||
conn = TransactionPool.Keys.First();
|
||||
|
||||
if (conn.State != ConnectionState.Open)
|
||||
conn.Open();
|
||||
}
|
||||
|
||||
ret = new DynamicConnection(this, conn, _singleTransaction);
|
||||
}
|
||||
else
|
||||
ret = _tempConn;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>Close connection if we are allowed to.</summary>
|
||||
/// <param name="connection">Connection to manage.</param>
|
||||
internal void Close(IDbConnection connection)
|
||||
{
|
||||
if (connection == null)
|
||||
return;
|
||||
|
||||
lock (SyncLock)
|
||||
{
|
||||
if (!_singleConnection && connection != null && TransactionPool.ContainsKey(connection))
|
||||
{
|
||||
// Close all commands
|
||||
if (CommandsPool.ContainsKey(connection))
|
||||
{
|
||||
CommandsPool[connection].ForEach(cmd => cmd.Dispose());
|
||||
CommandsPool[connection].Clear();
|
||||
}
|
||||
|
||||
// Rollback remaining transactions
|
||||
while (TransactionPool[connection].Count > 0)
|
||||
{
|
||||
IDbTransaction trans = TransactionPool[connection].Pop();
|
||||
trans.Rollback();
|
||||
trans.Dispose();
|
||||
}
|
||||
|
||||
// Close connection
|
||||
if (connection.State == ConnectionState.Open)
|
||||
connection.Close();
|
||||
|
||||
// remove from pools
|
||||
TransactionPool.Remove(connection);
|
||||
CommandsPool.Remove(connection);
|
||||
|
||||
// Set stamp
|
||||
_poolStamp = DateTime.Now.Ticks;
|
||||
|
||||
// Dispose the corpse
|
||||
connection.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Connection
|
||||
|
||||
#region Transaction
|
||||
|
||||
/// <summary>Begins a global database transaction.</summary>
|
||||
/// <remarks>Using this method connection is set to single open
|
||||
/// connection untill all transactions are finished.</remarks>
|
||||
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
|
||||
public IDbTransaction BeginTransaction()
|
||||
{
|
||||
_tempConn = Open() as DynamicConnection;
|
||||
|
||||
return _tempConn.BeginTransaction(null, () =>
|
||||
{
|
||||
var t = TransactionPool.TryGetValue(_tempConn.Connection);
|
||||
|
||||
if (t == null | t.Count == 0)
|
||||
{
|
||||
_tempConn.Dispose();
|
||||
_tempConn = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Transaction
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing,
|
||||
/// releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (SyncLock)
|
||||
{
|
||||
var tables = TablesCache.Values.ToList();
|
||||
TablesCache.Clear();
|
||||
|
||||
tables.ForEach(t => t.Dispose());
|
||||
|
||||
foreach (var con in TransactionPool)
|
||||
{
|
||||
// Close all commands
|
||||
if (CommandsPool.ContainsKey(con.Key))
|
||||
{
|
||||
CommandsPool[con.Key].ForEach(cmd => cmd.Dispose());
|
||||
CommandsPool[con.Key].Clear();
|
||||
}
|
||||
|
||||
// Rollback remaining transactions
|
||||
while (con.Value.Count > 0)
|
||||
{
|
||||
IDbTransaction trans = con.Value.Pop();
|
||||
trans.Rollback();
|
||||
trans.Dispose();
|
||||
}
|
||||
|
||||
// Close connection
|
||||
if (con.Key.State == ConnectionState.Open)
|
||||
con.Key.Close();
|
||||
|
||||
// Dispose it
|
||||
con.Key.Dispose();
|
||||
}
|
||||
|
||||
// Clear pools
|
||||
TransactionPool.Clear();
|
||||
CommandsPool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion IDisposable Members
|
||||
}
|
||||
}
|
||||
58
DynamORM/DynamicDatabaseOptions.cs
Normal file
58
DynamORM/DynamicDatabaseOptions.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Represents database connection options.</summary>
|
||||
[Flags]
|
||||
public enum DynamicDatabaseOptions
|
||||
{
|
||||
/// <summary>No specific options.</summary>
|
||||
None,
|
||||
|
||||
/// <summary>Only single presistent database connection.</summary>
|
||||
SingleConnection,
|
||||
|
||||
/// <summary>Only one transaction.</summary>
|
||||
SingleTransaction,
|
||||
|
||||
/// <summary>Database supports top syntax.</summary>
|
||||
SupportTop,
|
||||
|
||||
/// <summary>Database supports limit offset syntax.</summary>
|
||||
SupportLimitOffset,
|
||||
|
||||
/// <summary>Database support standard schema.</summary>
|
||||
SupportSchema,
|
||||
|
||||
/// <summary>Database support stored procedures.</summary>
|
||||
SupportStoredProcedures
|
||||
}
|
||||
}
|
||||
1052
DynamORM/DynamicExtensions.cs
Normal file
1052
DynamORM/DynamicExtensions.cs
Normal file
File diff suppressed because it is too large
Load Diff
57
DynamORM/DynamicSchemaColumn.cs
Normal file
57
DynamORM/DynamicSchemaColumn.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Stores information about column from database schema.</summary>
|
||||
public struct DynamicSchemaColumn
|
||||
{
|
||||
/// <summary>Gets or sets column name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column type.</summary>
|
||||
public DbType Type { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether column is a key.</summary>
|
||||
public bool IsKey { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether column should have unique value.</summary>
|
||||
public bool IsUnique { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column size.</summary>
|
||||
public int Size { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column precision.</summary>
|
||||
public byte Precision { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column scale.</summary>
|
||||
public byte Scale { get; set; }
|
||||
}
|
||||
}
|
||||
786
DynamORM/DynamicTable.cs
Normal file
786
DynamORM/DynamicTable.cs
Normal file
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using DynamORM.Builders;
|
||||
using DynamORM.Helpers;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Dynamic table is a simple ORM using dynamic objects.</summary>
|
||||
/// <example>
|
||||
/// <para>Assume that we have a table representing Users class.</para>
|
||||
/// <para>
|
||||
/// <para>Let's take a look at <c>Query</c> posibilities. Assume we want
|
||||
/// to get enumerator for all records in database, mapped to our class
|
||||
/// instead of dynamic type we can use following syntax.</para>
|
||||
/// <para>Approach first. Use dynamic <c>Query</c> method and just set type
|
||||
/// then just cast it to user class. Remember that you must cast result
|
||||
/// of <c>Query</c>to <c>IEnumerable<object></c>. because from
|
||||
/// point of view of runtime you are operating on <c>object</c> type.</para>
|
||||
/// <code>(db.Table<User>().Query(type: typeof(User)) as IEnumerable<object>).Cast<User>();</code>
|
||||
/// <para>Second approach is similar. We ask database using dynamic
|
||||
/// <c>Query</c> method. The difference is that we use extension method of
|
||||
/// <c>IEnumerable<object></c> (to which we must cast to) to map
|
||||
/// object.</para>
|
||||
/// <code>(db.Table<User>().Query(columns: "*") as IEnumerable<object>).MapEnumerable<User>();</code>
|
||||
/// You can also use generic approach. But be careful this method is currently avaliable thanks to framework hack.
|
||||
/// <code>(db.Table<User>().Query<User>() as IEnumerable<object>).Cast<User>()</code>
|
||||
/// <para>Another approach uses existing methods, but still requires a
|
||||
/// cast, because <c>Query</c> also returns dynamic object enumerator.</para>
|
||||
/// <code>(db.Table<User>().Query().Execute() as IEnumerable<object>).MapEnumerable<User>();</code>
|
||||
/// </para>
|
||||
/// </example>
|
||||
public class DynamicTable : DynamicObject, IDisposable, ICloneable
|
||||
{
|
||||
private static HashSet<string> _allowedCommands = new HashSet<string>
|
||||
{
|
||||
"Insert", "Update", "Delete",
|
||||
"Query", "Single", "Where",
|
||||
"First", "Last", "Get",
|
||||
"Count", "Sum", "Avg",
|
||||
"Min", "Max", "Scalar"
|
||||
};
|
||||
|
||||
/// <summary>Gets dynamic database.</summary>
|
||||
internal DynamicDatabase Database { get; private set; }
|
||||
|
||||
/// <summary>Gets type of table (for coning and schema building).</summary>
|
||||
internal Type TableType { get; private set; }
|
||||
|
||||
/// <summary>Gets name of table.</summary>
|
||||
public virtual string TableName { get; private set; }
|
||||
|
||||
/// <summary>Gets table schema.</summary>
|
||||
/// <remarks>If database doesn't support schema, only key columns are listed here.</remarks>
|
||||
public virtual Dictionary<string, DynamicSchemaColumn> Schema { get; private set; }
|
||||
|
||||
private DynamicTable() { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicTable" /> class.</summary>
|
||||
/// <param name="database">Database and connection management.</param>
|
||||
/// <param name="table">Table name.</param>
|
||||
/// <param name="keys">Override keys in schema.</param>
|
||||
public DynamicTable(DynamicDatabase database, string table = "", string[] keys = null)
|
||||
{
|
||||
Database = database;
|
||||
TableName = table;
|
||||
TableType = null;
|
||||
|
||||
BuildAndCacheSchema(keys);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicTable" /> class.</summary>
|
||||
/// <param name="database">Database and connection management.</param>
|
||||
/// <param name="type">Type describing table.</param>
|
||||
/// <param name="keys">Override keys in schema.</param>
|
||||
public DynamicTable(DynamicDatabase database, Type type, string[] keys = null)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type", "Type can't be null.");
|
||||
|
||||
Database = database;
|
||||
|
||||
TableType = type;
|
||||
|
||||
var mapper = DynamicMapperCache.GetMapper(type);
|
||||
|
||||
if (mapper != null)
|
||||
TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
|
||||
type.Name : mapper.Table.Name;
|
||||
|
||||
BuildAndCacheSchema(keys);
|
||||
}
|
||||
|
||||
#region Schema
|
||||
|
||||
private void BuildAndCacheSchema(string[] keys)
|
||||
{
|
||||
Dictionary<string, DynamicSchemaColumn> schema = null;
|
||||
|
||||
schema = Database.GetSchema(TableType) ??
|
||||
Database.GetSchema(TableName);
|
||||
|
||||
#region Fill currrent table schema
|
||||
|
||||
if (keys == null && TableType != null)
|
||||
{
|
||||
var mapper = DynamicMapperCache.GetMapper(TableType);
|
||||
|
||||
if (mapper != null)
|
||||
{
|
||||
var k = mapper.ColumnsMap.Where(p => p.Value.Column != null && p.Value.Column.IsKey).Select(p => p.Key);
|
||||
if (k.Count() > 0)
|
||||
keys = k.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (schema != null)
|
||||
{
|
||||
if (keys == null)
|
||||
Schema = new Dictionary<string, DynamicSchemaColumn>(schema);
|
||||
else
|
||||
{
|
||||
// TODO: Make this.... nicer
|
||||
List<string> ks = keys.Select(k => k.ToLower()).ToList();
|
||||
|
||||
Schema = schema.ToDictionary(k => k.Key, (v) =>
|
||||
{
|
||||
DynamicSchemaColumn dsc = v.Value;
|
||||
dsc.IsKey = ks.Contains(v.Key);
|
||||
return dsc;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Fill currrent table schema
|
||||
|
||||
#region Build ad-hock schema
|
||||
|
||||
if (keys != null && Schema == null)
|
||||
{
|
||||
Schema = keys.Select(k => k.ToLower()).ToList()
|
||||
.ToDictionary(k => k, k => new DynamicSchemaColumn { Name = k, IsKey = true });
|
||||
}
|
||||
|
||||
#endregion Build ad-hock schema
|
||||
}
|
||||
|
||||
#endregion Schema
|
||||
|
||||
#region Basic Queries
|
||||
|
||||
/// <summary>Enumerate the reader and yield the result.</summary>
|
||||
/// <param name="sql">Sql query containing numered parameters in format provided by
|
||||
/// <see cref="DynamicDatabase.GetParameterName"/> methods. Also names should be formated with
|
||||
/// <see cref="DecorateName.GetParameterName"/> method.</param>
|
||||
/// <param name="args">Arguments (parameters).</param>
|
||||
/// <returns>Enumerator of objects expanded from query.</returns>
|
||||
public virtual IEnumerable<dynamic> Query(string sql, params object[] args)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
using (var rdr = cmd
|
||||
.SetCommand(sql)
|
||||
.AddParameters(Database, args)
|
||||
.ExecuteReader())
|
||||
while (rdr.Read())
|
||||
yield return rdr.RowToDynamic();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Enumerate the reader and yield the result.</summary>
|
||||
/// <param name="builder">Command builder.</param>
|
||||
/// <returns>Enumerator of objects expanded from query.</returns>
|
||||
public virtual IEnumerable<dynamic> Query(IDynamicQueryBuilder builder)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
using (var rdr = cmd
|
||||
.SetCommand(builder)
|
||||
.ExecuteReader())
|
||||
while (rdr.Read())
|
||||
yield return rdr.RowToDynamic();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Create new <see cref="DynamicSelectQueryBuilder"/>.</summary>
|
||||
/// <returns>New <see cref="DynamicSelectQueryBuilder"/> instance.</returns>
|
||||
public virtual DynamicSelectQueryBuilder Query()
|
||||
{
|
||||
return new DynamicSelectQueryBuilder(this);
|
||||
}
|
||||
|
||||
/// <summary>Returns a single result.</summary>
|
||||
/// <param name="sql">Sql query containing numered parameters in format provided by
|
||||
/// <see cref="DynamicDatabase.GetParameterName"/> methods. Also names should be formated with
|
||||
/// <see cref="DecorateName.GetParameterName"/> method.</param>
|
||||
/// <param name="args">Arguments (parameters).</param>
|
||||
/// <returns>Result of a query.</returns>
|
||||
public virtual object Scalar(string sql, params object[] args)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
return cmd
|
||||
.SetCommand(sql).AddParameters(Database, args)
|
||||
.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a single result.</summary>
|
||||
/// <param name="builder">Command builder.</param>
|
||||
/// <returns>Result of a query.</returns>
|
||||
public virtual object Scalar(IDynamicQueryBuilder builder)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
return cmd
|
||||
.SetCommand(builder)
|
||||
.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Execute non query.</summary>
|
||||
/// <param name="sql">Sql query containing numered parameters in format provided by
|
||||
/// <see cref="DynamicDatabase.GetParameterName"/> methods. Also names should be formated with
|
||||
/// <see cref="DecorateName.GetParameterName"/> method.</param>
|
||||
/// <param name="args">Arguments (parameters).</param>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public virtual int Execute(string sql, params object[] args)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
return cmd
|
||||
.SetCommand(sql).AddParameters(Database, args)
|
||||
.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Execute non query.</summary>
|
||||
/// <param name="builder">Command builder.</param>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public virtual int Execute(IDynamicQueryBuilder builder)
|
||||
{
|
||||
using (var con = Database.Open())
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
return cmd
|
||||
.SetCommand(builder)
|
||||
.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Execute non query.</summary>
|
||||
/// <param name="builers">Command builders.</param>
|
||||
/// <returns>Number of affected rows.</returns>
|
||||
public virtual int Execute(IDynamicQueryBuilder[] builers)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
using (var con = Database.Open())
|
||||
{
|
||||
using (var trans = con.BeginTransaction())
|
||||
{
|
||||
foreach (var builder in builers)
|
||||
{
|
||||
using (var cmd = con.CreateCommand())
|
||||
{
|
||||
ret += cmd
|
||||
.SetCommand(builder)
|
||||
.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion Basic Queries
|
||||
|
||||
#region Insert
|
||||
|
||||
/// <summary>Create new <see cref="DynamicInsertQueryBuilder"/>.</summary>
|
||||
/// <returns>New <see cref="DynamicInsertQueryBuilder"/> instance.</returns>
|
||||
public DynamicInsertQueryBuilder Insert()
|
||||
{
|
||||
return new DynamicInsertQueryBuilder(this);
|
||||
}
|
||||
|
||||
/// <summary>Adds a record to the database. You can pass in an Anonymous object, an ExpandoObject,
|
||||
/// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString.</summary>
|
||||
/// <param name="o">Anonymous object, an ExpandoObject, a regular old POCO, or a NameValueCollection
|
||||
/// from a Request.Form or Request.QueryString, containing fields to update.</param>
|
||||
/// <returns>Number of updated rows.</returns>
|
||||
public virtual int Insert(object o)
|
||||
{
|
||||
return Insert()
|
||||
.Insert(o)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
#endregion Insert
|
||||
|
||||
#region Update
|
||||
|
||||
/// <summary>Create new <see cref="DynamicUpdateQueryBuilder"/>.</summary>
|
||||
/// <returns>New <see cref="DynamicUpdateQueryBuilder"/> instance.</returns>
|
||||
public DynamicUpdateQueryBuilder Update()
|
||||
{
|
||||
return new DynamicUpdateQueryBuilder(this);
|
||||
}
|
||||
|
||||
/// <summary>Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject,
|
||||
/// a regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString.</summary>
|
||||
/// <param name="o">Anonymous object, an ExpandoObject, a regular old POCO, or a NameValueCollection
|
||||
/// from a Request.Form or Request.QueryString, containing fields to update.</param>
|
||||
/// <param name="key">Anonymous object, an ExpandoObject, a regular old POCO, or a NameValueCollection
|
||||
/// from a Request.Form or Request.QueryString, containing fields with conditions.</param>
|
||||
/// <returns>Number of updated rows.</returns>
|
||||
public virtual int Update(object o, object key)
|
||||
{
|
||||
return Update()
|
||||
.Values(o)
|
||||
.Where(key)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
/// <summary>Updates a record in the database using schema. You can pass in an Anonymous object, an ExpandoObject,
|
||||
/// a regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString.</summary>
|
||||
/// <param name="o">Anonymous object, an ExpandoObject, a regular old POCO, or a NameValueCollection
|
||||
/// from a Request.Form or Request.QueryString, containing fields to update and conditions.</param>
|
||||
/// <returns>Number of updated rows.</returns>
|
||||
public virtual int Update(object o)
|
||||
{
|
||||
return Update()
|
||||
.Update(o)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
|
||||
#region Delete
|
||||
|
||||
/// <summary>Create new <see cref="DynamicDeleteQueryBuilder"/>.</summary>
|
||||
/// <returns>New <see cref="DynamicDeleteQueryBuilder"/> instance.</returns>
|
||||
public DynamicDeleteQueryBuilder Delete()
|
||||
{
|
||||
return new DynamicDeleteQueryBuilder(this);
|
||||
}
|
||||
|
||||
/// <summary>Removes a record from the database. You can pass in an Anonymous object, an ExpandoObject,
|
||||
/// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString.</summary>
|
||||
/// <param name="o">Anonymous object, an ExpandoObject, a regular old POCO, or a NameValueCollection
|
||||
/// from a Request.Form or Request.QueryString, containing fields with where conditions.</param>
|
||||
/// <param name="schema">If <c>true</c> use schema to determine key columns and ignore those which
|
||||
/// aren't keys.</param>
|
||||
/// <returns>Number of updated rows.</returns>
|
||||
public virtual int Delete(object o, bool schema = true)
|
||||
{
|
||||
return Delete()
|
||||
.Where(o, schema)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
#endregion Delete
|
||||
|
||||
#region Universal Dynamic Invoker
|
||||
|
||||
/// <summary>This is where the magic begins.</summary>
|
||||
/// <param name="binder">Binder to invoke.</param>
|
||||
/// <param name="args">Binder arguments.</param>
|
||||
/// <param name="result">Binder invoke result.</param>
|
||||
/// <returns>Returns <c>true</c> if invoke was performed.</returns>
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// parse the method
|
||||
var info = binder.CallInfo;
|
||||
|
||||
// Get generic types
|
||||
var types = binder.GetGenericTypeArguments();
|
||||
|
||||
// accepting named args only... SKEET!
|
||||
if (info.ArgumentNames.Count != args.Length)
|
||||
throw new InvalidOperationException("Please use named arguments for this type of query - the column name, orderby, columns, etc");
|
||||
|
||||
var op = binder.Name;
|
||||
|
||||
// Avoid strange things
|
||||
if (!_allowedCommands.Contains(op))
|
||||
throw new InvalidOperationException(string.Format("Dynamic method '{0}' is not supported.", op));
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case "Insert":
|
||||
result = DynamicInsert(args, info, types);
|
||||
break;
|
||||
case "Update":
|
||||
result = DynamicUpdate(args, info, types);
|
||||
break;
|
||||
case "Delete":
|
||||
result = DynamicDelete(args, info, types);
|
||||
break;
|
||||
default:
|
||||
result = DynamicQuery(args, info, op, types);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private object DynamicInsert(object[] args, CallInfo info, IList<Type> types)
|
||||
{
|
||||
var builder = new DynamicInsertQueryBuilder(this);
|
||||
|
||||
if (types != null && types.Count == 1)
|
||||
HandleTypeArgument<DynamicInsertQueryBuilder>(null, info, ref types, builder, 0);
|
||||
|
||||
// loop the named args - see if we have order, columns and constraints
|
||||
if (info.ArgumentNames.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var name = info.ArgumentNames[i].ToLower();
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "table":
|
||||
if (args[i] is string)
|
||||
builder.Table(args[i].ToString());
|
||||
else goto default;
|
||||
break;
|
||||
case "values":
|
||||
builder.Insert(args[i]);
|
||||
break;
|
||||
case "type":
|
||||
if (types == null || types.Count == 0)
|
||||
HandleTypeArgument<DynamicInsertQueryBuilder>(args, info, ref types, builder, i);
|
||||
else goto default;
|
||||
break;
|
||||
default:
|
||||
builder.Insert(name, args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute
|
||||
return Execute(builder);
|
||||
}
|
||||
|
||||
private object DynamicUpdate(object[] args, CallInfo info, IList<Type> types)
|
||||
{
|
||||
var builder = new DynamicUpdateQueryBuilder(this);
|
||||
|
||||
if (types != null && types.Count == 1)
|
||||
HandleTypeArgument<DynamicUpdateQueryBuilder>(null, info, ref types, builder, 0);
|
||||
|
||||
// loop the named args - see if we have order, columns and constraints
|
||||
if (info.ArgumentNames.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var name = info.ArgumentNames[i].ToLower();
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "table":
|
||||
if (args[i] is string)
|
||||
builder.Table(args[i].ToString());
|
||||
else goto default;
|
||||
break;
|
||||
case "update":
|
||||
builder.Update(args[i]);
|
||||
break;
|
||||
case "values":
|
||||
builder.Values(args[i]);
|
||||
break;
|
||||
case "where":
|
||||
builder.Where(args[i]);
|
||||
break;
|
||||
case "type":
|
||||
if (types == null || types.Count == 0)
|
||||
HandleTypeArgument(args, info, ref types, builder, i);
|
||||
else goto default;
|
||||
break;
|
||||
default:
|
||||
builder.Update(name, args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute
|
||||
return Execute(builder);
|
||||
}
|
||||
|
||||
private object DynamicDelete(object[] args, CallInfo info, IList<Type> types)
|
||||
{
|
||||
var builder = new DynamicDeleteQueryBuilder(this);
|
||||
|
||||
if (types != null && types.Count == 1)
|
||||
HandleTypeArgument<DynamicDeleteQueryBuilder>(null, info, ref types, builder, 0);
|
||||
|
||||
// loop the named args - see if we have order, columns and constraints
|
||||
if (info.ArgumentNames.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var name = info.ArgumentNames[i].ToLower();
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "table":
|
||||
if (args[i] is string)
|
||||
builder.Table(args[i].ToString());
|
||||
else goto default;
|
||||
break;
|
||||
case "where":
|
||||
builder.Where(args[i], false);
|
||||
break;
|
||||
case "delete":
|
||||
builder.Where(args[i], true);
|
||||
break;
|
||||
case "type":
|
||||
if (types == null || types.Count == 0)
|
||||
HandleTypeArgument<DynamicDeleteQueryBuilder>(args, info, ref types, builder, i);
|
||||
else goto default;
|
||||
break;
|
||||
default:
|
||||
builder.Where(name, args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute
|
||||
return Execute(builder);
|
||||
}
|
||||
|
||||
private object DynamicQuery(object[] args, CallInfo info, string op, IList<Type> types)
|
||||
{
|
||||
object result;
|
||||
var builder = new DynamicSelectQueryBuilder(this);
|
||||
|
||||
if (types != null && types.Count == 1)
|
||||
HandleTypeArgument<DynamicSelectQueryBuilder>(null, info, ref types, builder, 0);
|
||||
|
||||
// loop the named args - see if we have order, columns and constraints
|
||||
if (info.ArgumentNames.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var name = info.ArgumentNames[i].ToLower();
|
||||
|
||||
// TODO: Make this nicer
|
||||
switch (name)
|
||||
{
|
||||
case "order":
|
||||
if (args[i] is string)
|
||||
builder.OrderBy(((string)args[i]).Split(','));
|
||||
else if (args[i] is string[])
|
||||
builder.OrderBy(args[i] as string);
|
||||
else if (args[i] is DynamicColumn[])
|
||||
builder.OrderBy((DynamicColumn[])args[i]);
|
||||
else if (args[i] is DynamicColumn)
|
||||
builder.OrderBy((DynamicColumn)args[i]);
|
||||
else goto default;
|
||||
break;
|
||||
case "group":
|
||||
if (args[i] is string)
|
||||
builder.GroupBy(((string)args[i]).Split(','));
|
||||
else if (args[i] is string[])
|
||||
builder.GroupBy(args[i] as string);
|
||||
else if (args[i] is DynamicColumn[])
|
||||
builder.GroupBy((DynamicColumn[])args[i]);
|
||||
else if (args[i] is DynamicColumn)
|
||||
builder.GroupBy((DynamicColumn)args[i]);
|
||||
else goto default;
|
||||
break;
|
||||
case "columns":
|
||||
if (args[i] is string)
|
||||
builder.Select(((string)args[i]).Split(','));
|
||||
else if (args[i] is string[])
|
||||
builder.Select(args[i] as string);
|
||||
else if (args[i] is DynamicColumn[])
|
||||
builder.Select((DynamicColumn[])args[i]);
|
||||
else if (args[i] is DynamicColumn)
|
||||
builder.Select((DynamicColumn)args[i]);
|
||||
else goto default;
|
||||
break;
|
||||
case "where":
|
||||
builder.Where(args[i]);
|
||||
break;
|
||||
case "table":
|
||||
if (args[i] is string)
|
||||
builder.Table(args[i].ToString());
|
||||
else goto default;
|
||||
break;
|
||||
case "type":
|
||||
if (types == null || types.Count == 0)
|
||||
HandleTypeArgument<DynamicSelectQueryBuilder>(args, info, ref types, builder, i);
|
||||
else goto default;
|
||||
break;
|
||||
default:
|
||||
builder.Where(name, args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (op == "Count" && builder.Columns.Count == 0)
|
||||
{
|
||||
result = Scalar(builder.Select(new DynamicColumn
|
||||
{
|
||||
ColumnName = "*",
|
||||
Aggregate = op.ToUpper(),
|
||||
Alias = "Count"
|
||||
}));
|
||||
|
||||
if (result is long)
|
||||
result = (int)(long)result;
|
||||
}
|
||||
else if (op == "Sum" || op == "Max" ||
|
||||
op == "Min" || op == "Avg" || op == "Count")
|
||||
{
|
||||
if (builder.Columns.Count == 0)
|
||||
throw new InvalidOperationException("You must select at least one column to agregate.");
|
||||
|
||||
foreach (var o in builder.Columns)
|
||||
o.Aggregate = op.ToUpper();
|
||||
|
||||
if (builder.Columns.Count == 1)
|
||||
{
|
||||
result = Scalar(builder);
|
||||
|
||||
if (op == "Count" && result is long)
|
||||
result = (int)(long)result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Query(builder).FirstOrDefault(); // return lots
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// build the SQL
|
||||
var justOne = op == "First" || op == "Last" || op == "Get" || op == "Single";
|
||||
|
||||
// Be sure to sort by DESC on selected columns
|
||||
if (op == "Last")
|
||||
{
|
||||
if (builder.Order.Count > 0)
|
||||
foreach (var o in builder.Order)
|
||||
o.Order = o.Order == DynamicColumn.SortOrder.Desc ?
|
||||
DynamicColumn.SortOrder.Asc : DynamicColumn.SortOrder.Desc;
|
||||
}
|
||||
|
||||
if (justOne && !(op == "Last" && builder.Order.Count == 0))
|
||||
{
|
||||
if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
|
||||
builder.Limit(1);
|
||||
else if ((Database.Options & DynamicDatabaseOptions.SupportTop) == DynamicDatabaseOptions.SupportTop)
|
||||
builder.Top(1);
|
||||
}
|
||||
|
||||
if (op == "Scalar")
|
||||
{
|
||||
if (builder.Columns.Count != 1)
|
||||
throw new InvalidOperationException("You must select one column in scalar steatement.");
|
||||
|
||||
result = Scalar(builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (justOne)
|
||||
{
|
||||
if (op == "Last" && builder.Order.Count == 0)
|
||||
result = Query(builder).LastOrDefault(); // Last record fallback
|
||||
else
|
||||
result = Query(builder).FirstOrDefault(); // return a single record
|
||||
}
|
||||
else
|
||||
result = Query(builder); // return lots
|
||||
|
||||
// MapEnumerable to specified result (still needs to be casted after that)
|
||||
if (types != null)
|
||||
{
|
||||
if (types.Count == 1)
|
||||
result = justOne ?
|
||||
result.Map(types[0]) :
|
||||
((IEnumerable<object>)result).MapEnumerable(types[0]);
|
||||
|
||||
// TODO: Dictionaries
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void HandleTypeArgument<T>(object[] args, CallInfo info, ref IList<Type> types, DynamicQueryBuilder<T> builder, int i) where T : class
|
||||
{
|
||||
if (args != null)
|
||||
{
|
||||
if (args[i] is Type[])
|
||||
types = new List<Type>((Type[])args[i]);
|
||||
else if (args[i] is Type)
|
||||
types = new List<Type>(new Type[] { (Type)args[i] });
|
||||
}
|
||||
|
||||
if (types != null && types.Count == 1 && !info.ArgumentNames.Any(a => a.ToLower() == "table"))
|
||||
builder.Table(types[0]);
|
||||
}
|
||||
|
||||
#endregion Universal Dynamic Invoker
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with
|
||||
/// freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Database.RemoveFromCache(this);
|
||||
|
||||
// Lose reference but don't kill it.
|
||||
if (Database != null)
|
||||
Database = null;
|
||||
}
|
||||
|
||||
#endregion IDisposable Members
|
||||
|
||||
#region ICloneable Members
|
||||
|
||||
/// <summary>Creates a new object that is a copy of the current
|
||||
/// instance.</summary>
|
||||
/// <returns>A new object that is a copy of this instance.</returns>
|
||||
public object Clone()
|
||||
{
|
||||
return new DynamicTable()
|
||||
{
|
||||
Database = this.Database,
|
||||
Schema = this.Schema,
|
||||
TableName = this.TableName,
|
||||
TableType = this.TableType
|
||||
};
|
||||
}
|
||||
|
||||
#endregion ICloneable Members
|
||||
}
|
||||
}
|
||||
138
DynamORM/DynamicTransaction.cs
Normal file
138
DynamORM/DynamicTransaction.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <summary>Helper class to easy manage transaction.</summary>
|
||||
public class DynamicTransaction : IDbTransaction, IDisposable
|
||||
{
|
||||
private DynamicDatabase _db;
|
||||
private DynamicConnection _con;
|
||||
private bool _singleTransaction;
|
||||
private Action _disposed;
|
||||
private bool _operational = false;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicTransaction" /> class.</summary>
|
||||
/// <param name="db">Database connection manager.</param>
|
||||
/// <param name="con">Active connection.</param>
|
||||
/// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param>
|
||||
/// <param name="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param>
|
||||
/// <param name="disposed">This action is invoked when transaction is disposed.</param>
|
||||
internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed)
|
||||
{
|
||||
_db = db;
|
||||
_con = con;
|
||||
_singleTransaction = singleTransaction;
|
||||
_disposed = disposed;
|
||||
|
||||
lock (_db.SyncLock)
|
||||
{
|
||||
if (!_db.TransactionPool.ContainsKey(_con.Connection))
|
||||
throw new InvalidOperationException("Can't create transaction using disposed connection.");
|
||||
else if (_singleTransaction && _db.TransactionPool[_con.Connection].Count > 0)
|
||||
_operational = false;
|
||||
else
|
||||
{
|
||||
_db.TransactionPool[_con.Connection].Push(_con.Connection.BeginTransaction());
|
||||
_db.PoolStamp = DateTime.Now.Ticks;
|
||||
_operational = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Commits the database transaction.</summary>
|
||||
public void Commit()
|
||||
{
|
||||
lock (_db.SyncLock)
|
||||
{
|
||||
if (_operational)
|
||||
{
|
||||
var t = _db.TransactionPool.TryGetValue(_con.Connection);
|
||||
|
||||
if (t != null && t.Count > 0)
|
||||
{
|
||||
IDbTransaction trans = t.Pop();
|
||||
|
||||
_db.PoolStamp = DateTime.Now.Ticks;
|
||||
|
||||
trans.Commit();
|
||||
trans.Dispose();
|
||||
}
|
||||
|
||||
_operational = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Rolls back a transaction from a pending state.</summary>
|
||||
public void Rollback()
|
||||
{
|
||||
lock (_db.SyncLock)
|
||||
{
|
||||
if (_operational)
|
||||
{
|
||||
var t = _db.TransactionPool.TryGetValue(_con.Connection);
|
||||
|
||||
if (t != null && t.Count > 0)
|
||||
{
|
||||
IDbTransaction trans = t.Pop();
|
||||
|
||||
_db.PoolStamp = DateTime.Now.Ticks;
|
||||
|
||||
trans.Rollback();
|
||||
trans.Dispose();
|
||||
}
|
||||
|
||||
_operational = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets connection object to associate with the transaction.</summary>
|
||||
public IDbConnection Connection
|
||||
{
|
||||
get { return _con; }
|
||||
}
|
||||
|
||||
/// <summary>Gets <see cref="System.Data.IsolationLevel"/> for this transaction.</summary>
|
||||
public IsolationLevel IsolationLevel { get; private set; }
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with
|
||||
/// freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Rollback();
|
||||
|
||||
if (_disposed != null)
|
||||
_disposed();
|
||||
}
|
||||
}
|
||||
}
|
||||
126
DynamORM/Helpers/CollectionComparer.cs
Normal file
126
DynamORM/Helpers/CollectionComparer.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DynamORM.Helpers
|
||||
{
|
||||
/// <summary>Defines methods to support the comparison of collections for equality.</summary>
|
||||
/// <typeparam name="T">The type of collection to compare.</typeparam>
|
||||
public class CollectionComparer<T> : IEqualityComparer<IEnumerable<T>>
|
||||
{
|
||||
/// <summary>Determines whether the specified objects are equal.</summary>
|
||||
/// <param name="first">The first object of type T to compare.</param>
|
||||
/// <param name="second">The second object of type T to compare.</param>
|
||||
/// <returns>Returns <c>true</c> if the specified objects are equal; otherwise, <c>false</c>.</returns>
|
||||
bool IEqualityComparer<IEnumerable<T>>.Equals(IEnumerable<T> first, IEnumerable<T> second)
|
||||
{
|
||||
return Equals(first, second);
|
||||
}
|
||||
|
||||
/// <summary>Returns a hash code for the specified object.</summary>
|
||||
/// <param name="enumerable">The enumerable for which a hash code is to be returned.</param>
|
||||
/// <returns>A hash code for the specified object.</returns>
|
||||
int IEqualityComparer<IEnumerable<T>>.GetHashCode(IEnumerable<T> enumerable)
|
||||
{
|
||||
return GetHashCode(enumerable);
|
||||
}
|
||||
|
||||
/// <summary>Returns a hash code for the specified object.</summary>
|
||||
/// <param name="enumerable">The enumerable for which a hash code is to be returned.</param>
|
||||
/// <returns>A hash code for the specified object.</returns>
|
||||
public static int GetHashCode(IEnumerable<T> enumerable)
|
||||
{
|
||||
int hash = 17;
|
||||
|
||||
foreach (T val in enumerable.OrderBy(x => x))
|
||||
hash = (hash * 23) + val.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the specified objects are equal.</summary>
|
||||
/// <param name="first">The first object of type T to compare.</param>
|
||||
/// <param name="second">The second object of type T to compare.</param>
|
||||
/// <returns>Returns <c>true</c> if the specified objects are equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool Equals(IEnumerable<T> first, IEnumerable<T> second)
|
||||
{
|
||||
if ((first == null) != (second == null))
|
||||
return false;
|
||||
|
||||
if (!object.ReferenceEquals(first, second) && (first != null))
|
||||
{
|
||||
if (first.Count() != second.Count())
|
||||
return false;
|
||||
|
||||
if ((first.Count() != 0) && HaveMismatchedElement(first, second))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool HaveMismatchedElement(IEnumerable<T> first, IEnumerable<T> second)
|
||||
{
|
||||
int firstCount;
|
||||
int secondCount;
|
||||
|
||||
var firstElementCounts = GetElementCounts(first, out firstCount);
|
||||
var secondElementCounts = GetElementCounts(second, out secondCount);
|
||||
|
||||
if (firstCount != secondCount)
|
||||
return true;
|
||||
|
||||
foreach (var kvp in firstElementCounts)
|
||||
if (kvp.Value != (secondElementCounts.TryGetNullable(kvp.Key) ?? 0))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<T, int> GetElementCounts(IEnumerable<T> enumerable, out int nullCount)
|
||||
{
|
||||
var dictionary = new Dictionary<T, int>();
|
||||
nullCount = 0;
|
||||
|
||||
foreach (T element in enumerable)
|
||||
{
|
||||
if (element == null)
|
||||
nullCount++;
|
||||
else
|
||||
{
|
||||
int count = dictionary.TryGetNullable(element) ?? 0;
|
||||
dictionary[element] = ++count;
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
156
DynamORM/Helpers/FrameworkTools.cs
Normal file
156
DynamORM/Helpers/FrameworkTools.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DynamORM.Helpers
|
||||
{
|
||||
/// <summary>Framework detection and specific implementations.</summary>
|
||||
public static class FrameworkTools
|
||||
{
|
||||
#region Mono or .NET Framework detection
|
||||
|
||||
/// <summary>This is preaty simple trick.</summary>
|
||||
private static bool _isMono = Type.GetType("Mono.Runtime") != null;
|
||||
|
||||
/// <summary>Gets a value indicating whether application is running under mono runtime.</summary>
|
||||
public static bool IsMono { get { return _isMono; } }
|
||||
|
||||
#endregion Mono or .NET Framework detection
|
||||
|
||||
static FrameworkTools()
|
||||
{
|
||||
_frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter();
|
||||
}
|
||||
|
||||
#region GetGenericTypeArguments
|
||||
|
||||
private static Func<InvokeMemberBinder, IList<Type>> _frameworkTypeArgumentsGetter = null;
|
||||
|
||||
private static Func<InvokeMemberBinder, IList<Type>> CreateTypeArgumentsGetter()
|
||||
{
|
||||
// HACK: Creating binders assuming types are correct... this may fail.
|
||||
if (IsMono)
|
||||
{
|
||||
var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder");
|
||||
|
||||
if (binderType != null)
|
||||
{
|
||||
ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o");
|
||||
|
||||
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
|
||||
Expression.TypeAs(
|
||||
Expression.Field(
|
||||
Expression.TypeAs(param, binderType), "typeArguments"),
|
||||
typeof(IList<Type>)), param).Compile();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
|
||||
|
||||
if (inter != null)
|
||||
{
|
||||
var prop = inter.GetProperty("TypeArguments");
|
||||
|
||||
if (!prop.CanRead)
|
||||
return null;
|
||||
|
||||
var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o");
|
||||
|
||||
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
|
||||
Expression.TypeAs(
|
||||
Expression.Property(
|
||||
Expression.TypeAs(objParm, inter), prop.Name),
|
||||
typeof(IList<Type>)), objParm).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Extension method allowing to easyly extract generic type
|
||||
/// arguments from <see cref="InvokeMemberBinder"/> assuming that it
|
||||
/// inherits from
|
||||
/// <c>Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder</c>
|
||||
/// in .NET Framework or
|
||||
/// <c>Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder</c>
|
||||
/// under Mono.</summary>
|
||||
/// <param name="binder">Binder from which get type arguments.</param>
|
||||
/// <remarks>This is generally a bad solution, but there is no other
|
||||
/// currently so we have to go with it.</remarks>
|
||||
/// <returns>List of types passed as generic parameters.</returns>
|
||||
public static IList<Type> GetGenericTypeArguments(this InvokeMemberBinder binder)
|
||||
{
|
||||
// First try to use delegate if exist
|
||||
if (_frameworkTypeArgumentsGetter != null)
|
||||
return _frameworkTypeArgumentsGetter(binder);
|
||||
|
||||
if (_isMono)
|
||||
{
|
||||
// HACK: Using Reflection
|
||||
// In mono this is trivial.
|
||||
|
||||
// First we get field info.
|
||||
var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance |
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
// If this was a success get and return it's value
|
||||
if (field != null)
|
||||
return field.GetValue(binder) as IList<Type>;
|
||||
}
|
||||
else
|
||||
{
|
||||
// HACK: Using Reflection
|
||||
// In this case, we need more aerobic :D
|
||||
|
||||
// First, get the interface
|
||||
var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
|
||||
|
||||
if (inter != null)
|
||||
{
|
||||
// Now get property.
|
||||
var prop = inter.GetProperty("TypeArguments");
|
||||
|
||||
// If we have a property, return it's value
|
||||
if (prop != null)
|
||||
return prop.GetValue(binder, null) as IList<Type>;
|
||||
}
|
||||
}
|
||||
|
||||
// Sadly return null if failed.
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion GetGenericTypeArguments
|
||||
}
|
||||
}
|
||||
148
DynamORM/Mapper/ColumnAttribute.cs
Normal file
148
DynamORM/Mapper/ColumnAttribute.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Allows to add table name to class.</summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnAttribute : Attribute
|
||||
{
|
||||
/// <summary>Gets or sets name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column type.</summary>
|
||||
/// <remarks>Used when overriding schema.</remarks>
|
||||
public DbType? Type { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether column is a key.</summary>
|
||||
public bool IsKey { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether column should have unique value.</summary>
|
||||
/// <remarks>Used when overriding schema.</remarks>
|
||||
public bool? IsUnique { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column size.</summary>
|
||||
/// <remarks>Used when overriding schema.</remarks>
|
||||
public int? Size { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column precision.</summary>
|
||||
/// <remarks>Used when overriding schema.</remarks>
|
||||
public byte? Precision { get; set; }
|
||||
|
||||
/// <summary>Gets or sets column scale.</summary>
|
||||
/// <remarks>Used when overriding schema.</remarks>
|
||||
public byte? Scale { get; set; }
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
public ColumnAttribute() { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
public ColumnAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
public ColumnAttribute(string name, bool isKey)
|
||||
: this(name)
|
||||
{
|
||||
IsKey = isKey;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
/// <param name="type">Set column type.</param>
|
||||
public ColumnAttribute(string name, bool isKey, DbType type)
|
||||
: this(name, isKey)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
/// <param name="type">Set column type.</param>
|
||||
/// <param name="size">Set column value size.</param>
|
||||
public ColumnAttribute(string name, bool isKey, DbType type, int size)
|
||||
: this(name, isKey, type)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
/// <param name="type">Set column type.</param>
|
||||
/// <param name="precision">Set column value precision.</param>
|
||||
/// <param name="scale">Set column value scale.</param>
|
||||
public ColumnAttribute(string name, bool isKey, DbType type, byte precision, byte scale)
|
||||
: this(name, isKey, type)
|
||||
{
|
||||
Precision = precision;
|
||||
Scale = scale;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
/// <param name="type">Set column type.</param>
|
||||
/// <param name="size">Set column value size.</param>
|
||||
/// <param name="precision">Set column value precision.</param>
|
||||
/// <param name="scale">Set column value scale.</param>
|
||||
public ColumnAttribute(string name, bool isKey, DbType type, int size, byte precision, byte scale)
|
||||
: this(name, isKey, type, precision, scale)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
|
||||
/// <param name="name">Name of column.</param>
|
||||
/// <param name="isKey">Set column as a key column.</param>
|
||||
/// <param name="isUnique">Set column has unique value.</param>
|
||||
/// <param name="type">Set column type.</param>
|
||||
/// <param name="size">Set column value size.</param>
|
||||
/// <param name="precision">Set column value precision.</param>
|
||||
/// <param name="scale">Set column value scale.</param>
|
||||
public ColumnAttribute(string name, bool isKey, bool isUnique, DbType type, int size, byte precision, byte scale)
|
||||
: this(name, isKey, type, size, precision, scale)
|
||||
{
|
||||
IsUnique = isUnique;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
}
|
||||
}
|
||||
74
DynamORM/Mapper/DynamicMapperCache.cs
Normal file
74
DynamORM/Mapper/DynamicMapperCache.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Class with maper cache.</summary>
|
||||
public static class DynamicMapperCache
|
||||
{
|
||||
private static readonly object SyncLock = new object();
|
||||
private static Dictionary<Type, DynamicTypeMap> _cache = new Dictionary<Type, DynamicTypeMap>();
|
||||
|
||||
/// <summary>Get type mapper.</summary>
|
||||
/// <typeparam name="T">Type of mapper.</typeparam>
|
||||
/// <returns>Type mapper.</returns>
|
||||
public static DynamicTypeMap GetMapper<T>()
|
||||
{
|
||||
return GetMapper(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>Get type mapper.</summary>
|
||||
/// <param name="type">Type of mapper.</param>
|
||||
/// <returns>Type mapper.</returns>
|
||||
public static DynamicTypeMap GetMapper(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
return null;
|
||||
/*if (type.IsAnonymous())
|
||||
return null;*/
|
||||
|
||||
DynamicTypeMap mapper = null;
|
||||
|
||||
lock (SyncLock)
|
||||
{
|
||||
if (!_cache.TryGetValue(type, out mapper))
|
||||
{
|
||||
mapper = new DynamicTypeMap(type);
|
||||
|
||||
if (mapper != null)
|
||||
_cache.Add(type, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
DynamORM/Mapper/DynamicPropertyInvoker.cs
Normal file
102
DynamORM/Mapper/DynamicPropertyInvoker.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Dynamic property invoker.</summary>
|
||||
public class DynamicPropertyInvoker
|
||||
{
|
||||
/// <summary>Gets value getter.</summary>
|
||||
public Func<object, object> Get { get; private set; }
|
||||
|
||||
/// <summary>Gets value setter.</summary>
|
||||
public Action<object, object> Set { get; private set; }
|
||||
|
||||
/// <summary>Gets name of property.</summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>Gets type column description.</summary>
|
||||
public ColumnAttribute Column { get; private set; }
|
||||
|
||||
/// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary>
|
||||
public bool Ignore { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary>
|
||||
/// <param name="property">Property info to be invoked in the future.</param>
|
||||
/// <param name="attr">Column attribute if exist.</param>
|
||||
public DynamicPropertyInvoker(PropertyInfo property, ColumnAttribute attr)
|
||||
{
|
||||
Name = property.Name;
|
||||
|
||||
var ignore = property.GetCustomAttributes(typeof(IgnoreAttribute), false);
|
||||
|
||||
Ignore = ignore != null && ignore.Length > 0;
|
||||
|
||||
Column = attr;
|
||||
|
||||
Get = CreateGetter(property);
|
||||
Set = CreateSetter(property);
|
||||
}
|
||||
|
||||
private Func<object, object> CreateGetter(PropertyInfo property)
|
||||
{
|
||||
if (!property.CanRead)
|
||||
return null;
|
||||
|
||||
var objParm = Expression.Parameter(typeof(object), "o");
|
||||
|
||||
return Expression.Lambda<Func<object, object>>(
|
||||
Expression.Convert(
|
||||
Expression.Property(
|
||||
Expression.TypeAs(objParm, property.DeclaringType),
|
||||
property.Name),
|
||||
typeof(object)), objParm).Compile();
|
||||
}
|
||||
|
||||
private Action<object, object> CreateSetter(PropertyInfo property)
|
||||
{
|
||||
if (!property.CanWrite)
|
||||
return null;
|
||||
|
||||
var objParm = Expression.Parameter(typeof(object), "o");
|
||||
var valueParm = Expression.Parameter(typeof(object), "value");
|
||||
|
||||
return Expression.Lambda<Action<object, object>>(
|
||||
Expression.Assign(
|
||||
Expression.Property(
|
||||
Expression.Convert(objParm, property.DeclaringType),
|
||||
property.Name),
|
||||
Expression.Convert(valueParm, property.PropertyType)),
|
||||
objParm, valueParm).Compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
134
DynamORM/Mapper/DynamicTypeMap.cs
Normal file
134
DynamORM/Mapper/DynamicTypeMap.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Represents type columnMap.</summary>
|
||||
public class DynamicTypeMap
|
||||
{
|
||||
/// <summary>Gets mapper destination type creator.</summary>
|
||||
public Type Type { get; private set; }
|
||||
|
||||
/// <summary>Gets type table description.</summary>
|
||||
public TableAttribute Table { get; private set; }
|
||||
|
||||
/// <summary>Gets object creator.</summary>
|
||||
public Func<object> Creator { get; private set; }
|
||||
|
||||
/// <summary>Gets map of columns to properties.</summary>
|
||||
public Dictionary<string, DynamicPropertyInvoker> ColumnsMap { get; private set; }
|
||||
|
||||
/// <summary>Gets map of properties to column.</summary>
|
||||
public Dictionary<string, string> PropertyMap { get; private set; }
|
||||
|
||||
/// <summary>Gets list of ignored properties.</summary>
|
||||
public List<string> Ignored { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="DynamicTypeMap" /> class.</summary>
|
||||
/// <param name="type">Type to which columnMap objects.</param>
|
||||
public DynamicTypeMap(Type type)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
var attr = type.GetCustomAttributes(typeof(TableAttribute), false);
|
||||
|
||||
if (attr != null && attr.Length > 0)
|
||||
Table = (TableAttribute)attr[0];
|
||||
|
||||
Creator = CreateCreator();
|
||||
CreateColumnAndPropertyMap();
|
||||
}
|
||||
|
||||
private void CreateColumnAndPropertyMap()
|
||||
{
|
||||
var columnMap = new Dictionary<string, DynamicPropertyInvoker>();
|
||||
var propertyMap = new Dictionary<string, string>();
|
||||
|
||||
foreach (var pi in Type.GetProperties())
|
||||
{
|
||||
ColumnAttribute attr = null;
|
||||
|
||||
var attrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
|
||||
|
||||
if (attrs != null && attrs.Length > 0)
|
||||
attr = (ColumnAttribute)attrs[0];
|
||||
|
||||
string col = attr == null || string.IsNullOrEmpty(attr.Name) ? pi.Name : attr.Name;
|
||||
|
||||
var val = new DynamicPropertyInvoker(pi, attr);
|
||||
columnMap.Add(col.ToLower(), val);
|
||||
|
||||
propertyMap.Add(pi.Name, col);
|
||||
}
|
||||
|
||||
ColumnsMap = columnMap;
|
||||
PropertyMap = propertyMap;
|
||||
|
||||
Ignored = columnMap.Where(i => i.Value.Ignore).Select(i => i.Value.Name).ToList();
|
||||
}
|
||||
|
||||
private Func<object> CreateCreator()
|
||||
{
|
||||
if (Type.GetConstructor(Type.EmptyTypes) != null)
|
||||
return Expression.Lambda<Func<object>>(Expression.New(Type)).Compile();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Create object of <see cref="DynamicTypeMap.Type"/> type and fill values from <c>source</c>.</summary>
|
||||
/// <param name="source">Object containing values that will be mapped to newy created object.</param>
|
||||
/// <returns>New object of <see cref="DynamicTypeMap.Type"/> type with matching values from <c>source</c>.</returns>
|
||||
public object Create(object source)
|
||||
{
|
||||
return Map(source, Creator());
|
||||
}
|
||||
|
||||
/// <summary>Fill values from <c>source</c> to <see cref="DynamicTypeMap.Type"/> object in <c>destination</c>.</summary>
|
||||
/// <param name="source">Object containing values that will be mapped to newy created object.</param>
|
||||
/// <param name="destination">Object of <see cref="DynamicTypeMap.Type"/> type to which copy values from <c>source</c>.</param>
|
||||
/// <returns>Object of <see cref="DynamicTypeMap.Type"/> type with matching values from <c>source</c>.</returns>
|
||||
public object Map(object source, object destination)
|
||||
{
|
||||
DynamicPropertyInvoker dpi = null;
|
||||
|
||||
foreach (var item in source.ToDictionary())
|
||||
{
|
||||
if (ColumnsMap.TryGetValue(item.Key.ToLower(), out dpi) && item.Value != null)
|
||||
if (dpi.Set != null)
|
||||
dpi.Set(destination, item.Value);
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
DynamORM/Mapper/IgnoreAttribute.cs
Normal file
39
DynamORM/Mapper/IgnoreAttribute.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Allows to add ignore action to property.</summary>
|
||||
/// <remarks>Property still get's mapped from output.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class IgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
46
DynamORM/Mapper/TableAttribute.cs
Normal file
46
DynamORM/Mapper/TableAttribute.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Allows to add table name to class.</summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TableAttribute : Attribute
|
||||
{
|
||||
/// <summary>Gets or sets name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether overide database
|
||||
/// schema values.</summary>
|
||||
/// <remarks>If database doeesn't support schema, you still have to
|
||||
/// set this to true to get schema from type.</remarks>
|
||||
public bool Override { get; set; }
|
||||
}
|
||||
}
|
||||
65
DynamORM/Properties/AssemblyInfo.cs
Normal file
65
DynamORM/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* See: http://opensource.org/licenses/bsd-license.php
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
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("DynamORM")]
|
||||
[assembly: AssemblyDescription("Dynamic Object-Relational Mapping library.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("RUSSEK Software")]
|
||||
[assembly: AssemblyProduct("DynamORM")]
|
||||
[assembly: AssemblyCopyright("Copyright © RUSSEK Software 2012")]
|
||||
[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("0a42480b-bba7-4b01-807f-9962a76e4e47")]
|
||||
|
||||
// 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.1")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.1")]
|
||||
Reference in New Issue
Block a user