2 Commits

Author SHA1 Message Date
grzegorz.russek
b589aabaa3 Polishing 2013-06-04 17:44:51 +00:00
grzegorz.russek
61081ae371 Mark stable version 2013-06-04 17:27:27 +00:00
90 changed files with 1792 additions and 29564 deletions

View File

@@ -1,60 +0,0 @@
<?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)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A64D2052-D0CD-488E-BF05-E5952615D926}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AmalgamationTool</RootNamespace>
<AssemblyName>AmalgamationTool</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<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|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DynamORM.Amalgamation.cs">
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Include="Program.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>

File diff suppressed because it is too large Load Diff

View File

@@ -1,154 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace AmalgamationTool
{
internal class Program
{
private static void Main(string[] args)
{
List<string> usings = new List<string>();
Dictionary<string, List<string>> classes = new Dictionary<string, List<string>>();
// Build a file using string builder.
StringBuilder sb = new StringBuilder();
foreach (var f in new DirectoryInfo(Path.GetFullPath(args[0].Trim('"', '\''))).GetFiles("*.cs", SearchOption.AllDirectories))
{
string content = File.ReadAllText(f.FullName);
string namespaceName = string.Empty;
// Deal with usings
foreach (var u in content.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
.Where(l => l.Trim().StartsWith("using "))
.Select(l => l.Trim()))
if (!usings.Contains(u))
usings.Add(u);
// Extract namespace
//if (args.Length > 2)
//{
// var tcontent = Regex.Replace(content, @"^\s*using\s+.*\s*;$", string.Empty);
// tcontent = Regex.Replace(content, @"^\s*namespace\s+.*\s*", string.Empty).Trim();
// var ns = Regex.Match(content, @"^\s*namespace\s+(?<ns>.*)\s*");
// if (ns.Success)
// {
// if (!classes.ContainsKey(ns.Groups["ns"].Value))
// classes.Add(ns.Groups["ns"].Value, new List<string>());
// classes[ns.Groups["ns"].Value].Add(tcontent);
// }
//}
//else
{
var nstart = content.IndexOf("namespace ") + "namespace ".Length;
var bbrace = content.IndexOf("{", nstart);
var nlen = bbrace - nstart;
if (nstart < "namespace ".Length)
{
if (f.Name.ToLower() == "assemblyinfo.cs")
{
var hs = content.IndexOf("/*");
var es = content.IndexOf("*/", hs) + 2;
if (es > hs)
{
sb.AppendLine(content.Substring(hs, es - hs));
sb.AppendLine();
}
}
continue;
}
string ns = content.Substring(nstart, nlen).Trim();
// Add namespace if not exist
if (!classes.ContainsKey(ns))
classes.Add(ns, new List<string>());
var ebrace = content.LastIndexOf('}');
// Cut content as class/enum
classes[ns].Add(content.Substring(bbrace + 1, ebrace - bbrace - 1));
}
}
usings.Sort();
foreach (var u in usings)
sb.AppendLine(u);
sb.AppendLine(@"
[module: System.Diagnostics.CodeAnalysis.SuppressMessage(""StyleCop.CSharp.MaintainabilityRules"", ""SA1402:FileMayOnlyContainASingleClass"", Justification = ""This is a generated file which generates all the necessary support classes."")]
[module: System.Diagnostics.CodeAnalysis.SuppressMessage(""StyleCop.CSharp.MaintainabilityRules"", ""SA1403:FileMayOnlyContainASingleNamespace"", Justification = ""This is a generated file which generates all the necessary support classes."")]");
FillClassesAndNamespacesIddented(classes, sb);
File.WriteAllText(Path.GetFullPath(args[1].Trim('"', '\'')), sb.ToString());
}
private static void FillClassesAndNamespaces(Dictionary<string, List<string>> classes, StringBuilder sb)
{
foreach (var n in classes)
{
sb.AppendFormat("namespace {0}{1}{{", n.Key, Environment.NewLine);
n.Value.ForEach(c => sb.Append(c));
sb.AppendLine("}");
sb.AppendLine(string.Empty);
}
}
private static void FillClassesAndNamespacesIddented(Dictionary<string, List<string>> classes, StringBuilder sb)
{
var min = classes.Min(k => k.Key.Split('.').Count());
foreach (var n in classes.Where(nc => nc.Key.Split('.').Count() == min))
{
sb.AppendFormat("namespace {0}{1}{{", n.Key, Environment.NewLine);
n.Value.ForEach(c => sb.Append(c));
SubNamespaces(classes, n.Key, sb, min);
sb.AppendLine("}");
sb.AppendLine(string.Empty);
}
}
private static void SubNamespaces(Dictionary<string, List<string>> classes, string p, StringBuilder sb, int ident)
{
sb.AppendLine(string.Empty);
foreach (var n in classes.Where(nc => nc.Key.Split('.').Count() == ident + 1 && nc.Key.StartsWith(p)))
{
for (int i = 0; i < ident; i++) sb.Append(" ");
sb.AppendFormat("namespace {0}{1}", n.Key.Substring(p.Length + 1), Environment.NewLine);
for (int i = 0; i < ident; i++) sb.Append(" ");
sb.Append("{");
n.Value.ForEach(c =>
{
foreach (var l in c.Split(new string[] { Environment.NewLine }, StringSplitOptions.None))
{
for (int i = 0; i < ident; i++) sb.Append(" ");
sb.AppendLine(l);
}
});
SubNamespaces(classes, n.Key, sb, ident + 1);
for (int i = 0; i < ident; i++) sb.Append(" ");
sb.AppendLine("}");
sb.AppendLine(string.Empty);
}
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AmalgamationTool")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("AmalgamationTool")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
[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("de540809-dd27-47b1-bb01-7dce3a880cde")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -37,18 +37,16 @@
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="nunit.framework"> <Reference Include="nunit.framework, Version=2.5.10.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<Private>False</Private> <Private>False</Private>
<Package>nunit</Package> <Package>nunit</Package>
</Reference> </Reference>
<Reference Include="Mono.Data.Sqlite" /> <Reference Include="Mono.Data.Sqlite" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Helpers\Dynamic\DynamicParserTests.cs" />
<Compile Include="Modify\DynamicModificationTests.cs" /> <Compile Include="Modify\DynamicModificationTests.cs" />
<Compile Include="Modify\DynamicNoSchemaModificationTests.cs" /> <Compile Include="Modify\DynamicNoSchemaModificationTests.cs" />
<Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" /> <Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" />
<Compile Include="Modify\ParserTests.cs" />
<Compile Include="Select\DynamicNoSchemaAccessTests.cs" /> <Compile Include="Select\DynamicNoSchemaAccessTests.cs" />
<Compile Include="Select\DynamicTypeSchemaAccessTests.cs" /> <Compile Include="Select\DynamicTypeSchemaAccessTests.cs" />
<Compile Include="Helpers\AttachToDebugger.cs" /> <Compile Include="Helpers\AttachToDebugger.cs" />
@@ -61,8 +59,6 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
<Compile Include="Select\LegacyParserTests.cs" />
<Compile Include="Select\ParserTests.cs" />
<Compile Include="Select\RenamedTypedAccessTests.cs" /> <Compile Include="Select\RenamedTypedAccessTests.cs" />
<Compile Include="TestsBase.cs" /> <Compile Include="TestsBase.cs" />
<Compile Include="Select\TypedAccessTests.cs" /> <Compile Include="Select\TypedAccessTests.cs" />
@@ -88,4 +84,4 @@
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -10,82 +10,47 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DynamORM.Tests</RootNamespace> <RootNamespace>DynamORM.Tests</RootNamespace>
<AssemblyName>DynamORM.Tests</AssemblyName> <AssemblyName>DynamORM.Tests</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<SignAssembly>False</SignAssembly>
<DelaySign>False</DelaySign>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>Full</DebugType> <DebugSymbols>true</DebugSymbols>
<Optimize>False</Optimize> <DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<DebugSymbols>true</DebugSymbols>
<BaseAddress>4194304</BaseAddress>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<Prefer32Bit>False</Prefer32Bit>
<PlatformTarget>AnyCPU</PlatformTarget>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>PdbOnly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<BaseAddress>4194304</BaseAddress>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<Prefer32Bit>False</Prefer32Bit>
<PlatformTarget>AnyCPU</PlatformTarget>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<Prefer32Bit>False</Prefer32Bit>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="nunit.framework, Version=2.6.2.12296, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>C:\Program Files (x86)\NUnit 2.6.2\bin\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Data.SQLite">
<HintPath>Libraries\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Helpers\Dynamic\DynamicParserTests.cs" />
<Compile Include="Helpers\PoolingTests.cs" /> <Compile Include="Helpers\PoolingTests.cs" />
<Compile Include="Helpers\Validation\ObjectValidationTest.cs" />
<Compile Include="Modify\DynamicModificationTests.cs" /> <Compile Include="Modify\DynamicModificationTests.cs" />
<Compile Include="Modify\DynamicNoSchemaModificationTests.cs" /> <Compile Include="Modify\DynamicNoSchemaModificationTests.cs" />
<Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" /> <Compile Include="Modify\DynamicTypeSchemaModificationTests.cs" />
<Compile Include="Modify\ParserTests.cs" />
<Compile Include="Select\DynamicNoSchemaAccessTests.cs" /> <Compile Include="Select\DynamicNoSchemaAccessTests.cs" />
<Compile Include="Select\DynamicTypeSchemaAccessTests.cs" /> <Compile Include="Select\DynamicTypeSchemaAccessTests.cs" />
<Compile Include="Helpers\AttachToDebugger.cs" /> <Compile Include="Helpers\AttachToDebugger.cs" />
@@ -98,8 +63,7 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
<Compile Include="Select\LegacyParserTests.cs" /> <Compile Include="Select\RenamedTypedAccessTests.cs" />
<Compile Include="Select\ParserTests.cs" />
<Compile Include="TestsBase.cs" /> <Compile Include="TestsBase.cs" />
<Compile Include="Select\TypedAccessTests.cs" /> <Compile Include="Select\TypedAccessTests.cs" />
</ItemGroup> </ItemGroup>
@@ -107,7 +71,6 @@
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -116,17 +79,6 @@
<Name>DynamORM</Name> <Name>DynamORM</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="MSTest.TestAdapter">
<Version>2.0.0-beta4</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>2.0.0-beta4</Version>
</PackageReference>
<PackageReference Include="System.Data.SQLite">
<Version>1.0.111</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,108 +0,0 @@
using System;
using System.Collections;
namespace DynamORM.Tests
{
public class DynamicProduct : IDictionary
{
private IDictionary _dict = null;
public DynamicProduct(IDictionary dict)
{
_dict = dict;
}
// Properties from dict
public int ID
{
get { return (int)(_dict["ID"] ?? 0); }
set
{
if (!IsReadOnly)
_dict["ID"] = value;
}
}
public string Name
{
get { return (string)(_dict["Name"] ?? 0); }
set
{
if (!IsReadOnly)
_dict["Name"] = value;
}
}
public DateTime Delivery
{
get { return (DateTime)(_dict["Delivery"] ?? 0); }
set
{
if (!IsReadOnly)
_dict["Delivery"] = value;
}
}
public object Data
{
get { return (object)(_dict["Data"] ?? 0); }
set
{
if (!IsReadOnly)
_dict["Data"] = value;
}
}
// IDictionary implementation
public void Add(object key, object value)
{
_dict.Add(key, value);
}
public void Clear()
{
_dict.Clear();
}
public bool Contains(object key)
{
return _dict.Contains(key);
}
public IDictionaryEnumerator GetEnumerator()
{
return GetEnumerator();
}
public void Remove(object key)
{
_dict.Remove(key);
}
public void CopyTo(System.Array array, int index)
{
_dict.CopyTo(array, index);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _dict.GetEnumerator();
}
public bool IsFixedSize { get { return _dict.IsFixedSize; } }
public bool IsReadOnly { get { return _dict.IsReadOnly; } }
public ICollection Keys { get { return _dict.Keys; } }
public ICollection Values { get { return _dict.Values; } }
public object this[object key] { get { return _dict[key]; } set { _dict[key] = value; } }
public int Count { get { return _dict.Count; } }
public bool IsSynchronized { get { return _dict.IsSynchronized; } }
public object SyncRoot { get { return _dict.SyncRoot; } }
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -28,16 +28,25 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Helpers namespace DynamORM.Tests.Helpers
{ {
/// <summary>Class responsible for users operations testing.</summary> /// <summary>Class responsible for users operations testing.</summary>
[TestClass] [TestFixture]
public class AttachToDebugger 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 compatibility.</summary> /// <summary>Test anonymous type compatibility.</summary>
[TestMethod] [Test]
public void TestAnonType() public void TestAnonType()
{ {
var a = new { x = 1, y = 2 }; var a = new { x = 1, y = 2 };
@@ -47,7 +56,7 @@ namespace DynamORM.Tests.Helpers
} }
/// <summary>Test anonymous type value.</summary> /// <summary>Test anonymous type value.</summary>
[TestMethod] [Test]
public void TestAnonTypeValue() public void TestAnonTypeValue()
{ {
var a = new { x = 1, y = "bla bla" }; var a = new { x = 1, y = "bla bla" };

View File

@@ -1,121 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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 DynamORM.Helpers.Dynamics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DynamORM.Tests.Helpers.Dynamic
{
/// <summary><see cref="DynamicParser"/> tests.</summary>
[TestClass]
public class DynamicParserTests
{
/// <summary>
/// Tests the get member.
/// </summary>
[TestMethod]
public void TestGetMember()
{
Func<dynamic, object> f = x => x.SomePropery;
var val = DynamicParser.Parse(f).Result as DynamicParser.Node.GetMember;
Assert.IsNotNull(val);
Assert.AreEqual("SomePropery", val.Name);
}
/// <summary>
/// Tests the set member.
/// </summary>
[TestMethod]
public void TestSetMember()
{
Func<dynamic, object> f = x => x.SomePropery = "value";
var val = DynamicParser.Parse(f).Result as DynamicParser.Node.SetMember;
Assert.IsNotNull(val);
Assert.AreEqual("SomePropery", val.Name);
Assert.AreEqual("value", val.Value);
}
/// <summary>
/// Tests the index of the get.
/// </summary>
[TestMethod]
public void TestGetIndex()
{
Func<dynamic, object> f = x => x.SomePropery[0];
var val = DynamicParser.Parse(f).Result as DynamicParser.Node.GetIndex;
Assert.IsNotNull(val);
}
/// <summary>
/// Tests the index of the set.
/// </summary>
[TestMethod]
public void TestSetIndex()
{
Func<dynamic, object> f = x => x.SomePropery[0] = "value";
var val = DynamicParser.Parse(f).Result as DynamicParser.Node.SetIndex;
Assert.IsNotNull(val);
Assert.AreEqual("value", val.Value);
}
/// <summary>
/// Tests something.
/// </summary>
[TestMethod]
public void TestSomething()
{
Func<dynamic, object> f = x => x.SomePropery == "value" || x.OtherProperty == -1;
var p = DynamicParser.Parse(f);
var val = p.Result as DynamicParser.Node.Binary;
Assert.IsNotNull(val);
var left = val.Host as DynamicParser.Node.Binary;
var right = val.Right as DynamicParser.Node.Binary;
Assert.IsNotNull(left);
Assert.IsNotNull(right);
Assert.IsInstanceOfType(left.Host, typeof(DynamicParser.Node.GetMember));
Assert.IsInstanceOfType(right.Host, typeof(DynamicParser.Node.GetMember));
Assert.AreEqual("value", left.Right);
Assert.AreEqual(-1, right.Right);
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,23 +26,24 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using Microsoft.VisualStudio.TestTools.UnitTesting; using System;
using NUnit.Framework;
namespace DynamORM.Tests.Helpers namespace DynamORM.Tests.Helpers
{ {
/// <summary>Pooling tests.</summary> /// <summary>Pooling tests.</summary>
[TestClass] [TestFixture]
public class PoolingTests : TestsBase public class PoolingTests : TestsBase
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public virtual void SetUp() public virtual void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();
} }
/// <summary>Tear down test objects.</summary> /// <summary>Tear down test objects.</summary>
[TestCleanup] [TestFixtureTearDown]
public virtual void TearDown() public virtual void TearDown()
{ {
DestroyDynamicDatabase(); DestroyDynamicDatabase();
@@ -50,7 +51,7 @@ namespace DynamORM.Tests.Helpers
} }
/// <summary>Test single mode command disposing.</summary> /// <summary>Test single mode command disposing.</summary>
[TestMethod] [Test]
public void TestSingleModeCommand() public void TestSingleModeCommand()
{ {
CreateDynamicDatabase(); CreateDynamicDatabase();
@@ -62,11 +63,11 @@ namespace DynamORM.Tests.Helpers
Database.Dispose(); Database.Dispose();
Database = null; Database = null;
Assert.ThrowsException<DynamicQueryException>(() => cmd.ExecuteScalar()); Assert.Throws<ObjectDisposedException>(() => cmd.ExecuteScalar());
} }
/// <summary>Test single mode transaction disposing.</summary> /// <summary>Test single mode transaction disposing.</summary>
[TestMethod] [Test]
public void TestSingleModeTransaction() public void TestSingleModeTransaction()
{ {
try try

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,80 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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;
using DynamORM.Validation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DynamORM.Tests.Helpers.Validation
{
[TestClass]
public class ObjectValidationTest
{
public class TestObject
{
[Required(1f, 10f)]
public int TestInt { get; set; }
[Required(7, false, false)]
public string CanBeNull { get; set; }
[Required(2, true)]
[Required(7, 18, ElementRequirement = true)]
public decimal[] ArrayTest { get; set; }
}
[TestMethod]
public void ValidateCorrectObject()
{
var result = DynamicMapperCache.GetMapper<TestObject>().ValidateObject(
new TestObject
{
TestInt = 2,
ArrayTest = new decimal[] { 7, 18 },
});
Assert.IsNotNull(result);
Assert.AreEqual(0, result.Count);
}
[TestMethod]
public void ValidateIncorrectObject()
{
var result = DynamicMapperCache.GetMapper<TestObject>().ValidateObject(
new TestObject
{
TestInt = 0,
CanBeNull = string.Empty,
ArrayTest = new decimal[] { 0, 0 },
});
Assert.IsNotNull(result);
Assert.AreEqual(4, result.Count);
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -28,16 +28,16 @@
using System; using System;
using DynamORM.Tests.Helpers; using DynamORM.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Modify namespace DynamORM.Tests.Modify
{ {
/// <summary>Test standard dynamic access ORM.</summary> /// <summary>Test standard dynamic access ORM.</summary>
[TestClass] [TestFixture]
public class DynamicModificationTests : TestsBase public class DynamicModificationTests : TestsBase
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public virtual void SetUp() public virtual void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();
@@ -45,7 +45,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Tear down test objects.</summary> /// <summary>Tear down test objects.</summary>
[TestCleanup] [TestFixtureTearDown]
public virtual void TearDown() public virtual void TearDown()
{ {
DestroyDynamicDatabase(); DestroyDynamicDatabase();
@@ -62,14 +62,14 @@ namespace DynamORM.Tests.Modify
#region Insert #region Insert
/// <summary>Test row insertion by dynamic arguments.</summary> /// <summary>Test row insertion by dynamic arguments.</summary>
[TestMethod] [Test]
public void TestInsertByArguments() public void TestInsertByArguments()
{ {
Assert.AreEqual(1, GetTestTable().Insert(code: "201", first: null, last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla")); Assert.AreEqual(1, GetTestTable().Insert(code: "201", first: null, last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla"));
// Verify // Verify
var o = GetTestTable().Single(code: "201"); var o = GetTestTable().Single(code: "201");
Assert.AreNotEqual(200, o.id); Assert.Less(200, o.id);
Assert.AreEqual("201", o.code.ToString()); Assert.AreEqual("201", o.code.ToString());
Assert.AreEqual(null, o.first); Assert.AreEqual(null, o.first);
Assert.AreEqual("Gagarin", o.last); Assert.AreEqual("Gagarin", o.last);
@@ -79,14 +79,14 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row insertion by dynamic object.</summary> /// <summary>Test row insertion by dynamic object.</summary>
[TestMethod] [Test]
public void TestInsertByDynamicObjects() public void TestInsertByDynamicObjects()
{ {
Assert.AreEqual(1, GetTestTable().Insert(values: new { code = "202", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" })); Assert.AreEqual(1, GetTestTable().Insert(values: new { code = "202", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
// Verify // Verify
var o = GetTestTable().Single(code: "202"); var o = GetTestTable().Single(code: "202");
Assert.AreNotEqual(200, o.id); Assert.Less(200, o.id);
Assert.AreEqual("202", o.code.ToString()); Assert.AreEqual("202", o.code.ToString());
Assert.AreEqual(null, o.first); Assert.AreEqual(null, o.first);
Assert.AreEqual("Gagarin", o.last); Assert.AreEqual("Gagarin", o.last);
@@ -96,7 +96,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row insertion by mapped object.</summary> /// <summary>Test row insertion by mapped object.</summary>
[TestMethod] [Test]
public void TestInsertByMappedObject() public void TestInsertByMappedObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -113,7 +113,7 @@ namespace DynamORM.Tests.Modify
// Verify // Verify
var o = u.Single(code: "203"); var o = u.Single(code: "203");
Assert.AreNotEqual(200, o.id); Assert.Less(200, o.id);
Assert.AreEqual("203", o.code.ToString()); Assert.AreEqual("203", o.code.ToString());
Assert.AreEqual(null, o.first); Assert.AreEqual(null, o.first);
Assert.AreEqual("Gagarin", o.last); Assert.AreEqual("Gagarin", o.last);
@@ -123,7 +123,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row insertion by basic object.</summary> /// <summary>Test row insertion by basic object.</summary>
[TestMethod] [Test]
public void TestInsertByBasicObject() public void TestInsertByBasicObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -140,7 +140,7 @@ namespace DynamORM.Tests.Modify
// Verify // Verify
var o = u.Single(code: "204"); var o = u.Single(code: "204");
Assert.AreNotEqual(200, o.id); Assert.Less(200, o.id);
Assert.AreEqual("204", o.code.ToString()); Assert.AreEqual("204", o.code.ToString());
Assert.AreEqual(null, o.first); Assert.AreEqual(null, o.first);
Assert.AreEqual("Gagarin", o.last); Assert.AreEqual("Gagarin", o.last);
@@ -154,7 +154,7 @@ namespace DynamORM.Tests.Modify
#region Update #region Update
/// <summary>Test row updating by dynamic arguments.</summary> /// <summary>Test row updating by dynamic arguments.</summary>
[TestMethod] [Test]
public void TestUpdateByArguments() public void TestUpdateByArguments()
{ {
Assert.AreEqual(1, GetTestTable().Update(id: 1, code: "201", first: null, last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla")); Assert.AreEqual(1, GetTestTable().Update(id: 1, code: "201", first: null, last: "Gagarin", email: "juri.gagarin@megacorp.com", quote: "bla, bla, bla"));
@@ -171,7 +171,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by dynamic objects.</summary> /// <summary>Test row updating by dynamic objects.</summary>
[TestMethod] [Test]
public void TestUpdateByDynamicObject() public void TestUpdateByDynamicObject()
{ {
Assert.AreEqual(1, GetTestTable().Update(update: new { id = 2, code = "202", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" })); Assert.AreEqual(1, GetTestTable().Update(update: new { id = 2, code = "202", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
@@ -188,7 +188,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by mapped object.</summary> /// <summary>Test row updating by mapped object.</summary>
[TestMethod] [Test]
public void TestUpdateByMappedObject() public void TestUpdateByMappedObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -215,7 +215,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by basic object.</summary> /// <summary>Test row updating by basic object.</summary>
[TestMethod] [Test]
public void TestUpdateByBasicObject() public void TestUpdateByBasicObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -242,7 +242,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by dynamic objects.</summary> /// <summary>Test row updating by dynamic objects.</summary>
[TestMethod] [Test]
public void TestUpdateByDynamicObjects() public void TestUpdateByDynamicObjects()
{ {
Assert.AreEqual(1, GetTestTable().Update(values: new { code = "205", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }, where: new { id = 5 })); Assert.AreEqual(1, GetTestTable().Update(values: new { code = "205", first = DBNull.Value, last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }, where: new { id = 5 }));
@@ -259,7 +259,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by mapped objects.</summary> /// <summary>Test row updating by mapped objects.</summary>
[TestMethod] [Test]
public void TestUpdateByMappedObjects() public void TestUpdateByMappedObjects()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -286,7 +286,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row updating by basic objects.</summary> /// <summary>Test row updating by basic objects.</summary>
[TestMethod] [Test]
public void TestUpdateByBasicObjects() public void TestUpdateByBasicObjects()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -317,7 +317,7 @@ namespace DynamORM.Tests.Modify
#region Delete #region Delete
/// <summary>Test row deleting by dynamic arguments.</summary> /// <summary>Test row deleting by dynamic arguments.</summary>
[TestMethod] [Test]
public void TestDeleteByArguments() public void TestDeleteByArguments()
{ {
Assert.AreEqual(1, GetTestTable().Delete(code: "10")); Assert.AreEqual(1, GetTestTable().Delete(code: "10"));
@@ -327,7 +327,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary> /// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary>
[TestMethod] [Test]
public void TestDeleteyDynamicObject() 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" })); Assert.AreEqual(1, GetTestTable().Delete(delete: new { id = 11, code = 11, first = "Juri", last = "Gagarin", email = "juri.gagarin@megacorp.com", quote = "bla, bla, bla" }));
@@ -337,7 +337,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row deleting by mapped object.</summary> /// <summary>Test row deleting by mapped object.</summary>
[TestMethod] [Test]
public void TestDeleteByMappedObject() public void TestDeleteByMappedObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -357,7 +357,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row deleting by basic object.</summary> /// <summary>Test row deleting by basic object.</summary>
[TestMethod] [Test]
public void TestDeleteByBasicObject() public void TestDeleteByBasicObject()
{ {
var u = GetTestTable(); var u = GetTestTable();
@@ -377,7 +377,7 @@ namespace DynamORM.Tests.Modify
} }
/// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary> /// <summary>Test row deleting by dynamic objects (all except ID should be ignored).</summary>
[TestMethod] [Test]
public void TestDeleteyDynamicObjectWhere() public void TestDeleteyDynamicObjectWhere()
{ {
Assert.AreEqual(1, GetTestTable().Delete(where: new { id = 14, code = "14" })); Assert.AreEqual(1, GetTestTable().Delete(where: new { id = 14, code = "14" }));

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,17 +26,17 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Modify namespace DynamORM.Tests.Modify
{ {
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary> /// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
[TestClass] [TestFixture]
public class DynamicNoSchemaModificationTests : DynamicModificationTests public class DynamicNoSchemaModificationTests : DynamicModificationTests
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public virtual void SetUp() public override void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();
CreateDynamicDatabase( CreateDynamicDatabase(

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,14 +26,13 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System.Collections.Generic;
using DynamORM.Tests.Helpers; using DynamORM.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Modify namespace DynamORM.Tests.Modify
{ {
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary> /// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
[TestClass] [TestFixture]
public class DynamicTypeSchemaModificationTests : DynamicModificationTests public class DynamicTypeSchemaModificationTests : DynamicModificationTests
{ {
/// <summary>Create table using specified method.</summary> /// <summary>Create table using specified method.</summary>
@@ -42,28 +41,5 @@ namespace DynamORM.Tests.Modify
{ {
return Database.Table<users>(); return Database.Table<users>();
} }
/// <summary>
/// Tests the bulk insert.
/// </summary>
[TestMethod]
public void TestBulkInsert()
{
Assert.AreEqual(2, Database.Insert<users>(new List<users>
{
new users
{
id = 1001,
login = "a",
},
new users
{
id = 1002,
login = "b",
}
}));
Assert.AreEqual(2, Database.Delete<users>().Where(u => u.users.id.In(1001, 1002)).Execute());
}
} }
} }

View File

@@ -1,206 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Linq;
using DynamORM.Builders;
using DynamORM.Builders.Implementation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DynamORM.Tests.Helpers;
using System.Collections.Generic;
namespace DynamORM.Tests.Modify
{
/// <summary>New parser tests.</summary>
[TestClass]
public class ParserTests : TestsBase
{
/// <summary>Setup test parameters.</summary>
[TestInitialize]
public virtual void SetUp()
{
CreateTestDatabase();
CreateDynamicDatabase(
DynamicDatabaseOptions.SingleConnection |
DynamicDatabaseOptions.SingleTransaction |
DynamicDatabaseOptions.SupportLimitOffset);
}
/// <summary>Tear down test objects.</summary>
[TestCleanup]
public virtual void TearDown()
{
DestroyDynamicDatabase();
DestroyTestDatabase();
}
#region Insert
/// <summary>
/// Tests the basic insert.
/// </summary>
[TestMethod]
public void TestInsertBasic()
{
IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Values(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = 1);
Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0})",
string.Join(", ", cmd.Parameters.Keys.Select(p => string.Format("[${0}]", p)))), cmd.CommandText());
}
/// <summary>
/// Tests the insert with sub query.
/// </summary>
[TestMethod]
public void TestInsertSubQuery()
{
IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Values(x => x.Code = "001", x => x.Name = "Admin", x => x.IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == "001")));
Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0}, (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = [${1}])))",
string.Join(", ", cmd.Parameters.Keys.Take(2).Select(p => string.Format("[${0}]", p))), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the basic insert using object.
/// </summary>
[TestMethod]
public void TestInsertBasicObject()
{
IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Values(x => new { Code = "001", Name = "Admin", IsAdmin = 1 });
Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0})",
string.Join(", ", cmd.Parameters.Keys.Select(p => string.Format("[${0}]", p)))), cmd.CommandText());
}
/// <summary>
/// Tests the insert using object with sub query.
/// </summary>
[TestMethod]
public void TestInsertSubQueryObject()
{
IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Values(x => new
{
Code = "001",
Name = "Admin",
IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == "001"))
});
Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0}, (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = [${1}])))",
string.Join(", ", cmd.Parameters.Keys.Take(2).Select(p => string.Format("[${0}]", p))), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
#endregion Insert
#region Update
/// <summary>
/// Tests the basic update.
/// </summary>
[TestMethod]
public void TestUpdateBasic()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Set(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = 1)
.Where(x => x.Users.Id_User == 1);
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = [${2}] WHERE (""Users"".""Id_User"" = [${3}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2], cmd.Parameters.Keys.ToArray()[3]), cmd.CommandText());
}
/// <summary>
/// Tests the insert with sub query.
/// </summary>
[TestMethod]
public void TestUpdateSubQuery()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Set(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == a.Users.Id_User)))
.Where(x => x.Users.Id_User == 1);
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = ""Users"".""Id_User"")) WHERE (""Users"".""Id_User"" = [${2}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests the basic insert using object.
/// </summary>
[TestMethod]
public void TestUpdateBasicObject()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Set(x => new { Code = "001", Name = "Admin", IsAdmin = 1 })
.Where(x => new { Id_User = 1 });
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = [${2}] WHERE (""Id_User"" = [${3}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2], cmd.Parameters.Keys.ToArray()[3]), cmd.CommandText());
}
/// <summary>
/// Tests the basic insert using object.
/// </summary>
[TestMethod]
public void TestUpdateSubQueryObject()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Set(x => new
{
Code = "001",
Name = "Admin",
IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == a.Users.Id_User))
}).Where(x => new { Id_User = 1 });
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = ""Users"".""Id_User"")) WHERE (""Id_User"" = [${2}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
#endregion Update
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0.1")] [assembly: AssemblyVersion("1.0.0.1")]
[assembly: AssemblyFileVersion("1.1.0.1")] [assembly: AssemblyFileVersion("1.0.0.1")]

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.42000 // Runtime Version:4.0.30319.269
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,7 +19,7 @@ namespace DynamORM.Tests.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { internal class Resources {

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -29,17 +29,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DynamORM.Builders; using NUnit.Framework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DynamORM.Tests.Select namespace DynamORM.Tests.Select
{ {
/// <summary>Test standard dynamic access ORM.</summary> /// <summary>Test standard dynamic access ORM.</summary>
[TestClass] [TestFixture]
public class DynamicAccessTests : TestsBase public class DynamicAccessTests : TestsBase
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public virtual void SetUp() public virtual void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();
@@ -47,7 +46,7 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Tear down test objects.</summary> /// <summary>Tear down test objects.</summary>
[TestCleanup] [TestFixtureTearDown]
public virtual void TearDown() public virtual void TearDown()
{ {
DestroyDynamicDatabase(); DestroyDynamicDatabase();
@@ -61,38 +60,24 @@ namespace DynamORM.Tests.Select
return Database.Table("users"); return Database.Table("users");
} }
/// <summary>Create table using specified method.</summary>
/// <returns>Dynamic table.</returns>
public virtual IDynamicSelectQueryBuilder GetTestBuilder()
{
return Database.Table("users").Query() as IDynamicSelectQueryBuilder;
}
#region Select #region Select
/// <summary>Test unknown op.</summary> /// <summary>Test unknown op.</summary>
[TestMethod] [Test]
public void TestUnknownOperation() public void TestUnknownOperation()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(with: "cheese")); Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(with: "cheese"));
} }
/// <summary>Test dynamic <c>Count</c> method.</summary> /// <summary>Test dynamic <c>Count</c> method.</summary>
[TestMethod] [Test]
public void TestCount() public void TestCount()
{ {
Assert.AreEqual(200, GetTestTable().Count(columns: "id")); Assert.AreEqual(200, GetTestTable().Count(columns: "id"));
} }
/// <summary>Test dynamic <c>Count</c> method.</summary> /// <summary>Test count with in steatement.</summary>
[TestMethod] [Test]
public void TestCount2()
{
Assert.AreEqual(200L, GetTestBuilder().Select(x => x.Count(x.id)).Scalar());
}
/// <summary>Test count with in statement.</summary>
[TestMethod]
public void TestSelectInEnumerableCount() public void TestSelectInEnumerableCount()
{ {
Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn
@@ -102,18 +87,8 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test count with in statement.</summary> /// <summary>Test count with in steatement.</summary>
[TestMethod] [Test]
public void TestSelectInEnumerableCount2()
{
Assert.AreEqual(4L, GetTestBuilder()
.Where(x => x.last.In(new object[] { "Hendricks", "Goodwin", "Freeman" }.Take(3)))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test count with in statement.</summary>
[TestMethod]
public void TestSelectInArrayCount() public void TestSelectInArrayCount()
{ {
Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count(last: new DynamicColumn
@@ -123,157 +98,71 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test count with in statement.</summary>
[TestMethod]
public void TestSelectInArrayCount2()
{
Assert.AreEqual(4L, GetTestBuilder()
.Where(x => x.last.In(new object[] { "Hendricks", "Goodwin", "Freeman" }))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic <c>First</c> method.</summary> /// <summary>Test dynamic <c>First</c> method.</summary>
[TestMethod] [Test]
public void TestFirst() public void TestFirst()
{ {
Assert.AreEqual(1, GetTestTable().First(columns: "id").id); Assert.AreEqual(1, GetTestTable().First(columns: "id").id);
} }
/// <summary>Test dynamic <c>First</c> method.</summary>
[TestMethod]
public void TestFirst2()
{
Assert.AreEqual(1, GetTestBuilder()
.Select(x => x.id)
.Execute()
.First().id);
}
/// <summary>Test dynamic <c>Last</c> method.</summary> /// <summary>Test dynamic <c>Last</c> method.</summary>
[TestMethod] [Test]
public void TestLast() public void TestLast()
{ {
Assert.AreEqual(200, GetTestTable().Last(columns: "id").id); Assert.AreEqual(200, GetTestTable().Last(columns: "id").id);
} }
/// <summary>Test dynamic <c>Last</c> method.</summary>
[TestMethod]
public void TestLast2()
{
Assert.AreEqual(200, GetTestBuilder()
.Select(x => x.id)
.Execute()
.Last().id);
}
/// <summary>Test dynamic <c>Count</c> method.</summary> /// <summary>Test dynamic <c>Count</c> method.</summary>
[TestMethod] [Test]
public void TestCountSpecificRecord() public void TestCountSpecificRecord()
{ {
Assert.AreEqual(1, GetTestTable().Count(first: "Ori")); Assert.AreEqual(1, GetTestTable().Count(first: "Ori"));
} }
/// <summary>Test dynamic <c>Count</c> method.</summary>
[TestMethod]
public void TestCountSpecificRecord2()
{
Assert.AreEqual(1L, GetTestBuilder()
.Where(x => x.first == "Ori")
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic <c>Min</c> method.</summary> /// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod] [Test]
public void TestMin() public void TestMin()
{ {
Assert.AreEqual(1, GetTestTable().Min(columns: "id")); Assert.AreEqual(1, GetTestTable().Min(columns: "id"));
} }
/// <summary>Test dynamic <c>Min</c> method.</summary> /// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod] [Test]
public void TestMin2()
{
Assert.AreEqual(1L, GetTestBuilder()
.Select(x => x.Min(x.id))
.Scalar());
}
/// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod]
public void TestMax() public void TestMax()
{ {
Assert.AreEqual(200, GetTestTable().Max(columns: "id")); Assert.AreEqual(200, GetTestTable().Max(columns: "id"));
} }
/// <summary>Test dynamic <c>Min</c> method.</summary> /// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod] [Test]
public void TestMax2()
{
Assert.AreEqual(200L, GetTestBuilder()
.Select(x => x.Max(x.id))
.Scalar());
}
/// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod]
public void TesttAvg() public void TesttAvg()
{ {
Assert.AreEqual(100.5, GetTestTable().Avg(columns: "id")); Assert.AreEqual(100.5, GetTestTable().Avg(columns: "id"));
} }
/// <summary>Test dynamic <c>Min</c> method.</summary>
[TestMethod]
public void TesttAvg2()
{
Assert.AreEqual(100.5, GetTestBuilder()
.Select(x => x.Avg(x.id))
.Scalar());
}
/// <summary>Test dynamic <c>Sum</c> method.</summary> /// <summary>Test dynamic <c>Sum</c> method.</summary>
[TestMethod] [Test]
public void TestSum() public void TestSum()
{ {
Assert.AreEqual(20100, GetTestTable().Sum(columns: "id")); Assert.AreEqual(20100, GetTestTable().Sum(columns: "id"));
} }
/// <summary>Test dynamic <c>Sum</c> method.</summary>
[TestMethod]
public void TestSum2()
{
Assert.AreEqual(20100L, GetTestBuilder()
.Select(x => x.Sum(x.id))
.Scalar());
}
/// <summary>Test dynamic <c>Scalar</c> method for invalid operation exception.</summary> /// <summary>Test dynamic <c>Scalar</c> method for invalid operation exception.</summary>
[TestMethod] [Test]
public void TestScalarException() public void TestScalarException()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().Scalar(id: 19)); Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar(id: 19));
} }
/// <summary>Test dynamic <c>Scalar</c> method.</summary> /// <summary>Test dynamic <c>Scalar</c> method.</summary>
[TestMethod] [Test]
public void TestScalar() public void TestScalar()
{ {
Assert.AreEqual("Ori", GetTestTable().Scalar(columns: "first", id: 19)); Assert.AreEqual("Ori", GetTestTable().Scalar(columns: "first", id: 19));
} }
/// <summary>Test dynamic <c>Scalar</c> method.</summary>
[TestMethod]
public void TestScalar2()
{
Assert.AreEqual("Ori", GetTestBuilder()
.Where(x => x.id == 19)
.Select(x => x.first)
.Scalar());
}
/// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate.</summary> /// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate.</summary>
[TestMethod] [Test]
public void TestScalarGroupConcat() public void TestScalarGroupConcat()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -282,21 +171,8 @@ namespace DynamORM.Tests.Select
GetTestTable().Scalar(columns: "first:first:group_concat", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 })); 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.</summary>
[TestMethod]
public void TestScalarGroupConcat2()
{
// 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",
GetTestBuilder()
.Where(x => x.id < 20)
.Select(x => x.group_concat(x.first).As(x.first))
.Scalar());
}
/// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary> /// <summary>Test dynamic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
[TestMethod] [Test]
public void TestScalarGroupConcatNoAggregateField() public void TestScalarGroupConcatNoAggregateField()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -305,21 +181,8 @@ namespace DynamORM.Tests.Select
GetTestTable().Scalar(columns: "group_concat(first):first", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 })); GetTestTable().Scalar(columns: "group_concat(first):first", 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>
[TestMethod]
public void TestScalarGroupConcatNoAggregateField2()
{
// 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",
GetTestBuilder()
.Where(x => x.id < 20)
.SelectColumn("group_concat(first):first")
.Scalar());
}
/// <summary>Test something fancy... like: <code>select "first", count("first") occurs from "users" group by "first" order by 2 desc;</code>.</summary> /// <summary>Test something fancy... like: <code>select "first", count("first") occurs from "users" group by "first" order by 2 desc;</code>.</summary>
[TestMethod] [Test]
public void TestFancyAggregateQuery() public void TestFancyAggregateQuery()
{ {
var v = (GetTestTable().Query(columns: "first,first:occurs:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList(); var v = (GetTestTable().Query(columns: "first,first:occurs:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
@@ -333,58 +196,20 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(1, v.Last().occurs); Assert.AreEqual(1, v.Last().occurs);
} }
/// <summary>Test something fancy... like: <code>select "first", count("first") occurs from "users" group by "first" order by 2 desc;</code>.</summary>
[TestMethod]
public void TestFancyAggregateQuery2()
{
var v = GetTestBuilder()
.Select(x => x.first, x => x.Count(x.first).As(x.occurs))
.GroupBy(x => x.first)
.OrderBy(x => x.Desc(2))
.Execute()
.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> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
[TestMethod] [Test]
public void TestAggregateInAggregate() public void TestAggregateInAggregate()
{ {
Assert.AreEqual(12.77, GetTestTable().Scalar(columns: @"length(""login""):len:avg")); Assert.AreEqual(12.77, GetTestTable().Scalar(columns: @"length(""login""):len:avg"));
} }
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
[TestMethod]
public void TestAggregateInAggregate2()
{
Assert.AreEqual(12.77, GetTestBuilder()
.Select(x => x.Avg(x.Length(x.login)).As(x.len))
.Scalar());
}
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
[TestMethod] [Test]
public void TestAggregateInAggregateMark2() public void TestAggregateInAggregateMark2()
{ {
Assert.AreEqual(27.7, GetTestTable().Avg(columns: @"length(""email""):len")); Assert.AreEqual(27.7, GetTestTable().Avg(columns: @"length(""email""):len"));
} }
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
[TestMethod]
public void TestAggregateInAggregateMark3()
{
Assert.AreEqual(27.7, GetTestBuilder()
.Select(x => "AVG(LENGTH(email)) AS LEN")
.Scalar());
}
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary> /// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
public void TestFunctionInWhere() public void TestFunctionInWhere()
{ {
@@ -399,17 +224,8 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
public void TestFunctionInWhere2()
{
Assert.AreEqual(97, GetTestBuilder()
.Where(x => x.Length(x.email) > 27)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic <c>Single</c> multi.</summary> /// <summary>Test dynamic <c>Single</c> multi.</summary>
[TestMethod] [Test]
public void TestSingleObject() public void TestSingleObject()
{ {
var exp = new { id = 19, first = "Ori", last = "Ellis" }; var exp = new { id = 19, first = "Ori", last = "Ellis" };
@@ -420,236 +236,87 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(exp.last, o.last); Assert.AreEqual(exp.last, o.last);
} }
/// <summary>Test dynamic <c>Single</c> multi.</summary>
[TestMethod]
public void TestSingleObject2()
{
var exp = new { id = 19, first = "Ori", last = "Ellis" };
var o = GetTestBuilder()
.Where(x => x.id == 19)
.Select(x => new { id = x.id, first = x.first, last = x.last })
.Execute()
.First();
Assert.AreEqual(exp.id, o.id);
Assert.AreEqual(exp.first, o.first);
Assert.AreEqual(exp.last, o.last);
}
/// <summary>Test dynamic duplicate column name occurrence.</summary>
[TestMethod]
public void TestDuplicateColumnNameException()
{
Assert.ThrowsException<ArgumentException>(() => GetTestBuilder()
.Where(x => x.id == 19)
.Select(x => new
{
id = x.id,
first = x.first,
last = x.last,
})
.Select(x => x.last.As(x.first)) // Make last be first
.Execute()
.First());
}
#endregion Select #endregion Select
#region Where #region Where
/// <summary>Test dynamic where expression equal.</summary> /// <summary>Test dynamic where expression equal.</summary>
[TestMethod] [Test]
public void TestWhereEq() public void TestWhereEq()
{ {
Assert.AreEqual("hoyt.tran", GetTestTable().Single(where: new DynamicColumn("id").Eq(100)).login); Assert.AreEqual("hoyt.tran", GetTestTable().Single(where: new DynamicColumn("id").Eq(100)).login);
} }
/// <summary>Test dynamic where expression equal.</summary>
[TestMethod]
public void TestWhereEq2()
{
Assert.AreEqual("hoyt.tran", GetTestBuilder()
.Where(x => x.id == 100).Execute().First().login);
}
/// <summary>Test dynamic where expression not equal.</summary> /// <summary>Test dynamic where expression not equal.</summary>
[TestMethod] [Test]
public void TestWhereNot() public void TestWhereNot()
{ {
Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("id").Not(100))); Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("id").Not(100)));
} }
/// <summary>Test dynamic where expression not equal.</summary>
[TestMethod]
public void TestWhereNot2()
{
Assert.AreEqual(199L, GetTestBuilder()
.Where(x => x.id != 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression like.</summary> /// <summary>Test dynamic where expression like.</summary>
[TestMethod] [Test]
public void TestWhereLike() public void TestWhereLike()
{ {
Assert.AreEqual(100, GetTestTable().Single(where: new DynamicColumn("login").Like("Hoyt.%")).id); Assert.AreEqual(100, GetTestTable().Single(where: new DynamicColumn("login").Like("Hoyt.%")).id);
} }
/// <summary>Test dynamic where expression like.</summary>
[TestMethod]
public void TestWhereLike2()
{
Assert.AreEqual(100, GetTestBuilder()
.Where(x => x.login.Like("Hoyt.%")).Execute().First().id);
}
/// <summary>Test dynamic where expression not like.</summary> /// <summary>Test dynamic where expression not like.</summary>
[TestMethod] [Test]
public void TestWhereNotLike() public void TestWhereNotLike()
{ {
Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("login").NotLike("Hoyt.%"))); Assert.AreEqual(199, GetTestTable().Count(where: new DynamicColumn("login").NotLike("Hoyt.%")));
} }
/// <summary>Test dynamic where expression not like.</summary>
[TestMethod]
public void TestWhereNotLike2()
{
Assert.AreEqual(199L, GetTestBuilder()
.Where(x => x.login.NotLike("Hoyt.%"))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression not like.</summary>
[TestMethod]
public void TestWhereNotLike3()
{
Assert.AreEqual(199L, GetTestBuilder()
.Where(x => !x.login.Like("Hoyt.%"))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression greater.</summary> /// <summary>Test dynamic where expression greater.</summary>
[TestMethod] [Test]
public void TestWhereGt() public void TestWhereGt()
{ {
Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").Greater(100))); Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").Greater(100)));
} }
/// <summary>Test dynamic where expression greater.</summary>
[TestMethod]
public void TestWhereGt2()
{
Assert.AreEqual(100L, GetTestBuilder()
.Where(x => x.id > 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression greater or equal.</summary> /// <summary>Test dynamic where expression greater or equal.</summary>
[TestMethod] [Test]
public void TestWhereGte() public void TestWhereGte()
{ {
Assert.AreEqual(101, GetTestTable().Count(where: new DynamicColumn("id").GreaterOrEqual(100))); Assert.AreEqual(101, GetTestTable().Count(where: new DynamicColumn("id").GreaterOrEqual(100)));
} }
/// <summary>Test dynamic where expression greater or equal.</summary>
[TestMethod]
public void TestWhereGte2()
{
Assert.AreEqual(101L, GetTestBuilder()
.Where(x => x.id >= 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression less.</summary> /// <summary>Test dynamic where expression less.</summary>
[TestMethod] [Test]
public void TestWhereLt() public void TestWhereLt()
{ {
Assert.AreEqual(99, GetTestTable().Count(where: new DynamicColumn("id").Less(100))); Assert.AreEqual(99, GetTestTable().Count(where: new DynamicColumn("id").Less(100)));
} }
/// <summary>Test dynamic where expression less.</summary>
[TestMethod]
public void TestWhereLt2()
{
Assert.AreEqual(99L, GetTestBuilder()
.Where(x => x.id < 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression less or equal.</summary> /// <summary>Test dynamic where expression less or equal.</summary>
[TestMethod] [Test]
public void TestWhereLte() public void TestWhereLte()
{ {
Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").LessOrEqual(100))); Assert.AreEqual(100, GetTestTable().Count(where: new DynamicColumn("id").LessOrEqual(100)));
} }
/// <summary>Test dynamic where expression less or equal.</summary>
[TestMethod]
public void TestWhereLte2()
{
Assert.AreEqual(100L, GetTestBuilder()
.Where(x => x.id <= 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression between.</summary> /// <summary>Test dynamic where expression between.</summary>
[TestMethod] [Test]
public void TestWhereBetween() public void TestWhereBetween()
{ {
Assert.AreEqual(26, GetTestTable().Count(where: new DynamicColumn("id").Between(75, 100))); Assert.AreEqual(26, GetTestTable().Count(where: new DynamicColumn("id").Between(75, 100)));
} }
/// <summary>Test dynamic where expression between.</summary> /// <summary>Test dynamic where expression in params.</summary>
[TestMethod] [Test]
public void TestWhereBetween2()
{
Assert.AreEqual(26L, GetTestBuilder()
.Where(x => x.id.Between(75, 100))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression in parameters.</summary>
[TestMethod]
public void TestWhereIn1() public void TestWhereIn1()
{ {
Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(75, 99, 100))); Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(75, 99, 100)));
} }
/// <summary>Test dynamic where expression in array.</summary> /// <summary>Test dynamic where expression in array.</summary>
[TestMethod] [Test]
public void TestWhereIn2() public void TestWhereIn2()
{ {
Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(new[] { 75, 99, 100 }))); Assert.AreEqual(3, GetTestTable().Count(where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));
} }
/// <summary>Test dynamic where expression in parameters.</summary>
[TestMethod]
public void TestWhereIn3()
{
Assert.AreEqual(3L, GetTestBuilder()
.Where(x => x.id.In(75, 99, 100))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test dynamic where expression in parameters.</summary>
[TestMethod]
public void TestWhereIn4()
{
Assert.AreEqual(3L, GetTestBuilder()
.Where(x => x.id.In(new[] { 75, 99, 100 }))
.Select(x => x.Count())
.Scalar());
}
#endregion Where #endregion Where
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,16 +26,16 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Select namespace DynamORM.Tests.Select
{ {
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary> /// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
[TestClass] [TestFixture]
public class DynamicNoSchemaAccessTests : DynamicAccessTests public class DynamicNoSchemaAccessTests : DynamicAccessTests
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public override void SetUp() public override void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,12 @@
*/ */
using DynamORM.Tests.Helpers; using DynamORM.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Select namespace DynamORM.Tests.Select
{ {
/// <summary>Test standard dynamic access ORM. With out schema information from database.</summary> /// <summary>Test standard dynamic access ORM. With out schema information from database.</summary>
[TestClass] [TestFixture]
public class DynamicTypeSchemaAccessTests : DynamicNoSchemaAccessTests public class DynamicTypeSchemaAccessTests : DynamicNoSchemaAccessTests
{ {
/// <summary>Create table using specified method.</summary> /// <summary>Create table using specified method.</summary>

View File

@@ -1,321 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Linq;
using DynamORM.Builders;
using DynamORM.Builders.Implementation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DynamORM.Tests.Select
{
/// <summary>Tests of legacy parser methods.</summary>
[TestClass]
public class LegacyParserTests : TestsBase
{
/// <summary>Setup test parameters.</summary>
[TestInitialize]
public virtual void SetUp()
{
CreateTestDatabase();
CreateDynamicDatabase(
DynamicDatabaseOptions.SingleConnection |
DynamicDatabaseOptions.SingleTransaction |
DynamicDatabaseOptions.SupportLimitOffset);
}
/// <summary>Tear down test objects.</summary>
[TestCleanup]
public virtual void TearDown()
{
DestroyDynamicDatabase();
DestroyTestDatabase();
}
/// <summary>
/// Tests the where expression equal.
/// </summary>
[TestMethod]
public void TestWhereEq()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Eq(0));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" = [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression equal with brackets.
/// </summary>
[TestMethod]
public void TestWhereBracketsEq()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Eq(0).SetBeginBlock())
.Where(new DynamicColumn("u.IsActive").Eq(1).SetEndBlock());
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE ((u.\"Deleted\" = [${0}]) AND (u.\"IsActive\" = [${1}]))", cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression equal with brackets and or condition.
/// </summary>
[TestMethod]
public void TestWhereBracketsOrEq()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Eq(0).SetBeginBlock())
.Where(new DynamicColumn("u.IsActive").Eq(1).SetOr().SetEndBlock());
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE ((u.\"Deleted\" = [${0}]) OR (u.\"IsActive\" = [${1}]))", cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression equal with brackets.
/// </summary>
[TestMethod]
public void TestWhereBracketsOrEq2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Id_User").Greater(1))
.Where(new DynamicColumn("u.Deleted").Eq(0).SetBeginBlock())
.Where(new DynamicColumn("u.IsActive").Eq(1).SetOr().SetEndBlock());
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Id_User\" > [${0}]) AND ((u.\"Deleted\" = [${1}]) OR (u.\"IsActive\" = [${2}]))",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests the where expression equal with brackets.
/// </summary>
[TestMethod]
public void TestWhereBracketsOrEqForgotToEnd()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Id_User").Greater(1))
.Where(new DynamicColumn("u.Deleted").Eq(0).SetBeginBlock())
.Where(new DynamicColumn("u.IsActive").Eq(1).SetOr());
using (var con = Database.Open())
using (var c = con.CreateCommand())
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Id_User\" > @0) AND ((u.\"Deleted\" = @1) OR (u.\"IsActive\" = @2))"),
c.SetCommand(cmd).CommandText);
}
/// <summary>
/// Tests the where expression not equal.
/// </summary>
[TestMethod]
public void TestWhereNotEq()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Not(0));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" <> [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression greater.
/// </summary>
[TestMethod]
public void TestWhereGreater()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Greater(0));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" > [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression greater or equal.
/// </summary>
[TestMethod]
public void TestWhereGreaterOrEqual()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").GreaterOrEqual(0));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" >= [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression less.
/// </summary>
[TestMethod]
public void TestWhereLess()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Less(1));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" < [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression less or equal.
/// </summary>
[TestMethod]
public void TestWhereLessOrEqual()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").LessOrEqual(1));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" <= [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression like.
/// </summary>
[TestMethod]
public void TestWhereLike()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Like("%1"));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE u.\"Deleted\" LIKE [${0}]", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression not like.
/// </summary>
[TestMethod]
public void TestWhereNotLike()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").NotLike("%1"));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE u.\"Deleted\" NOT LIKE [${0}]", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression between.
/// </summary>
[TestMethod]
public void TestWhereBetween()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").Between(0, 1));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE u.\"Deleted\" BETWEEN [${0}] AND [${1}]", cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression in.
/// </summary>
[TestMethod]
public void TestWhereIn()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new DynamicColumn("u.Deleted").In(0, 1));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE u.\"Deleted\" IN([${0}], [${1}])", cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the where expression using anonymous types.
/// </summary>
[TestMethod]
public void TestWhereAnon()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.Where(new { Deleted = 0, IsActive = 1, _table = "u" });
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u WHERE (u.\"Deleted\" = [${0}]) AND (u.\"IsActive\" = [${1}])", cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests the order by column.
/// </summary>
[TestMethod]
public void TestOrderByCol()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.OrderByColumn(new DynamicColumn("u.Name").Desc());
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u ORDER BY u.\"Name\" DESC"), cmd.CommandText());
}
/// <summary>
/// Tests the order by column number.
/// </summary>
[TestMethod]
public void TestOrderByNum()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.OrderByColumn(new DynamicColumn("u.Name").SetAlias("1").Desc());
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u ORDER BY 1 DESC"), cmd.CommandText());
}
/// <summary>
/// Tests the group by column.
/// </summary>
[TestMethod]
public void TestGroupByCol()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(x => x.dbo.Users.As(x.u))
.GroupByColumn(new DynamicColumn("u.Name"));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS u GROUP BY u.\"Name\""), cmd.CommandText());
}
}
}

View File

@@ -1,942 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Linq;
using DynamORM.Builders;
using DynamORM.Builders.Implementation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DynamORM.Tests.Select
{
/// <summary>
/// New parser tests.
/// </summary>
[TestClass]
public class ParserTests : TestsBase
{
/// <summary>Setup test parameters.</summary>
[TestInitialize]
public virtual void SetUp()
{
CreateTestDatabase();
CreateDynamicDatabase(
DynamicDatabaseOptions.SingleConnection |
DynamicDatabaseOptions.SingleTransaction |
DynamicDatabaseOptions.SupportLimitOffset);
}
/// <summary>Tear down test objects.</summary>
[TestCleanup]
public virtual void TearDown()
{
try
{
DestroyDynamicDatabase();
DestroyTestDatabase();
}
catch { }
}
/// <summary>
/// Tests from method.
/// </summary>
[TestMethod]
public void TestFromGet()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users);
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests from method with multi tables.
/// </summary>
[TestMethod]
public void TestFromGetMultiKulti()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users, c => c.Clients);
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\", \"Clients\"", cmd.CommandText());
}
/// <summary>
/// Tests from method with as expression in text.
/// </summary>
[TestMethod]
public void TestFromGetAs1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As("c"));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests from method with as expression using lambda.
/// </summary>
[TestMethod]
public void TestFromGetAs2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests from method using text.
/// </summary>
[TestMethod]
public void TestFromText()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => "dbo.Users");
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests from method using text with decorators.
/// </summary>
[TestMethod]
public void TestFromDecoratedText()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => "\"dbo\".\"Users\"");
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests from method using text with as.
/// </summary>
[TestMethod]
public void TestFromTextAs1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => "dbo.Users AS c");
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with as.
/// </summary>
[TestMethod]
public void TestFromTextAs2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u(u.dbo.Users).As(u.u));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with as.
/// </summary>
[TestMethod]
public void TestFromTextAs3()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u("\"dbo\".\"Users\"").As(u.u));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with sub query.
/// </summary>
[TestMethod]
public void TestFromSubQuery1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u(new DynamicSelectQueryBuilder(Database).From(x => x.dbo.Users)).As("u"));
Assert.AreEqual("SELECT * FROM (SELECT * FROM \"dbo\".\"Users\") AS u", cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with sub query.
/// </summary>
[TestMethod]
public void TestFromSubQuery2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u(cmd.SubQuery(x => x.dbo.Users)).As("u"));
Assert.AreEqual("SELECT * FROM (SELECT * FROM \"dbo\".\"Users\") AS u", cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with sub query.
/// </summary>
[TestMethod]
public void TestFromSubQuery3()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.SubQuery((b, s) => b.From(y => y(s.From(x => x.dbo.Users)).As("u")));
Assert.AreEqual("SELECT * FROM (SELECT * FROM \"dbo\".\"Users\") AS u", cmd.CommandText());
}
/// <summary>
/// Tests where method with alias.
/// </summary>
[TestMethod]
public void TestWhereAlias()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.UserName == "admin");
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE (c.\"UserName\" = [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests where method with alias.
/// </summary>
[TestMethod]
public void TestHavingAlias()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Having(u => u.Sum(u.c.ClientsCount) > 10);
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c HAVING (Sum(c.\"ClientsCount\") > [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests complex where method with alias.
/// </summary>
[TestMethod]
public void TestWhereAliasComplex()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.UserName == "admin" || u.c.UserName == "root")
.Where(u => u.c.IsActive = true);
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE ((c.\"UserName\" = [${0}]) OR (c.\"UserName\" = [${1}])) AND c.\"IsActive\" = ([${2}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests where method with alias using in.
/// </summary>
[TestMethod]
public void TestWhereAliasIn()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
int[] ids = new int[] { 0, 1, 2, 3, 4, 5 };
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.UserName == "admin" || u.c.UserName == "root")
.Where(u => u.c.IsActive == true)
.Where(u => u.c.Id_User.In(ids));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE ((c.\"UserName\" = [${0}]) OR (c.\"UserName\" = [${1}])) AND (c.\"IsActive\" = [${2}]) AND c.\"Id_User\" IN({3})",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2],
string.Join(", ", cmd.Parameters.Keys.Skip(3).Select(p => string.Format("[${0}]", p)))), cmd.CommandText());
}
/// <summary>
/// Tests where method with alias using between.
/// </summary>
[TestMethod]
public void TestWhereAliasBetween1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
int[] ids = new int[] { 0, 5 };
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.UserName == "admin" || u.c.UserName == "root")
.Where(u => u.c.IsActive == true)
.Where(u => u.c.Id_User.Between(ids));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE ((c.\"UserName\" = [${0}]) OR (c.\"UserName\" = [${1}])) AND (c.\"IsActive\" = [${2}]) AND c.\"Id_User\" BETWEEN [${3}] AND [${4}]",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2],
cmd.Parameters.Keys.ToArray()[3], cmd.Parameters.Keys.ToArray()[4]), cmd.CommandText());
}
/// <summary>
/// Tests where method with alias using between.
/// </summary>
[TestMethod]
public void TestWhereAliasBetween2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
int[] ids = new int[] { 0, 5 };
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.UserName == "admin" || u.c.UserName == "root")
.Where(u => u.c.IsActive == true)
.Where(u => u.c.Id_User.Between(ids[0], ids[1]));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE ((c.\"UserName\" = [${0}]) OR (c.\"UserName\" = [${1}])) AND (c.\"IsActive\" = [${2}]) AND c.\"Id_User\" BETWEEN [${3}] AND [${4}]",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2],
cmd.Parameters.Keys.ToArray()[3], cmd.Parameters.Keys.ToArray()[4]), cmd.CommandText());
}
/// <summary>
/// Tests where method without alias.
/// </summary>
[TestMethod]
public void TestWhereNoAlias()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Where(u => u.UserName == "admin");
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" WHERE (\"UserName\" = [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests where method with full column name.
/// </summary>
[TestMethod]
public void TestWhereNoAliasTableName()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Where(u => u.dbo.Users.UserName == "admin");
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" WHERE (\"dbo\".\"Users\".\"UserName\" = [${0}])", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests simple join method.
/// </summary>
[TestMethod]
public void TestJoinClassic()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests inner join method.
/// </summary>
[TestMethod]
public void TestInnerJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.Inner().dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr INNER JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests inner join method with aliases mix.
/// </summary>
[TestMethod]
public void TestInnerJoin2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(usr => usr.Inner().dbo.UserClients.AS(usr.uc).On(usr.Id_User == usr.uc.User_Id && usr.uc.Users != null))
.Select(usr => usr.All(), uc => uc.Users);
Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN \"dbo\".\"UserClients\" AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))"), cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with sub query.
/// </summary>
[TestMethod]
public void TestInnerJoin3()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.SubQuery((b, s) => b.Join(usr => usr(s.From(x => x.dbo.UserClients)).Inner().As(usr.uc).On(usr.Id_User == usr.uc.User_Id && usr.uc.Users != null)))
.Select(usr => usr.All(), uc => uc.Users);
Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN (SELECT * FROM \"dbo\".\"UserClients\") AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))"), cmd.CommandText());
}
/// <summary>
/// Tests from method using invoke with sub query.
/// </summary>
[TestMethod]
public void TestInnerJoin4()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.SubQuery((b, s) => b.Join(usr => usr(s.From(x => x.dbo.UserClients).Where(x => x.Deleted == 0)).Inner().As(usr.uc).On(usr.Id_User == usr.uc.User_Id && usr.uc.Users != null)))
.Select(usr => usr.All(), uc => uc.Users);
Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN (SELECT * FROM \"dbo\".\"UserClients\" WHERE (\"Deleted\" = [${0}])) AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests left outer join method.
/// </summary>
[TestMethod]
public void TestLeftOuterJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.LeftOuter().dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr LEFT OUTER JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests left join method.
/// </summary>
[TestMethod]
public void TestLeftJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.Left().dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr LEFT JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests right outer join method.
/// </summary>
[TestMethod]
public void TestRightOuterJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.RightOuter().dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr RIGHT OUTER JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests right join method.
/// </summary>
[TestMethod]
public void TestRightJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.Right().dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr RIGHT JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
}
/// <summary>
/// Tests complex join with parameters.
/// </summary>
[TestMethod]
public void TestJoinClassicWithParamAndWhere()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(u => u.dbo.UserClients.AS(u.uc).On(u.usr.Id_User == u.uc.User_Id && u.uc.Deleted == 0))
.Where(u => u.usr.Active == true);
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr JOIN \"dbo\".\"UserClients\" AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Deleted\" = [${0}])) WHERE (usr.\"Active\" = [${1}])",
cmd.Parameters.Keys.First(), cmd.Parameters.Keys.Last()), cmd.CommandText());
}
/// <summary>
/// Tests select all.
/// </summary>
[TestMethod]
public void TestSelectAll1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.c.All());
Assert.AreEqual("SELECT c.* FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select all.
/// </summary>
[TestMethod]
public void TestSelectAll2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Select(u => u.dbo.Users.All());
Assert.AreEqual("SELECT \"dbo\".\"Users\".* FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests select field.
/// </summary>
[TestMethod]
public void TestSelectField1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.c.UserName);
Assert.AreEqual("SELECT c.\"UserName\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select field.
/// </summary>
[TestMethod]
public void TestSelectField2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Select(u => u.dbo.Users.UserName);
Assert.AreEqual("SELECT \"dbo\".\"Users\".\"UserName\" FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests select field with alias.
/// </summary>
[TestMethod]
public void TestSelectFieldAlias1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.c.UserName.As(u.Name));
Assert.AreEqual("SELECT c.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select field with alias.
/// </summary>
[TestMethod]
public void TestSelectFieldAlias2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Select(u => u.dbo.Users.UserName.As(u.Name));
Assert.AreEqual("SELECT \"dbo\".\"Users\".\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests select field with alias.
/// </summary>
[TestMethod]
public void TestSelectFieldAlias3()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.u))
.Select(u => u.UserName.As(u.Name));
Assert.AreEqual("SELECT u.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
}
/// <summary>
/// Tests select field with alias.
/// </summary>
[TestMethod]
public void TestSelectFieldAlias4()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.u))
.Select(u => u.UserName.As(u.u.Name));
Assert.AreEqual("SELECT u.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
}
/// <summary>
/// Tests select aggregate field with alias (Sum).
/// </summary>
[TestMethod]
public void TestSelectAggregateField1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.Sum(u.c.UserName).As(u.Name));
Assert.AreEqual("SELECT Sum(c.\"UserName\") AS \"Name\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select aggregate field with alias (Coalesce).
/// </summary>
[TestMethod]
public void TestSelectAggregateField2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.Coalesce(u.c.UserName, u.c.FirstName + " " + u.c.LastName).As(u.Name));
Assert.AreEqual(string.Format("SELECT Coalesce(c.\"UserName\", ((c.\"FirstName\" + [${0}]) + c.\"LastName\")) AS \"Name\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests select aggregate field with alias (Sum).
/// </summary>
[TestMethod]
public void TestSelectAggregateField3()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users)
.Select(u => u.Sum(u.dbo.Users.UserName));
Assert.AreEqual("SELECT Sum(\"dbo\".\"Users\".\"UserName\") FROM \"dbo\".\"Users\"", cmd.CommandText());
}
/// <summary>
/// Tests select aggregate field with alias (Sum).
/// </summary>
[TestMethod]
public void TestSelectAggregateField4()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.Sum(u("\"UserName\"")).As(u.Name));
Assert.AreEqual("SELECT Sum(\"UserName\") AS \"Name\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select aggregate field with alias (Sum).
/// </summary>
[TestMethod]
public void TestSelectAggregateField5()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u(u.Sum(u("\"UserName\"")), " + 1").As(u.Name));
Assert.AreEqual("SELECT Sum(\"UserName\") + 1 AS \"Name\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select from anonymous type.
/// </summary>
[TestMethod]
public void TestSelectAnon()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => new
{
Id_User = u.c.Id_User,
Name = u.c.UserName,
});
Assert.AreEqual("SELECT c.\"Id_User\" AS \"Id_User\", c.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestSelectCaseEscaped1()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u("CASE ", u.c.IsActive, " WHEN ", 1, " THEN ", 0, " ELSE ", 1, " END").As(u.Deleted));
Assert.AreEqual(string.Format("SELECT CASE c.\"IsActive\" WHEN [${0}] THEN [${1}] ELSE [${2}] END AS \"Deleted\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestSelectCaseEscaped2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u("CASE WHEN ", u.c.IsActive == 1, " THEN ", 0, " ELSE ", 1, " END").As(u.Deleted));
Assert.AreEqual(string.Format("SELECT CASE WHEN (c.\"IsActive\" = [${0}]) THEN [${1}] ELSE [${2}] END AS \"Deleted\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestCoalesceEscaped()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u("COALESCE(", Database.DecorateName("ServerHash"), ", ", new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ")").As(u.Hash));
Assert.AreEqual(string.Format("SELECT COALESCE(\"ServerHash\", [${0}]) AS \"Hash\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0]), cmd.CommandText());
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestCoalesce()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.Coalesce(u.c.ServerHash, new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }).As(u.Hash));
Assert.AreEqual(string.Format("SELECT Coalesce(c.\"ServerHash\", [${0}]) AS \"Hash\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0]), cmd.CommandText());
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestCoalesceCalculatedArgs()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.Coalesce(u.c.Test1 + "_", u.c.Test2 + "_", u.c.Test3 + "_").As(u.Hash));
Assert.AreEqual(string.Format("SELECT Coalesce((c.\"Test1\" + [${0}]), (c.\"Test2\" + [${1}]), (c.\"Test3\" + [${2}])) AS \"Hash\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
//var c = Database.Open().CreateCommand();
//cmd.FillCommand(c);
//c.Dispose();
}
/// <summary>
/// Tests select escaped case.
/// </summary>
[TestMethod]
public void TestCoalesceInWhere()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u.ServerHash.As(u.Hash))
.Where(u => u.Coalesce(u.c.ServerHash, new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }) == new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
Assert.AreEqual(string.Format("SELECT \"ServerHash\" AS \"Hash\" FROM \"dbo\".\"Users\" AS c WHERE (Coalesce(c.\"ServerHash\", [${0}]) = [${1}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1]), cmd.CommandText());
}
/// <summary>
/// Tests select escaped case with sub query.
/// </summary>
[TestMethod]
public void TestSelectCaseEscapedAndSub()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u("CASE WHEN ", u.c.IsActive == 1, " AND ", u.c.IsAdmin == u(cmd.SubQuery()
.From(x => x.dbo.AccessRights.As(x.a))
.Where(x => x.a.User_Id == x.c.Id_User)
.Select(x => x.a.IsAdmin)), " THEN ", 0, " ELSE ", 1, " END").As(u.Deleted));
Assert.AreEqual(string.Format("SELECT CASE WHEN (c.\"IsActive\" = [${0}]) AND (c.\"IsAdmin\" = (SELECT a.\"IsAdmin\" FROM \"dbo\".\"AccessRights\" AS a WHERE (a.\"User_Id\" = c.\"Id_User\"))) THEN [${1}] ELSE [${2}] END AS \"Deleted\" FROM \"dbo\".\"Users\" AS c",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests group by.
/// </summary>
[TestMethod]
public void TestGroupBy()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.GroupBy(u => u.c.UserName);
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c GROUP BY c.\"UserName\"", cmd.CommandText());
}
/// <summary>
/// Tests order by.
/// </summary>
[TestMethod]
public void TestOrderBy()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.OrderBy(u => u.c.UserName);
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c ORDER BY c.\"UserName\" ASC", cmd.CommandText());
}
/// <summary>
/// Tests order by using string with number.
/// </summary>
[TestMethod]
public void TestOrderByNumberedColumnStr()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.OrderBy(u => "1 DESC");
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c ORDER BY 1 DESC", cmd.CommandText());
}
/// <summary>
/// Tests order by using member with number.
/// </summary>
[TestMethod]
public void TestOrderByNumberedColFn()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.OrderBy(u => u.Desc(1));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c ORDER BY 1 DESC", cmd.CommandText());
}
/// <summary>
/// Tests order by using member with field.
/// </summary>
[TestMethod]
public void TestOrderByAlt()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.OrderBy(u => u.Desc(u.c.UserName));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c ORDER BY c.\"UserName\" DESC", cmd.CommandText());
}
/// <summary>
/// Tests sub query select.
/// </summary>
[TestMethod]
public void TestSubQuerySelect()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Select(u => u(cmd.SubQuery()
.From(x => x.dbo.AccessRights.As(x.a))
.Where(x => x.a.User_Id == x.c.Id_User)
.Select(x => x.a.IsAdmin)).As(u.IsAdmin));
Assert.AreEqual("SELECT (SELECT a.\"IsAdmin\" FROM \"dbo\".\"AccessRights\" AS a WHERE (a.\"User_Id\" = c.\"Id_User\")) AS \"IsAdmin\" FROM \"dbo\".\"Users\" AS c", cmd.CommandText());
}
/// <summary>
/// Tests sub query where.
/// </summary>
[TestMethod]
public void TestSubQueryWhere()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.IsAdmin == u(cmd.SubQuery()
.From(x => x.dbo.AccessRights.As(x.a))
.Where(x => x.a.User_Id == x.c.Id_User)
.Select(x => x.a.IsAdmin)));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c WHERE (c.\"IsAdmin\" = (SELECT a.\"IsAdmin\" FROM \"dbo\".\"AccessRights\" AS a WHERE (a.\"User_Id\" = c.\"Id_User\")))", cmd.CommandText());
}
/// <summary>
/// Tests sub query in.
/// </summary>
[TestMethod]
public void TestSubQueryWhereIn()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Where(u => u.c.Id_User.In(u(cmd.SubQuery()
.From(x => x.dbo.AccessRights.As(x.a))
.Where(x => x.a.IsAdmin == 1)
.Select(x => x.a.User_Id))));
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS c WHERE c.\"Id_User\" IN((SELECT a.\"User_Id\" FROM \"dbo\".\"AccessRights\" AS a WHERE (a.\"IsAdmin\" = [${0}])))", cmd.Parameters.Keys.First()), cmd.CommandText());
}
/// <summary>
/// Tests sub query join.
/// </summary>
[TestMethod]
public void TestSubQueryJoin()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.c))
.Join(u => u.Inner()(cmd.SubQuery()
.From(x => x.dbo.AccessRights.As(x.a))
.Select(x => x.a.IsAdmin, x => x.a.User_Id)).As(u.ar).On(u.ar.User_Id == u.c.Id_User));
Assert.AreEqual("SELECT * FROM \"dbo\".\"Users\" AS c INNER JOIN (SELECT a.\"IsAdmin\", a.\"User_Id\" FROM \"dbo\".\"AccessRights\" AS a) AS ar ON (ar.\"User_Id\" = c.\"Id_User\")", cmd.CommandText());
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,6 @@ using NUnit.Framework;
namespace DynamORM.Tests.Select namespace DynamORM.Tests.Select
{ {
/// <summary>Test typed ORM.</summary> /// <summary>Test typed ORM.</summary>
[TestFixture]
public class RenamedTypedAccessTests : TypedAccessTests<Users> 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> /// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -29,27 +29,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DynamORM.Builders;
using DynamORM.Tests.Helpers; using DynamORM.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework;
namespace DynamORM.Tests.Select namespace DynamORM.Tests.Select
{ {
/// <summary>Test typed ORM.</summary> /// <summary>Test typed ORM.</summary>
/// <typeparam name="T">Type to test.</typeparam> /// <typeparam name="T">Type to test.</typeparam>
[TestClass] [TestFixture(typeof(users))]
public class TypedAccessTests<T> : TestsBase where T : class public class TypedAccessTests<T> : TestsBase
{ {
/// <summary>Setup test parameters.</summary> /// <summary>Setup test parameters.</summary>
[TestInitialize] [TestFixtureSetUp]
public virtual void SetUp() public virtual void SetUp()
{ {
CreateTestDatabase(); CreateTestDatabase();
CreateDynamicDatabase(); CreateDynamicDatabase();
// Cache table (profiler freaks out)
GetTestTable();
} }
/// <summary>Tear down test objects.</summary> /// <summary>Tear down test objects.</summary>
[TestCleanup] [TestFixtureTearDown]
public virtual void TearDown() public virtual void TearDown()
{ {
DestroyDynamicDatabase(); DestroyDynamicDatabase();
@@ -63,17 +65,10 @@ namespace DynamORM.Tests.Select
return Database.Table(); return Database.Table();
} }
/// <summary>Create table using specified method.</summary>
/// <returns>Dynamic table.</returns>
public virtual IDynamicSelectQueryBuilder GetTestBuilder()
{
return Database.Table().Query() as IDynamicSelectQueryBuilder;
}
#region Select typed #region Select typed
/// <summary>Test load all rows into mapped list alternate way.</summary> /// <summary>Test load all rows into mapped list alternate way.</summary>
[TestMethod] [Test]
public virtual void TestTypedGetAll() public virtual void TestTypedGetAll()
{ {
var list = (GetTestTable().Query(type: typeof(T)) as IEnumerable<object>).Cast<T>().ToList(); var list = (GetTestTable().Query(type: typeof(T)) as IEnumerable<object>).Cast<T>().ToList();
@@ -81,57 +76,22 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(200, list.Count); Assert.AreEqual(200, list.Count);
} }
/// <summary>Test load all rows into mapped list alternate way.</summary>
[TestMethod]
public virtual void TestTypedGetAll2()
{
var list = GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Execute()
.MapEnumerable<T>()
.ToList();
Assert.AreEqual(200, list.Count);
}
/// <summary>Test load all rows into mapped list alternate way.</summary>
[TestMethod]
public virtual void TestTypedGetAll3()
{
var list = GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Execute<T>()
.ToList();
Assert.AreEqual(200, list.Count);
}
/// <summary>Test unknown op.</summary> /// <summary>Test unknown op.</summary>
[TestMethod] [Test]
public virtual void TestTypedUnknownOperation() public virtual void TestTypedUnknownOperation()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(type: typeof(T), with: "cheese")); Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch(type: typeof(T), with: "cheese"));
} }
/// <summary>Test typed <c>Count</c> method.</summary> /// <summary>Test typed <c>Count</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedCount() public virtual void TestTypedCount()
{ {
Assert.AreEqual(200, GetTestTable().Count(type: typeof(T), columns: "id")); Assert.AreEqual(200, GetTestTable().Count(type: typeof(T), columns: "id"));
} }
/// <summary>Test typed <c>Count</c> method.</summary> /// <summary>Test count with in steatement.</summary>
[TestMethod] [Test]
public virtual void TestTypedCount2()
{
Assert.AreEqual(200, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Count(x.t.id))
.Scalar());
}
/// <summary>Test count with in statement.</summary>
[TestMethod]
public virtual void TestTypedSelectInEnumerableCount() public virtual void TestTypedSelectInEnumerableCount()
{ {
Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn
@@ -141,19 +101,8 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test count with in statement.</summary> /// <summary>Test count with in steatement.</summary>
[TestMethod] [Test]
public virtual void TestTypedSelectInEnumerableCount2()
{
Assert.AreEqual(4, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.last.In(new object[] { "Hendricks", "Goodwin", "Freeman" }.Take(3)))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test count with in statement.</summary>
[TestMethod]
public virtual void TestTypedSelectInArrayCount() public virtual void TestTypedSelectInArrayCount()
{ {
Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count(type: typeof(T), last: new DynamicColumn
@@ -163,155 +112,71 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test count with in statement.</summary>
[TestMethod]
public virtual void TestTypedSelectInArrayCount2()
{
Assert.AreEqual(4, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.last.In(new object[] { "Hendricks", "Goodwin", "Freeman" }))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed <c>First</c> method.</summary> /// <summary>Test typed <c>First</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedFirst() public virtual void TestTypedFirst()
{ {
Assert.AreEqual(1, GetTestTable().First(type: typeof(T), columns: "id").id); Assert.AreEqual(1, GetTestTable().First(type: typeof(T), columns: "id").id);
} }
/// <summary>Test typed <c>First</c> method.</summary>
[TestMethod]
public virtual void TestTypedFirst2()
{
Assert.AreEqual(1, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.t.id)
.Execute()
.First().id);
}
/// <summary>Test typed <c>Last</c> method.</summary> /// <summary>Test typed <c>Last</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedLast() public virtual void TestTypedLast()
{ {
Assert.AreEqual(200, GetTestTable().Last(type: typeof(T), columns: "id").id); Assert.AreEqual(200, GetTestTable().Last(type: typeof(T), columns: "id").id);
} }
/// <summary>Test typed <c>Last</c> method.</summary>
[TestMethod]
public virtual void TestTypedLast2()
{
Assert.AreEqual(200, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.t.id)
.Execute()
.Last().id);
}
/// <summary>Test typed <c>Count</c> method.</summary> /// <summary>Test typed <c>Count</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedCountSpecificRecord() public virtual void TestTypedCountSpecificRecord()
{ {
Assert.AreEqual(1, GetTestTable().Count(type: typeof(T), first: "Ori")); Assert.AreEqual(1, GetTestTable().Count(type: typeof(T), first: "Ori"));
} }
/// <summary>Test typed <c>Min</c> method.</summary> /// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedMin() public virtual void TestTypedMin()
{ {
Assert.AreEqual(1, GetTestTable().Min(type: typeof(T), columns: "id")); Assert.AreEqual(1, GetTestTable().Min(type: typeof(T), columns: "id"));
} }
/// <summary>Test typed <c>Min</c> method.</summary> /// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedMin2()
{
Assert.AreEqual(1, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Min(x.t.id))
.Scalar());
}
/// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod]
public virtual void TestTypedMax() public virtual void TestTypedMax()
{ {
Assert.AreEqual(200, GetTestTable().Max(type: typeof(T), columns: "id")); Assert.AreEqual(200, GetTestTable().Max(type: typeof(T), columns: "id"));
} }
/// <summary>Test typed <c>Min</c> method.</summary> /// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedMax2()
{
Assert.AreEqual(200, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Max(x.t.id))
.Scalar());
}
/// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod]
public virtual void TestTypedtAvg() public virtual void TestTypedtAvg()
{ {
Assert.AreEqual(100.5, GetTestTable().Avg(type: typeof(T), columns: "id")); Assert.AreEqual(100.5, GetTestTable().Avg(type: typeof(T), columns: "id"));
} }
/// <summary>Test typed <c>Min</c> method.</summary>
[TestMethod]
public virtual void TestTypedtAvg2()
{
Assert.AreEqual(100.5, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Avg(x.t.id))
.Scalar());
}
/// <summary>Test typed <c>Sum</c> method.</summary> /// <summary>Test typed <c>Sum</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedSum() public virtual void TestTypedSum()
{ {
Assert.AreEqual(20100, GetTestTable().Sum(type: typeof(T), columns: "id")); Assert.AreEqual(20100, GetTestTable().Sum(type: typeof(T), columns: "id"));
} }
/// <summary>Test typed <c>Sum</c> method.</summary>
[TestMethod]
public virtual void TestTypedSum2()
{
Assert.AreEqual(20100, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Sum(x.t.id))
.Scalar());
}
/// <summary>Test typed <c>Scalar</c> method for invalid operation exception.</summary> /// <summary>Test typed <c>Scalar</c> method for invalid operation exception.</summary>
[TestMethod] [Test]
public virtual void TestTypedScalarException() public virtual void TestTypedScalarException()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().Scalar(type: typeof(T), id: 19)); Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar(type: typeof(T), id: 19));
} }
/// <summary>Test typed <c>Scalar</c> method.</summary> /// <summary>Test typed <c>Scalar</c> method.</summary>
[TestMethod] [Test]
public virtual void TestTypedScalar() public virtual void TestTypedScalar()
{ {
Assert.AreEqual("Ori", GetTestTable().Scalar(type: typeof(T), columns: "first", id: 19)); Assert.AreEqual("Ori", GetTestTable().Scalar(type: typeof(T), columns: "first", id: 19));
} }
/// <summary>Test typed <c>Scalar</c> method.</summary>
[TestMethod]
public void TestTypedScalar2()
{
Assert.AreEqual("Ori", GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id == 19)
.Select(x => x.t.first)
.Scalar());
}
/// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate.</summary> /// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate.</summary>
[TestMethod] [Test]
public virtual void TestTypedScalarGroupConcat() public virtual void TestTypedScalarGroupConcat()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -320,22 +185,8 @@ namespace DynamORM.Tests.Select
GetTestTable().Scalar(type: typeof(T), columns: "first:first:group_concat", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 })); 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.</summary>
[TestMethod]
public virtual void TestTypedScalarGroupConcat2()
{
// 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",
GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id < 20)
.Select(x => x.group_concat(x.t.first).As(x.first))
.Scalar());
}
/// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary> /// <summary>Test typed <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
[TestMethod] [Test]
public virtual void TestTypedScalarGroupConcatNoAggregateField() public virtual void TestTypedScalarGroupConcatNoAggregateField()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -344,22 +195,8 @@ namespace DynamORM.Tests.Select
GetTestTable().Scalar(type: typeof(T), columns: "group_concat(first):first", id: new DynamicColumn { Operator = DynamicColumn.CompareOperator.Lt, Value = 20 })); GetTestTable().Scalar(type: typeof(T), columns: "group_concat(first):first", 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>
[TestMethod]
public virtual void TestTypedScalarGroupConcatNoAggregateField2()
{
// 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",
GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id < 20)
.SelectColumn("group_concat(first):first")
.Scalar());
}
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary> /// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
[TestMethod] [Test]
public virtual void TestTypedFancyAggregateQuery() 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(); var v = (GetTestTable().Query(type: typeof(T), columns: "first,first:aggregatefield:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
@@ -373,61 +210,20 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(1, v.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>
[TestMethod]
public virtual void TestTypedFancyAggregateQuery2()
{
var v = GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.t.first, x => x.Count(x.t.first).As(x.aggregatefield))
.GroupBy(x => x.t.first)
.OrderBy(x => x.Desc(2))
.Execute()
.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> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
[TestMethod] [Test]
public virtual void TestTypedAggregateInAggregate() public virtual void TestTypedAggregateInAggregate()
{ {
Assert.AreEqual(12.77, GetTestTable().Scalar(type: typeof(T), columns: @"length(""login""):len:avg")); 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("login")) len from "users";</code>.</summary>
[TestMethod]
public virtual void TestTypedAggregateInAggregate2()
{
Assert.AreEqual(12.77, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => x.Avg(x.Length(x.t.login)).As(x.len))
.Scalar());
}
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
[TestMethod] [Test]
public virtual void TestTypedAggregateInAggregateMark2() public virtual void TestTypedAggregateInAggregateMark2()
{ {
Assert.AreEqual(27.7, GetTestTable().Avg(type: typeof(T), columns: @"length(""email""):len")); Assert.AreEqual(27.7, GetTestTable().Avg(type: typeof(T), columns: @"length(""email""):len"));
} }
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
[TestMethod]
public virtual void TestTypedAggregateInAggregateMark3()
{
Assert.AreEqual(27.7, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Select(x => "AVG(LENGTH(t.email)) AS LEN")
.Scalar());
}
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary> /// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
public virtual void TestTypedFunctionInWhere() public virtual void TestTypedFunctionInWhere()
{ {
@@ -442,18 +238,8 @@ namespace DynamORM.Tests.Select
})); }));
} }
/// <summary>Test emails longer than 27 chars. <code>select count(*) from "users" where length("email") > 27;</code>.</summary>
public virtual void TestTypedFunctionInWhere2()
{
Assert.AreEqual(97, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.Length(x.t.email) > 27)
.Select(x => x.Count(x.t.All()))
.Scalar());
}
/// <summary>Test typed <c>Single</c> multi.</summary> /// <summary>Test typed <c>Single</c> multi.</summary>
[TestMethod] [Test]
public virtual void TestTypedSingleObject() public virtual void TestTypedSingleObject()
{ {
var exp = new { id = 19, first = "Ori", last = "Ellis" }; var exp = new { id = 19, first = "Ori", last = "Ellis" };
@@ -464,238 +250,93 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(exp.last, o.last); Assert.AreEqual(exp.last, o.last);
} }
/// <summary>Test typed <c>Single</c> multi.</summary>
[TestMethod]
public virtual void TestTypedSingleObject2()
{
var exp = new { id = 19, first = "Ori", last = "Ellis" };
var o = GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id == 19)
.Select(x => new { id = x.t.id, first = x.t.first, last = x.t.last })
.Execute()
.First();
Assert.AreEqual(exp.id, o.id);
Assert.AreEqual(exp.first, o.first);
Assert.AreEqual(exp.last, o.last);
}
#endregion Select typed #endregion Select typed
#region Where typed #region Where typed
/// <summary>Test typed where expression equal.</summary> /// <summary>Test typed where expression equal.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereEq() public virtual void TestTypedWhereEq()
{ {
Assert.AreEqual("hoyt.tran", GetTestTable().Single(type: typeof(T), where: new DynamicColumn("id").Eq(100)).login); Assert.AreEqual("hoyt.tran", GetTestTable().Single(type: typeof(T), where: new DynamicColumn("id").Eq(100)).login);
} }
/// <summary>Test typed where expression equal.</summary>
[TestMethod]
public virtual void TestTypedWhereEq2()
{
Assert.AreEqual("hoyt.tran", GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id == 100).Execute().First().login);
}
/// <summary>Test typed where expression not equal.</summary> /// <summary>Test typed where expression not equal.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereNot() public virtual void TestTypedWhereNot()
{ {
Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Not(100))); Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Not(100)));
} }
/// <summary>Test typed where expression not equal.</summary>
[TestMethod]
public virtual void TestTypedWhereNot2()
{
Assert.AreEqual(199, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id != 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression like.</summary> /// <summary>Test typed where expression like.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereLike() public virtual void TestTypedWhereLike()
{ {
Assert.AreEqual(100, GetTestTable().Single(type: typeof(T), where: new DynamicColumn("login").Like("Hoyt.%")).id); Assert.AreEqual(100, GetTestTable().Single(type: typeof(T), where: new DynamicColumn("login").Like("Hoyt.%")).id);
} }
/// <summary>Test typed where expression like.</summary>
[TestMethod]
public virtual void TestTypedWhereLike2()
{
Assert.AreEqual(100, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.login.Like("Hoyt.%")).Execute().First().id);
}
/// <summary>Test typed where expression not like.</summary> /// <summary>Test typed where expression not like.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereNotLike() public virtual void TestTypedWhereNotLike()
{ {
Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("login").NotLike("Hoyt.%"))); Assert.AreEqual(199, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("login").NotLike("Hoyt.%")));
} }
/// <summary>Test typed where expression not like.</summary>
[TestMethod]
public virtual void TestTypedWhereNotLike2()
{
Assert.AreEqual(199, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.login.NotLike("Hoyt.%"))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression not like.</summary>
[TestMethod]
public virtual void TestTypedWhereNotLike3()
{
Assert.AreEqual(199, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => !x.t.login.Like("Hoyt.%"))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression greater.</summary> /// <summary>Test typed where expression greater.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereGt() public virtual void TestTypedWhereGt()
{ {
Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Greater(100))); Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Greater(100)));
} }
/// <summary>Test typed where expression greater.</summary>
[TestMethod]
public virtual void TestTypedWhereGt2()
{
Assert.AreEqual(100, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id > 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression greater or equal.</summary> /// <summary>Test typed where expression greater or equal.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereGte() public virtual void TestTypedWhereGte()
{ {
Assert.AreEqual(101, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").GreaterOrEqual(100))); Assert.AreEqual(101, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").GreaterOrEqual(100)));
} }
/// <summary>Test typed where expression greater or equal.</summary>
[TestMethod]
public virtual void TestTypedWhereGte2()
{
Assert.AreEqual(101, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id >= 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression less.</summary> /// <summary>Test typed where expression less.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereLt() public virtual void TestTypedWhereLt()
{ {
Assert.AreEqual(99, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Less(100))); Assert.AreEqual(99, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Less(100)));
} }
/// <summary>Test typed where expression less.</summary>
[TestMethod]
public virtual void TestTypedWhereLt2()
{
Assert.AreEqual(99, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id < 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression less or equal.</summary> /// <summary>Test typed where expression less or equal.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereLte() public virtual void TestTypedWhereLte()
{ {
Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").LessOrEqual(100))); Assert.AreEqual(100, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").LessOrEqual(100)));
} }
/// <summary>Test typed where expression less or equal.</summary>
[TestMethod]
public virtual void TestTypedWhereLte2()
{
Assert.AreEqual(100, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id <= 100)
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression between.</summary> /// <summary>Test typed where expression between.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereBetween() public virtual void TestTypedWhereBetween()
{ {
Assert.AreEqual(26, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Between(75, 100))); Assert.AreEqual(26, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").Between(75, 100)));
} }
/// <summary>Test typed where expression between.</summary> /// <summary>Test typed where expression in params.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereBetween2()
{
Assert.AreEqual(26, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id.Between(75, 100))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression in parameters.</summary>
[TestMethod]
public virtual void TestTypedWhereIn1() public virtual void TestTypedWhereIn1()
{ {
Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(75, 99, 100))); Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(75, 99, 100)));
} }
/// <summary>Test typed where expression in array.</summary> /// <summary>Test typed where expression in array.</summary>
[TestMethod] [Test]
public virtual void TestTypedWhereIn2() public virtual void TestTypedWhereIn2()
{ {
Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(new[] { 75, 99, 100 }))); Assert.AreEqual(3, GetTestTable().Count(type: typeof(T), where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));
} }
/// <summary>Test typed where expression in parameters.</summary>
[TestMethod]
public virtual void TestTypedWhereIn3()
{
Assert.AreEqual(3, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id.In(75, 99, 100))
.Select(x => x.Count())
.Scalar());
}
/// <summary>Test typed where expression in array.</summary>
[TestMethod]
public virtual void TestTypedWhereIn4()
{
Assert.AreEqual(3, GetTestBuilder()
.From(x => x(typeof(T)).As(x.t))
.Where(x => x.t.id.In(new[] { 75, 99, 100 }))
.Select(x => x.Count())
.Scalar());
}
#endregion Where typed #endregion Where typed
#region Select generic #region Select generic
/// <summary>Test load all rows into mapped list alternate way.</summary> /// <summary>Test load all rows into mapped list alternate way.</summary>
[TestMethod] [Test]
public virtual void TestGenericGetAll() public virtual void TestGenericGetAll()
{ {
var list = (GetTestTable().Query<T>() as IEnumerable<object>).Cast<T>().ToList(); var list = (GetTestTable().Query<T>() as IEnumerable<object>).Cast<T>().ToList();
@@ -704,21 +345,21 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test unknown op.</summary> /// <summary>Test unknown op.</summary>
[TestMethod] [Test]
public virtual void TestGenericUnknownOperation() public virtual void TestGenericUnknownOperation()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch<T>(with: "cheese")); Assert.Throws<InvalidOperationException>(() => GetTestTable().MakeMeASandwitch<T>(with: "cheese"));
} }
/// <summary>Test generic <c>Count</c> method.</summary> /// <summary>Test generic <c>Count</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericCount() public virtual void TestGenericCount()
{ {
Assert.AreEqual(200, GetTestTable().Count<T>(columns: "id")); Assert.AreEqual(200, GetTestTable().Count<T>(columns: "id"));
} }
/// <summary>Test count with in statement.</summary> /// <summary>Test count with in statement.</summary>
[TestMethod] [Test]
public virtual void TestGenericSelectInEnumerableCount() public virtual void TestGenericSelectInEnumerableCount()
{ {
Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn
@@ -729,7 +370,7 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test count with in statement.</summary> /// <summary>Test count with in statement.</summary>
[TestMethod] [Test]
public virtual void TestGenericSelectInArrayCount() public virtual void TestGenericSelectInArrayCount()
{ {
Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn Assert.AreEqual(4, GetTestTable().Count<T>(last: new DynamicColumn
@@ -740,70 +381,70 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test generic <c>First</c> method.</summary> /// <summary>Test generic <c>First</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericFirst() public virtual void TestGenericFirst()
{ {
Assert.AreEqual(1, GetTestTable().First<T>(columns: "id").id); Assert.AreEqual(1, GetTestTable().First<T>(columns: "id").id);
} }
/// <summary>Test generic <c>Last</c> method.</summary> /// <summary>Test generic <c>Last</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericLast() public virtual void TestGenericLast()
{ {
Assert.AreEqual(200, GetTestTable().Last<T>(columns: "id").id); Assert.AreEqual(200, GetTestTable().Last<T>(columns: "id").id);
} }
/// <summary>Test generic <c>Count</c> method.</summary> /// <summary>Test generic <c>Count</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericCountSpecificRecord() public virtual void TestGenericCountSpecificRecord()
{ {
Assert.AreEqual(1, GetTestTable().Count<T>(first: "Ori")); Assert.AreEqual(1, GetTestTable().Count<T>(first: "Ori"));
} }
/// <summary>Test generic <c>Min</c> method.</summary> /// <summary>Test generic <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericMin() public virtual void TestGenericMin()
{ {
Assert.AreEqual(1, GetTestTable().Min<T>(columns: "id")); Assert.AreEqual(1, GetTestTable().Min<T>(columns: "id"));
} }
/// <summary>Test generic <c>Min</c> method.</summary> /// <summary>Test generic <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericMax() public virtual void TestGenericMax()
{ {
Assert.AreEqual(200, GetTestTable().Max<T>(columns: "id")); Assert.AreEqual(200, GetTestTable().Max<T>(columns: "id"));
} }
/// <summary>Test generic <c>Min</c> method.</summary> /// <summary>Test generic <c>Min</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenerictAvg() public virtual void TestGenerictAvg()
{ {
Assert.AreEqual(100.5, GetTestTable().Avg<T>(columns: "id")); Assert.AreEqual(100.5, GetTestTable().Avg<T>(columns: "id"));
} }
/// <summary>Test generic <c>Sum</c> method.</summary> /// <summary>Test generic <c>Sum</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericSum() public virtual void TestGenericSum()
{ {
Assert.AreEqual(20100, GetTestTable().Sum<T>(columns: "id")); Assert.AreEqual(20100, GetTestTable().Sum<T>(columns: "id"));
} }
/// <summary>Test generic <c>Scalar</c> method for invalid operation exception.</summary> /// <summary>Test generic <c>Scalar</c> method for invalid operation exception.</summary>
[TestMethod] [Test]
public virtual void TestGenericScalarException() public virtual void TestGenericScalarException()
{ {
Assert.ThrowsException<InvalidOperationException>(() => GetTestTable().Scalar<T>(id: 19)); Assert.Throws<InvalidOperationException>(() => GetTestTable().Scalar<T>(id: 19));
} }
/// <summary>Test generic <c>Scalar</c> method.</summary> /// <summary>Test generic <c>Scalar</c> method.</summary>
[TestMethod] [Test]
public virtual void TestGenericScalar() public virtual void TestGenericScalar()
{ {
Assert.AreEqual("Ori", GetTestTable().Scalar<T>(columns: "first", id: 19)); Assert.AreEqual("Ori", GetTestTable().Scalar<T>(columns: "first", id: 19));
} }
/// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate.</summary> /// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate.</summary>
[TestMethod] [Test]
public virtual void TestGenericScalarGroupConcat() public virtual void TestGenericScalarGroupConcat()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -813,7 +454,7 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary> /// <summary>Test generic <c>Scalar</c> method with SQLite specific aggregate not using aggregate field.</summary>
[TestMethod] [Test]
public virtual void TestGenericScalarGroupConcatNoAggregateField() public virtual void TestGenericScalarGroupConcatNoAggregateField()
{ {
// This test should produce something like this: // This test should produce something like this:
@@ -823,7 +464,7 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary> /// <summary>Test something fancy... like: <code>select "first", count("first") aggregatefield from "users" group by "first" order by 2 desc;</code>.</summary>
[TestMethod] [Test]
public virtual void TestGenericFancyAggregateQuery() public virtual void TestGenericFancyAggregateQuery()
{ {
var v = (GetTestTable().Query<T>(columns: "first,first:aggregatefield:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList(); var v = (GetTestTable().Query<T>(columns: "first,first:aggregatefield:count", group: "first", order: ":desc:2") as IEnumerable<dynamic>).ToList();
@@ -838,14 +479,14 @@ namespace DynamORM.Tests.Select
} }
/// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("login")) len from "users";</code>.</summary>
[TestMethod] [Test]
public virtual void TestGenericAggregateInAggregate() public virtual void TestGenericAggregateInAggregate()
{ {
Assert.AreEqual(12.77, GetTestTable().Scalar<T>(columns: @"length(""login""):len:avg")); 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> /// <summary>This time also something fancy... aggregate in aggregate <code>select AVG(LENGTH("email")) len from "users";</code>.</summary>
[TestMethod] [Test]
public virtual void TestGenericAggregateInAggregateMark2() public virtual void TestGenericAggregateInAggregateMark2()
{ {
Assert.AreEqual(27.7, GetTestTable().Avg<T>(columns: @"length(""email""):len")); Assert.AreEqual(27.7, GetTestTable().Avg<T>(columns: @"length(""email""):len"));
@@ -866,7 +507,7 @@ namespace DynamORM.Tests.Select
} }
/// <summary>Test generic <c>Single</c> multi.</summary> /// <summary>Test generic <c>Single</c> multi.</summary>
[TestMethod] [Test]
public virtual void TestGenericSingleObject() public virtual void TestGenericSingleObject()
{ {
var exp = new { id = 19, first = "Ori", last = "Ellis" }; var exp = new { id = 19, first = "Ori", last = "Ellis" };
@@ -882,77 +523,77 @@ namespace DynamORM.Tests.Select
#region Where generic #region Where generic
/// <summary>Test generic where expression equal.</summary> /// <summary>Test generic where expression equal.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereEq() public virtual void TestGenericWhereEq()
{ {
Assert.AreEqual("hoyt.tran", GetTestTable().Single<T>(where: new DynamicColumn("id").Eq(100)).login); Assert.AreEqual("hoyt.tran", GetTestTable().Single<T>(where: new DynamicColumn("id").Eq(100)).login);
} }
/// <summary>Test generic where expression not equal.</summary> /// <summary>Test generic where expression not equal.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereNot() public virtual void TestGenericWhereNot()
{ {
Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("id").Not(100))); Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("id").Not(100)));
} }
/// <summary>Test generic where expression like.</summary> /// <summary>Test generic where expression like.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereLike() public virtual void TestGenericWhereLike()
{ {
Assert.AreEqual(100, GetTestTable().Single<T>(where: new DynamicColumn("login").Like("Hoyt.%")).id); Assert.AreEqual(100, GetTestTable().Single<T>(where: new DynamicColumn("login").Like("Hoyt.%")).id);
} }
/// <summary>Test generic where expression not like.</summary> /// <summary>Test generic where expression not like.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereNotLike() public virtual void TestGenericWhereNotLike()
{ {
Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("login").NotLike("Hoyt.%"))); Assert.AreEqual(199, GetTestTable().Count<T>(where: new DynamicColumn("login").NotLike("Hoyt.%")));
} }
/// <summary>Test generic where expression greater.</summary> /// <summary>Test generic where expression greater.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereGt() public virtual void TestGenericWhereGt()
{ {
Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").Greater(100))); Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").Greater(100)));
} }
/// <summary>Test generic where expression greater or equal.</summary> /// <summary>Test generic where expression greater or equal.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereGte() public virtual void TestGenericWhereGte()
{ {
Assert.AreEqual(101, GetTestTable().Count<T>(where: new DynamicColumn("id").GreaterOrEqual(100))); Assert.AreEqual(101, GetTestTable().Count<T>(where: new DynamicColumn("id").GreaterOrEqual(100)));
} }
/// <summary>Test generic where expression less.</summary> /// <summary>Test generic where expression less.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereLt() public virtual void TestGenericWhereLt()
{ {
Assert.AreEqual(99, GetTestTable().Count<T>(where: new DynamicColumn("id").Less(100))); Assert.AreEqual(99, GetTestTable().Count<T>(where: new DynamicColumn("id").Less(100)));
} }
/// <summary>Test generic where expression less or equal.</summary> /// <summary>Test generic where expression less or equal.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereLte() public virtual void TestGenericWhereLte()
{ {
Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").LessOrEqual(100))); Assert.AreEqual(100, GetTestTable().Count<T>(where: new DynamicColumn("id").LessOrEqual(100)));
} }
/// <summary>Test generic where expression between.</summary> /// <summary>Test generic where expression between.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereBetween() public virtual void TestGenericWhereBetween()
{ {
Assert.AreEqual(26, GetTestTable().Count<T>(where: new DynamicColumn("id").Between(75, 100))); Assert.AreEqual(26, GetTestTable().Count<T>(where: new DynamicColumn("id").Between(75, 100)));
} }
/// <summary>Test generic where expression in parameters.</summary> /// <summary>Test generic where expression in parameters.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereIn1() public virtual void TestGenericWhereIn1()
{ {
Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(75, 99, 100))); Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(75, 99, 100)));
} }
/// <summary>Test generic where expression in array.</summary> /// <summary>Test generic where expression in array.</summary>
[TestMethod] [Test]
public virtual void TestGenericWhereIn2() public virtual void TestGenericWhereIn2()
{ {
Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(new[] { 75, 99, 100 }))); Assert.AreEqual(3, GetTestTable().Count<T>(where: new DynamicColumn("id").In(new[] { 75, 99, 100 })));

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,69 +1,25 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.2.0.8774-RC
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM", "DynamORM\DynamORM.csproj", "{63963ED7-9C78-4672-A4D4-339B6E825503}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM", "DynamORM\DynamORM.csproj", "{63963ED7-9C78-4672-A4D4-339B6E825503}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM.Tests", "DynamORM.Tests\DynamORM.Tests.csproj", "{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamORM.Tests", "DynamORM.Tests\DynamORM.Tests.csproj", "{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AmalgamationTool", "AmalgamationTool\AmalgamationTool.csproj", "{A64D2052-D0CD-488E-BF05-E5952615D926}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tester", "Tester\Tester.csproj", "{F747AA57-BEA7-4FB8-B371-546296789AEF}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {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}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Debug|x86.ActiveCfg = Debug|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.ActiveCfg = Release|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 {63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Any CPU.Build.0 = Release|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{63963ED7-9C78-4672-A4D4-339B6E825503}.Release|x86.ActiveCfg = Release|Any CPU
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|Any CPU.ActiveCfg = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|Any CPU.Build.0 = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|Mixed Platforms.Build.0 = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|x86.ActiveCfg = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Debug|x86.Build.0 = Debug|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|Any CPU.ActiveCfg = Release|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|Any CPU.Build.0 = Release|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|Mixed Platforms.ActiveCfg = Release|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|Mixed Platforms.Build.0 = Release|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|x86.ActiveCfg = Release|x86
{A64D2052-D0CD-488E-BF05-E5952615D926}.Release|x86.Build.0 = Release|x86
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Any CPU.ActiveCfg = Debug|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}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Debug|x86.ActiveCfg = Debug|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.ActiveCfg = Release|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 {D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Any CPU.Build.0 = Release|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D5013B4E-8A1B-4DBB-8FB5-E09935F4F764}.Release|x86.ActiveCfg = Release|Any CPU
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Debug|Any CPU.ActiveCfg = Debug|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Debug|Mixed Platforms.Build.0 = Debug|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Debug|x86.ActiveCfg = Debug|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Debug|x86.Build.0 = Debug|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Release|Any CPU.ActiveCfg = Release|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Release|Mixed Platforms.ActiveCfg = Release|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Release|Mixed Platforms.Build.0 = Release|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Release|x86.ActiveCfg = Release|x86
{F747AA57-BEA7-4FB8-B371-546296789AEF}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Tester\Tester.csproj
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,46 +27,40 @@
*/ */
using System.Data; using System.Data;
using DynamORM.Builders.Extensions; using System.Text;
namespace DynamORM.Builders.Implementation namespace DynamORM.Builders
{ {
/// <summary>Base query builder for insert/update/delete statements.</summary> /// <summary>Delete query builder.</summary>
internal abstract class DynamicModifyBuilder : DynamicQueryBuilder public class DynamicDeleteQueryBuilder : DynamicQueryBuilder<DynamicDeleteQueryBuilder>
{ {
/// <summary> /// <summary>Initializes a new instance of the <see cref="DynamicDeleteQueryBuilder"/> class.</summary>
/// Initializes a new instance of the <see cref="DynamicModifyBuilder"/> class. /// <param name="table">Parent dynamic table.</param>
/// </summary> public DynamicDeleteQueryBuilder(DynamicTable table)
/// <param name="db">The database.</param> : base(table)
public DynamicModifyBuilder(DynamicDatabase db)
: base(db)
{ {
VirtualMode = false;
} }
/// <summary> /// <summary>Fill command with query.</summary>
/// Initializes a new instance of the <see cref="DynamicModifyBuilder" /> class. /// <param name="command">Command to fill.</param>
/// </summary> /// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
/// <param name="db">The database.</param> public override IDbCommand FillCommand(IDbCommand command)
/// <param name="tableName">Name of the table.</param>
public DynamicModifyBuilder(DynamicDatabase db, string tableName)
: this(db)
{ {
VirtualMode = false; StringBuilder sb = new StringBuilder();
this.Table(tableName);
sb.Append("DELETE FROM ");
DynamicTable.Database.DecorateName(sb, TableName);
FillWhere(command, sb);
return command.SetCommand(sb.ToString());
} }
/// <summary>Execute this builder.</summary> /// <summary>Execute this builder.</summary>
/// <returns>Result of an execution..</returns> /// <returns>Number of affected rows.</returns>
public virtual int Execute() public override dynamic Execute()
{ {
using (IDbConnection con = Database.Open()) return DynamicTable.Execute(this);
using (IDbCommand cmd = con.CreateCommand())
{
return cmd
.SetCommand(this)
.ExecuteNonQuery();
}
} }
} }
} }

View 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 selected.</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})", db.DecorateName(TableName), builderColumns, builderValues);
}
/// <summary>Execute this builder.</summary>
/// <returns>Number of affected rows.</returns>
public override dynamic Execute()
{
return DynamicTable.Execute(this);
}
}
}

View File

@@ -0,0 +1,404 @@
/*
* 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 or sets a value indicating whether set parameters for null values.</summary>
public bool VirtualMode { get; 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;
VirtualMode = false;
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(Y));
}
/// <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 || !col.Value.IsKey)
continue;
/*throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", condition.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.ToLower());
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 || v.Value == DBNull.Value) && !VirtualMode && !v.VirtualColumn)
{
#region Null operators
if (v.Operator == DynamicColumn.CompareOperator.Not || v.Operator == DynamicColumn.CompareOperator.Eq)
sb.AppendFormat(" {0} {1}{2} IS{3} NULL{4}",
first ? "WHERE" : v.Or ? "OR" : "AND",
v.BeginBlock ? "(" : string.Empty,
column,
v.Operator == DynamicColumn.CompareOperator.Not ? " NOT" : string.Empty,
v.EndBlock ? ")" : string.Empty);
else
throw new InvalidOperationException("NULL can only be compared by IS or IS NOT operator.");
#endregion Null operators
}
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} {3} ",
first ? "WHERE" : v.Or ? "OR" : "AND",
v.BeginBlock ? "(" : string.Empty,
column,
ToOperator(v.Operator));
db.GetParameterName(sb, pos);
if (v.EndBlock)
sb.Append(")");
command.AddParameter(this, v);
#endregion Standard operators
}
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}{2} BETWEEN ",
first ? "WHERE" : v.Or ? "OR" : "AND",
v.BeginBlock ? "(" : string.Empty,
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);
if (v.EndBlock)
sb.Append(")");
// Reset value
v.Value = vals;
}
else
throw new InvalidOperationException("BETWEEN must have two values.");
#endregion Between operator
}
else if (v.Operator == DynamicColumn.CompareOperator.In)
{
#region In operator
sb.AppendFormat(" {0} {1}{2} IN(",
first ? "WHERE" : v.Or ? "OR" : "AND",
v.BeginBlock ? "(" : string.Empty,
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(")");
if (v.EndBlock)
sb.Append(")");
#endregion In operator
}
else
throw new Exception("BAZINGA. You have reached unreachable code.");
#endregion In or Between operator
}
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();
}
}

View 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 selected.</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);
}
}
}

View 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 selected.</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);
}
}
}

View File

@@ -1,245 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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 DynamORM.Builders.Implementation;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Extensions
{
internal static class DynamicHavingQueryExtensions
{
#region Where
internal static T InternalHaving<T>(this T builder, Func<dynamic, object> func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
return builder.InternalHaving(false, false, func);
}
internal static T InternalHaving<T>(this T builder, bool addBeginBrace, bool addEndBrace, Func<dynamic, object> func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
if (func == null) throw new ArgumentNullException("Array of functions cannot be null.");
using (DynamicParser parser = DynamicParser.Parse(func))
{
string condition = null;
bool and = true;
object result = parser.Result;
if (result is string)
{
condition = (string)result;
if (condition.ToUpper().IndexOf("OR") == 0)
{
and = false;
condition = condition.Substring(3);
}
else if (condition.ToUpper().IndexOf("AND") == 0)
condition = condition.Substring(4);
}
else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType)
return builder.InternalHaving(result);
else
{
// Intercepting the 'x => x.And()' and 'x => x.Or()' virtual methods...
if (result is DynamicParser.Node.Method && ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument)
{
DynamicParser.Node.Method node = (DynamicParser.Node.Method)result;
string name = node.Name.ToUpper();
if (name == "AND" || name == "OR")
{
object[] args = ((DynamicParser.Node.Method)node).Arguments;
if (args == null) throw new ArgumentNullException("arg", string.Format("{0} is not a parameterless method.", name));
if (args.Length != 1) throw new ArgumentException(string.Format("{0} requires one and only one parameter: {1}.", name, args.Sketch()));
and = name == "AND" ? true : false;
result = args[0];
}
}
// Just parsing the contents now...
condition = builder.Parse(result, pars: builder.Parameters).Validated("Where condition");
}
if (addBeginBrace) builder.HavingOpenBracketsCount++;
if (addEndBrace) builder.HavingOpenBracketsCount--;
if (builder.HavingCondition == null)
builder.HavingCondition = string.Format("{0}{1}{2}",
addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty);
else
builder.HavingCondition = string.Format("{0} {1} {2}{3}{4}", builder.HavingCondition, and ? "AND" : "OR",
addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty);
}
return builder;
}
internal static T InternalHaving<T>(this T builder, DynamicColumn column) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
bool virt = builder.VirtualMode;
if (column.VirtualColumn.HasValue)
builder.VirtualMode = column.VirtualColumn.Value;
Action<IParameter> modParam = (p) =>
{
if (column.Schema.HasValue)
p.Schema = column.Schema;
if (!p.Schema.HasValue)
p.Schema = column.Schema ?? builder.GetColumnFromSchema(column.ColumnName);
};
builder.CreateTemporaryParameterAction(modParam);
// It's kind of uglu, but... well it works.
if (column.Or)
switch (column.Operator)
{
default:
case DynamicColumn.CompareOperator.Eq: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break;
case DynamicColumn.CompareOperator.Not: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break;
case DynamicColumn.CompareOperator.Like: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break;
case DynamicColumn.CompareOperator.NotLike: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); break;
case DynamicColumn.CompareOperator.In: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break;
case DynamicColumn.CompareOperator.Lt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break;
case DynamicColumn.CompareOperator.Lte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break;
case DynamicColumn.CompareOperator.Gt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break;
case DynamicColumn.CompareOperator.Gte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break;
case DynamicColumn.CompareOperator.Between: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); break;
}
else
switch (column.Operator)
{
default:
case DynamicColumn.CompareOperator.Eq: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break;
case DynamicColumn.CompareOperator.Not: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break;
case DynamicColumn.CompareOperator.Like: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break;
case DynamicColumn.CompareOperator.NotLike: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break;
case DynamicColumn.CompareOperator.In: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break;
case DynamicColumn.CompareOperator.Lt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break;
case DynamicColumn.CompareOperator.Lte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break;
case DynamicColumn.CompareOperator.Gt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break;
case DynamicColumn.CompareOperator.Gte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break;
case DynamicColumn.CompareOperator.Between: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break;
}
builder.OnCreateTemporaryParameter.Remove(modParam);
builder.VirtualMode = virt;
return builder;
}
internal static T InternalHaving<T>(this T builder, string column, DynamicColumn.CompareOperator op, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
if (value is DynamicColumn)
{
DynamicColumn v = (DynamicColumn)value;
if (string.IsNullOrEmpty(v.ColumnName))
v.ColumnName = column;
return builder.InternalHaving(v);
}
else if (value is IEnumerable<DynamicColumn>)
{
foreach (DynamicColumn v in (IEnumerable<DynamicColumn>)value)
builder.InternalHaving(v);
return builder;
}
return builder.InternalHaving(new DynamicColumn
{
ColumnName = column,
Operator = op,
Value = value
});
}
internal static T InternalHaving<T>(this T builder, string column, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
return builder.InternalHaving(column, DynamicColumn.CompareOperator.Eq, value);
}
internal static T InternalHaving<T>(this T builder, object conditions, bool schema = false) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving
{
if (conditions is DynamicColumn)
return builder.InternalHaving((DynamicColumn)conditions);
else if (conditions is IEnumerable<DynamicColumn>)
{
foreach (DynamicColumn v in (IEnumerable<DynamicColumn>)conditions)
builder.InternalHaving(v);
return builder;
}
IDictionary<string, object> dict = conditions.ToDictionary();
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType());
string table = dict.TryGetValue("_table").NullOr(x => x.ToString(), string.Empty);
foreach (KeyValuePair<string, object> condition in dict)
{
if (mapper.Ignored.Contains(condition.Key) || condition.Key == "_table")
continue;
string colName = mapper != null ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key : condition.Key;
DynamicSchemaColumn? col = null;
// This should be used on typed queries or update/delete steatements, which usualy operate on a single table.
if (schema)
{
col = builder.GetColumnFromSchema(colName, mapper, table);
if ((!col.HasValue || !col.Value.IsKey) &&
(mapper == null || mapper.ColumnsMap.TryGetValue(colName).NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true)))
continue;
colName = col.HasValue ? col.Value.Name : colName;
}
if (!string.IsNullOrEmpty(table))
builder.InternalHaving(x => x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value);
else
builder.InternalHaving(x => x(builder.FixObjectName(colName)) == condition.Value);
}
return builder;
}
#endregion Where
}
}

View File

@@ -1,162 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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.Builders.Implementation;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Extensions
{
internal static class DynamicModifyBuilderExtensions
{
internal static T Table<T>(this T builder, Func<dynamic, object> func) where T : DynamicModifyBuilder
{
if (func == null)
throw new ArgumentNullException("Function cannot be null.");
using (DynamicParser parser = DynamicParser.Parse(func))
{
object result = parser.Result;
// If the expression result is string.
if (result is string)
return builder.Table((string)result);
else if (result is Type)
return builder.Table((Type)result);
else if (result is DynamicParser.Node)
{
// Or if it resolves to a dynamic node
DynamicParser.Node node = (DynamicParser.Node)result;
string owner = null;
string main = null;
while (true)
{
// Deny support for the AS() virtual method...
if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS")
throw new ArgumentException(string.Format("Alias is not supported on modification builders. (Parsing: {0})", result));
// Support for table specifications...
if (node is DynamicParser.Node.GetMember)
{
if (owner != null)
throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result));
if (main != null)
owner = ((DynamicParser.Node.GetMember)node).Name;
else
main = ((DynamicParser.Node.GetMember)node).Name;
node = node.Host;
continue;
}
// Support for generic sources...
if (node is DynamicParser.Node.Invoke)
{
if (owner == null && main == null)
{
DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node;
if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type)
return builder.Table((Type)invoke.Arguments[0]);
else if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is String)
return builder.Table((string)invoke.Arguments[0]);
else
throw new ArgumentException(string.Format("Invalid argument count or type when parsing '{2}'. Invoke supports only one argument of type Type or String", owner, main, result));
}
else if (owner != null)
throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result));
else if (main != null)
throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", main, result));
}
if (!string.IsNullOrEmpty(main))
return builder.Table(string.Format("{0}{1}",
string.IsNullOrEmpty(owner) ? string.Empty : string.Format("{0}.", owner),
main));
}
}
throw new ArgumentException(string.Format("Unable to set table parsing '{0}'", result));
}
}
internal static T Table<T>(this T builder, string tableName, Dictionary<string, DynamicSchemaColumn> schema = null) where T : DynamicModifyBuilder
{
Tuple<string, string> tuple = tableName.Validated("Table Name").SplitSomethingAndAlias();
if (!string.IsNullOrEmpty(tuple.Item2))
throw new ArgumentException(string.Format("Can not use aliases in INSERT steatement. ({0})", tableName), "tableName");
string[] parts = tuple.Item1.Split('.');
if (parts.Length > 2)
throw new ArgumentException(string.Format("Table name can consist only from name or owner and name. ({0})", tableName), "tableName");
builder.Tables.Clear();
builder.Tables.Add(new DynamicQueryBuilder.TableInfo(builder.Database,
builder.Database.StripName(parts.Last()).Validated("Table"), null,
parts.Length == 2 ? builder.Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null));
if (schema != null)
(builder.Tables[0] as DynamicQueryBuilder.TableInfo).Schema = schema;
return builder;
}
internal static T Table<T>(this T builder, Type type) where T : DynamicQueryBuilder
{
if (type.IsAnonymous())
throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}).", type.FullName));
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type);
if (mapper == null)
throw new InvalidOperationException("Cant assign unmapable type as a table.");
if (builder is DynamicModifyBuilder)
{
builder.Tables.Clear();
builder.Tables.Add(new DynamicQueryBuilder.TableInfo(builder.Database, type));
}
else if (builder is DynamicSelectQueryBuilder)
(builder as DynamicSelectQueryBuilder).From(x => x(type));
return builder;
}
}
}

View File

@@ -1,245 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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 DynamORM.Builders.Implementation;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Extensions
{
internal static class DynamicWhereQueryExtensions
{
#region Where
internal static T InternalWhere<T>(this T builder, Func<dynamic, object> func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
return builder.InternalWhere(false, false, func);
}
internal static T InternalWhere<T>(this T builder, bool addBeginBrace, bool addEndBrace, Func<dynamic, object> func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
if (func == null) throw new ArgumentNullException("Array of functions cannot be null.");
using (DynamicParser parser = DynamicParser.Parse(func))
{
string condition = null;
bool and = true;
object result = parser.Result;
if (result is string)
{
condition = (string)result;
if (condition.ToUpper().IndexOf("OR") == 0)
{
and = false;
condition = condition.Substring(3);
}
else if (condition.ToUpper().IndexOf("AND") == 0)
condition = condition.Substring(4);
}
else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType)
return builder.InternalWhere(result);
else
{
// Intercepting the 'x => x.And()' and 'x => x.Or()' virtual methods...
if (result is DynamicParser.Node.Method && ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument)
{
DynamicParser.Node.Method node = (DynamicParser.Node.Method)result;
string name = node.Name.ToUpper();
if (name == "AND" || name == "OR")
{
object[] args = ((DynamicParser.Node.Method)node).Arguments;
if (args == null) throw new ArgumentNullException("arg", string.Format("{0} is not a parameterless method.", name));
if (args.Length != 1) throw new ArgumentException(string.Format("{0} requires one and only one parameter: {1}.", name, args.Sketch()));
and = name == "AND" ? true : false;
result = args[0];
}
}
// Just parsing the contents now...
condition = builder.Parse(result, pars: builder.Parameters).Validated("Where condition");
}
if (addBeginBrace) builder.WhereOpenBracketsCount++;
if (addEndBrace) builder.WhereOpenBracketsCount--;
if (builder.WhereCondition == null)
builder.WhereCondition = string.Format("{0}{1}{2}",
addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty);
else
builder.WhereCondition = string.Format("{0} {1} {2}{3}{4}", builder.WhereCondition, and ? "AND" : "OR",
addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty);
}
return builder;
}
internal static T InternalWhere<T>(this T builder, DynamicColumn column) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
bool virt = builder.VirtualMode;
if (column.VirtualColumn.HasValue)
builder.VirtualMode = column.VirtualColumn.Value;
Action<IParameter> modParam = (p) =>
{
if (column.Schema.HasValue)
p.Schema = column.Schema;
if (!p.Schema.HasValue)
p.Schema = column.Schema ?? builder.GetColumnFromSchema(column.ColumnName);
};
builder.CreateTemporaryParameterAction(modParam);
// It's kind of uglu, but... well it works.
if (column.Or)
switch (column.Operator)
{
default:
case DynamicColumn.CompareOperator.Eq: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break;
case DynamicColumn.CompareOperator.Not: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break;
case DynamicColumn.CompareOperator.Like: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break;
case DynamicColumn.CompareOperator.NotLike: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); break;
case DynamicColumn.CompareOperator.In: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break;
case DynamicColumn.CompareOperator.Lt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break;
case DynamicColumn.CompareOperator.Lte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break;
case DynamicColumn.CompareOperator.Gt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break;
case DynamicColumn.CompareOperator.Gte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break;
case DynamicColumn.CompareOperator.Between: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); break;
}
else
switch (column.Operator)
{
default:
case DynamicColumn.CompareOperator.Eq: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break;
case DynamicColumn.CompareOperator.Not: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break;
case DynamicColumn.CompareOperator.Like: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break;
case DynamicColumn.CompareOperator.NotLike: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break;
case DynamicColumn.CompareOperator.In: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break;
case DynamicColumn.CompareOperator.Lt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break;
case DynamicColumn.CompareOperator.Lte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break;
case DynamicColumn.CompareOperator.Gt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break;
case DynamicColumn.CompareOperator.Gte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break;
case DynamicColumn.CompareOperator.Between: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break;
}
builder.OnCreateTemporaryParameter.Remove(modParam);
builder.VirtualMode = virt;
return builder;
}
internal static T InternalWhere<T>(this T builder, string column, DynamicColumn.CompareOperator op, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
if (value is DynamicColumn)
{
DynamicColumn v = (DynamicColumn)value;
if (string.IsNullOrEmpty(v.ColumnName))
v.ColumnName = column;
return builder.InternalWhere(v);
}
else if (value is IEnumerable<DynamicColumn>)
{
foreach (DynamicColumn v in (IEnumerable<DynamicColumn>)value)
builder.InternalWhere(v);
return builder;
}
return builder.InternalWhere(new DynamicColumn
{
ColumnName = column,
Operator = op,
Value = value
});
}
internal static T InternalWhere<T>(this T builder, string column, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
return builder.InternalWhere(column, DynamicColumn.CompareOperator.Eq, value);
}
internal static T InternalWhere<T>(this T builder, object conditions, bool schema = false) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
if (conditions is DynamicColumn)
return builder.InternalWhere((DynamicColumn)conditions);
else if (conditions is IEnumerable<DynamicColumn>)
{
foreach (DynamicColumn v in (IEnumerable<DynamicColumn>)conditions)
builder.InternalWhere(v);
return builder;
}
IDictionary<string, object> dict = conditions.ToDictionary();
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType());
string table = dict.TryGetValue("_table").NullOr(x => x.ToString(), string.Empty);
foreach (KeyValuePair<string, object> condition in dict)
{
if (mapper.Ignored.Contains(condition.Key) || condition.Key == "_table")
continue;
string colName = mapper != null ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key : condition.Key;
DynamicSchemaColumn? col = null;
// This should be used on typed queries or update/delete steatements, which usualy operate on a single table.
if (schema)
{
col = builder.GetColumnFromSchema(colName, mapper, table);
if ((!col.HasValue || !col.Value.IsKey) &&
(mapper == null || mapper.ColumnsMap.TryGetValue(colName).NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true)))
continue;
colName = col.HasValue ? col.Value.Name : colName;
}
if (!string.IsNullOrEmpty(table))
builder.InternalWhere(x => x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value);
else
builder.InternalWhere(x => x(builder.FixObjectName(colName)) == condition.Value);
}
return builder;
}
#endregion Where
}
}

View File

@@ -1,78 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Builders
{
/// <summary>Dynamic delete query builder interface.</summary>
/// <remarks>This interface it publicly available. Implementation should be hidden.</remarks>
public interface IDynamicDeleteQueryBuilder : IDynamicQueryBuilder
{
/// <summary>Execute this builder.</summary>
/// <returns>Result of an execution..</returns>
int Execute();
/// <summary>
/// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Where() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Where( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicDeleteQueryBuilder Where(Func<dynamic, object> func);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
IDynamicDeleteQueryBuilder Where(DynamicColumn column);
/// <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>
IDynamicDeleteQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
IDynamicDeleteQueryBuilder Where(string column, object 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>
IDynamicDeleteQueryBuilder Where(object conditions, bool schema = false);
}
}

View File

@@ -1,63 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Builders
{
/// <summary>Dynamic insert query builder interface.</summary>
/// <remarks>This interface it publicly available. Implementation should be hidden.</remarks>
public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder
{
/// <summary>Execute this builder.</summary>
/// <returns>Result of an execution..</returns>
int Execute();
/// <summary>
/// Specifies the columns to insert using the dynamic lambda expressions given. Each expression correspond to one
/// column, and can:
/// <para>- Resolve to a string, in this case a '=' must appear in the string.</para>
/// <para>- Resolve to a expression with the form: 'x => x.Column = Value'.</para>
/// </summary>
/// <param name="fn">The specifications.</param>
/// <param name="func">The specifications.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicInsertQueryBuilder Values(Func<dynamic, object> fn, params Func<dynamic, object>[] func);
/// <summary>Add insert fields.</summary>
/// <param name="column">Insert column.</param>
/// <param name="value">Insert value.</param>
/// <returns>Builder instance.</returns>
IDynamicInsertQueryBuilder Insert(string column, object value);
/// <summary>Add insert fields.</summary>
/// <param name="o">Set insert value as properties and values of an object.</param>
/// <returns>Builder instance.</returns>
IDynamicInsertQueryBuilder Insert(object o);
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,28 +26,19 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM.Builders namespace DynamORM.Builders
{ {
/// <summary>Dynamic query builder base interface.</summary> /// <summary>Base query builder interface.</summary>
/// <remarks>This interface it publicly available. Implementation should be hidden.</remarks> public interface IDynamicQueryBuilder
public interface IDynamicQueryBuilder : IExtendedDisposable
{ {
/// <summary>Gets <see cref="DynamicDatabase"/> instance.</summary> /// <summary>Gets <see cref="DynamicTable"/> instance.</summary>
DynamicDatabase Database { get; } DynamicTable DynamicTable { get; }
/// <summary>Gets tables information.</summary> /// <summary>Gets table schema.</summary>
IList<ITableInfo> Tables { get; } Dictionary<string, DynamicSchemaColumn> Schema { get; }
/// <summary>Gets the tables used in this builder.</summary>
IDictionary<string, IParameter> Parameters { get; }
/// <summary>Gets or sets a value indicating whether add virtual parameters.</summary>
bool VirtualMode { get; set; }
/// <summary>Gets a value indicating whether database supports standard schema.</summary> /// <summary>Gets a value indicating whether database supports standard schema.</summary>
bool SupportSchema { get; } bool SupportSchema { get; }
@@ -57,19 +48,8 @@ namespace DynamORM.Builders
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns> /// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
IDbCommand FillCommand(IDbCommand command); IDbCommand FillCommand(IDbCommand command);
/// <summary> /// <summary>Execute this builder.</summary>
/// Generates the text this command will execute against the underlying database. /// <returns>Result of an execution..</returns>
/// </summary> dynamic Execute();
/// <returns>The text to execute against the underlying database.</returns>
/// <remarks>This method must be override by derived classes.</remarks>
string CommandText();
/// <summary>Gets or sets the on create temporary parameter actions.</summary>
/// <remarks>This is exposed to allow setting schema of column.</remarks>
List<Action<IParameter>> OnCreateTemporaryParameter { get; set; }
/// <summary>Gets or sets the on create real parameter actions.</summary>
/// <remarks>This is exposed to allow modification of parameter.</remarks>
List<Action<IParameter, IDbDataParameter>> OnCreateParameter { get; set; }
} }
} }

View File

@@ -1,288 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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;
namespace DynamORM.Builders
{
/// <summary>Dynamic select query builder interface.</summary>
/// <remarks>This interface it publicly available. Implementation should be hidden.</remarks>
public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable<object>
{
/// <summary>Execute this builder.</summary>
/// <returns>Enumerator of objects expanded from query.</returns>
IEnumerable<dynamic> Execute();
/// <summary>Execute this builder and map to given type.</summary>
/// <typeparam name="T">Type of object to map on.</typeparam>
/// <returns>Enumerator of objects expanded from query.</returns>
IEnumerable<T> Execute<T>() where T : class;
/// <summary>Execute this builder as a data reader.</summary>
/// <param name="reader">Action containing reader.</param>
void ExecuteDataReader(Action<IDataReader> reader);
/// <summary>Returns a single result.</summary>
/// <returns>Result of a query.</returns>
object Scalar();
#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE
/// <summary>Returns a single result.</summary>
/// <typeparam name="T">Type to parse to.</typeparam>
/// <param name="defaultValue">Default value.</param>
/// <returns>Result of a query.</returns>
T ScalarAs<T>(T defaultValue = default(T));
#endif
#region From/Join
/// <summary>
/// Adds to the 'From' clause the contents obtained by parsing the dynamic lambda expressions given. The supported
/// formats are:
/// <para>- Resolve to a string: 'x => "Table AS Alias', where the alias part is optional.</para>
/// <para>- Resolve to an expression: 'x => x.Table.As( x.Alias )', where the alias part is optional.</para>
/// <para>- Generic expression: 'x => x( expression ).As( x.Alias )', where the alias part is mandatory. In this
/// case the alias is not annotated.</para>
/// </summary>
/// <param name="fn">The specification.</param>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder From(Func<dynamic, object> fn, params Func<dynamic, object>[] func);
/// <summary>
/// Adds to the 'Join' clause the contents obtained by parsing the dynamic lambda expressions given. The supported
/// formats are:
/// <para>- Resolve to a string: 'x => "Table AS Alias ON Condition', where the alias part is optional.</para>
/// <para>- Resolve to an expression: 'x => x.Table.As( x.Alias ).On( condition )', where the alias part is optional.</para>
/// <para>- Generic expression: 'x => x( expression ).As( x.Alias ).On( condition )', where the alias part is mandatory.
/// In this case the alias is not annotated.</para>
/// The expression might be prepended by a method that, in this case, is used to specify the specific join type you
/// want to perform, as in: 'x => x.Left()...". Two considerations apply:
/// <para>- If a 'false' argument is used when no 'Join' part appears in its name, then no 'Join' suffix is added
/// with a space in between.</para>
/// <para>- If a 'false' argument is used when a 'Join' part does appear, then no split is performed to separate the
/// 'Join' part.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder Join(params Func<dynamic, object>[] func);
#endregion From/Join
#region Where
/// <summary>
/// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Where() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Where( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder Where(Func<dynamic, object> func);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Where(DynamicColumn column);
/// <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>
IDynamicSelectQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Where(string column, object 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>
IDynamicSelectQueryBuilder Where(object conditions, bool schema = false);
#endregion Where
#region Select
/// <summary>
/// Adds to the 'Select' clause the contents obtained by parsing the dynamic lambda expressions given. The supported
/// formats are:
/// <para>- Resolve to a string: 'x => "Table.Column AS Alias', where the alias part is optional.</para>
/// <para>- Resolve to an expression: 'x => x.Table.Column.As( x.Alias )', where the alias part is optional.</para>
/// <para>- Select all columns from a table: 'x => x.Table.All()'.</para>
/// <para>- Generic expression: 'x => x( expression ).As( x.Alias )', where the alias part is mandatory. In this case
/// the alias is not annotated.</para>
/// </summary>
/// <param name="fn">The specification.</param>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder Select(Func<dynamic, object> fn, params Func<dynamic, object>[] func);
/// <summary>Add select columns.</summary>
/// <param name="columns">Columns to add to object.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder SelectColumn(params DynamicColumn[] columns);
/// <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>
IDynamicSelectQueryBuilder SelectColumn(params string[] columns);
#endregion Select
#region GroupBy
/// <summary>
/// Adds to the 'Group By' clause the contents obtained from from parsing the dynamic lambda expression given.
/// </summary>
/// <param name="fn">The specification.</param>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder GroupBy(Func<dynamic, object> fn, params Func<dynamic, object>[] func);
/// <summary>Add select columns.</summary>
/// <param name="columns">Columns to group by.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder GroupByColumn(params DynamicColumn[] columns);
/// <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>
IDynamicSelectQueryBuilder GroupByColumn(params string[] columns);
#endregion GroupBy
#region Having
/// <summary>
/// Adds to the 'Having' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, Having the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Having() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Having( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder Having(Func<dynamic, object> func);
/// <summary>Add Having condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Having(DynamicColumn column);
/// <summary>Add Having condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="op">Condition operator.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Having(string column, DynamicColumn.CompareOperator op, object value);
/// <summary>Add Having condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Having(string column, object value);
/// <summary>Add Having 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>
IDynamicSelectQueryBuilder Having(object conditions, bool schema = false);
#endregion Having
#region OrderBy
/// <summary>
/// Adds to the 'Order By' clause the contents obtained from from parsing the dynamic lambda expression given. It
/// accepts a multipart column specification followed by an optional <code>Ascending()</code> or <code>Descending()</code> virtual methods
/// to specify the direction. If no virtual method is used, the default is ascending order. You can also use the
/// shorter versions <code>Asc()</code> and <code>Desc()</code>.
/// </summary>
/// <param name="fn">The specification.</param>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder OrderBy(Func<dynamic, object> fn, params Func<dynamic, object>[] func);
/// <summary>Add select columns.</summary>
/// <param name="columns">Columns to order by.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder OrderByColumn(params DynamicColumn[] columns);
/// <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>
IDynamicSelectQueryBuilder OrderByColumn(params string[] columns);
#endregion OrderBy
#region Top/Limit/Offset/Distinct
/// <summary>Set top if database support it.</summary>
/// <param name="top">How many objects select.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Top(int? top);
/// <summary>Set top if database support it.</summary>
/// <param name="limit">How many objects select.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Limit(int? limit);
/// <summary>Set top if database support it.</summary>
/// <param name="offset">How many objects skip selecting.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Offset(int? offset);
/// <summary>Set distinct mode.</summary>
/// <param name="distinct">Distinct mode.</param>
/// <returns>Builder instance.</returns>
IDynamicSelectQueryBuilder Distinct(bool distinct = true);
#endregion Top/Limit/Offset/Distinct
}
}

View File

@@ -1,122 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Builders
{
/// <summary>Dynamic update query builder interface.</summary>
/// <remarks>This interface it publicly available. Implementation should be hidden.</remarks>
public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder
{
/// <summary>Execute this builder.</summary>
/// <returns>Result of an execution..</returns>
int Execute();
#region Update
/// <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>
IDynamicUpdateQueryBuilder Update(string column, object value);
/// <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>
IDynamicUpdateQueryBuilder Update(object conditions);
#endregion Update
#region Values
/// <summary>
/// Specifies the columns to update using the dynamic lambda expressions given. Each expression correspond to one
/// column, and can:
/// <para>- Resolve to a string, in this case a '=' must appear in the string.</para>
/// <para>- Resolve to a expression with the form: 'x => x.Column = Value'.</para>
/// </summary>
/// <param name="func">The specifications.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicUpdateQueryBuilder Set(params Func<dynamic, object>[] func);
/// <summary>Add insert fields.</summary>
/// <param name="column">Insert column.</param>
/// <param name="value">Insert value.</param>
/// <returns>Builder instance.</returns>
IDynamicUpdateQueryBuilder Values(string column, object value);
/// <summary>Add insert fields.</summary>
/// <param name="o">Set insert value as properties and values of an object.</param>
/// <returns>Builder instance.</returns>
IDynamicUpdateQueryBuilder Values(object o);
#endregion Values
#region Where
/// <summary>
/// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Where() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Where( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicUpdateQueryBuilder Where(Func<dynamic, object> func);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
IDynamicUpdateQueryBuilder Where(DynamicColumn column);
/// <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>
IDynamicUpdateQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value);
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
IDynamicUpdateQueryBuilder Where(string column, object 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>
IDynamicUpdateQueryBuilder Where(object conditions, bool schema = false);
#endregion Where
}
}

View File

@@ -1,55 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Helpers;
namespace DynamORM.Builders
{
/// <summary>Interface describing parameter info.</summary>
public interface IParameter : IExtendedDisposable
{
/// <summary>Gets the parameter position in command.</summary>
/// <remarks>Available after filling the command.</remarks>
int Ordinal { get; }
/// <summary>Gets the parameter temporary name.</summary>
string Name { get; }
/// <summary>Gets or sets the parameter value.</summary>
object Value { get; set; }
/// <summary>Gets or sets a value indicating whether name of temporary parameter is well known.</summary>
bool WellKnown { get; set; }
/// <summary>Gets or sets a value indicating whether this <see cref="IParameter"/> is virtual.</summary>
bool Virtual { get; set; }
/// <summary>Gets or sets the parameter schema information.</summary>
DynamicSchemaColumn? Schema { get; set; }
}
}

View File

@@ -1,49 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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 DynamORM.Helpers;
namespace DynamORM.Builders
{
/// <summary>Interface describing table information.</summary>
public interface ITableInfo : IExtendedDisposable
{
/// <summary>Gets table owner name.</summary>
string Owner { get; }
/// <summary>Gets table name.</summary>
string Name { get; }
/// <summary>Gets table alias.</summary>
string Alias { get; }
/// <summary>Gets table schema.</summary>
Dictionary<string, DynamicSchemaColumn> Schema { get; }
}
}

View File

@@ -1,129 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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;
using DynamORM.Builders.Extensions;
namespace DynamORM.Builders.Implementation
{
/// <summary>Implementation of dynamic delete query builder.</summary>
internal class DynamicDeleteQueryBuilder : DynamicModifyBuilder, IDynamicDeleteQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
/// <summary>
/// Initializes a new instance of the <see cref="DynamicDeleteQueryBuilder"/> class.
/// </summary>
/// <param name="db">The database.</param>
internal DynamicDeleteQueryBuilder(DynamicDatabase db)
: base(db)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DynamicDeleteQueryBuilder"/> class.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="tableName">Name of the table.</param>
public DynamicDeleteQueryBuilder(DynamicDatabase db, string tableName)
: base(db, tableName)
{
}
/// <summary>Generates the text this command will execute against the underlying database.</summary>
/// <returns>The text to execute against the underlying database.</returns>
/// <remarks>This method must be override by derived classes.</remarks>
public override string CommandText()
{
ITableInfo info = Tables.Single();
return string.Format("DELETE FROM {0}{1}{2}{3}",
string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)),
Database.DecorateName(info.Name),
string.IsNullOrEmpty(WhereCondition) ? string.Empty : " WHERE ",
WhereCondition);
}
#region Where
/// <summary>
/// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Where() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Where( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
public virtual IDynamicDeleteQueryBuilder Where(Func<dynamic, object> func)
{
return this.InternalWhere(func);
}
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
public virtual IDynamicDeleteQueryBuilder Where(DynamicColumn column)
{
return this.InternalWhere(column);
}
/// <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 IDynamicDeleteQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value)
{
return this.InternalWhere(column, op, value);
}
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
public virtual IDynamicDeleteQueryBuilder Where(string column, object value)
{
return this.InternalWhere(column, 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 IDynamicDeleteQueryBuilder Where(object conditions, bool schema = false)
{
return this.InternalWhere(conditions, schema);
}
#endregion Where
}
}

View File

@@ -1,224 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Implementation
{
/// <summary>Implementation of dynamic insert query builder.</summary>
internal class DynamicInsertQueryBuilder : DynamicModifyBuilder, IDynamicInsertQueryBuilder
{
private string _columns;
private string _values;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicInsertQueryBuilder"/> class.
/// </summary>
/// <param name="db">The database.</param>
internal DynamicInsertQueryBuilder(DynamicDatabase db)
: base(db)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DynamicInsertQueryBuilder"/> class.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="tableName">Name of the table.</param>
public DynamicInsertQueryBuilder(DynamicDatabase db, string tableName)
: base(db, tableName)
{
}
/// <summary>Generates the text this command will execute against the underlying database.</summary>
/// <returns>The text to execute against the underlying database.</returns>
/// <remarks>This method must be override by derived classes.</remarks>
public override string CommandText()
{
ITableInfo info = Tables.Single();
return string.Format("INSERT INTO {0}{1} ({2}) VALUES ({3})",
string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)),
Database.DecorateName(info.Name), _columns, _values);
}
#region Insert
/// <summary>
/// Specifies the columns to insert using the dynamic lambda expressions given. Each expression correspond to one
/// column, and can:
/// <para>- Resolve to a string, in this case a '=' must appear in the string.</para>
/// <para>- Resolve to a expression with the form: 'x => x.Column = Value'.</para>
/// </summary>
/// <param name="fn">The specifications.</param>
/// <param name="func">The specifications.</param>
/// <returns>This instance to permit chaining.</returns>
public virtual IDynamicInsertQueryBuilder Values(Func<dynamic, object> fn, params Func<dynamic, object>[] func)
{
if (fn == null)
throw new ArgumentNullException("Array of specifications cannot be null.");
int index = InsertFunc(-1, fn);
if (func != null)
foreach (Func<dynamic, object> f in func)
index = InsertFunc(index, f);
return this;
}
private int InsertFunc(int index, Func<dynamic, object> f)
{
index++;
if (f == null)
throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index));
using (DynamicParser parser = DynamicParser.Parse(f))
{
object result = parser.Result;
if (result == null)
throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index));
string main = null;
string value = null;
string str = null;
// When 'x => x.Table.Column = value' or 'x => x.Column = value'...
if (result is DynamicParser.Node.SetMember)
{
DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result;
DynamicSchemaColumn? col = GetColumnFromSchema(node.Name);
main = Database.DecorateName(node.Name);
value = Parse(node.Value, ref col, pars: Parameters, nulls: true);
_columns = _columns == null ? main : string.Format("{0}, {1}", _columns, main);
_values = _values == null ? value : string.Format("{0}, {1}", _values, value);
return index;
}
else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType)
{
Insert(result);
return index;
}
// Other specifications are considered invalid...
string err = string.Format("Specification '{0}' is invalid.", result);
str = Parse(result);
if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?";
throw new ArgumentException(err);
}
}
/// <summary>Add insert fields.</summary>
/// <param name="column">Insert column.</param>
/// <param name="value">Insert value.</param>
/// <returns>Builder instance.</returns>
public virtual IDynamicInsertQueryBuilder Insert(string column, object value)
{
if (value is DynamicColumn)
{
DynamicColumn v = (DynamicColumn)value;
if (string.IsNullOrEmpty(v.ColumnName))
v.ColumnName = column;
return Insert(v);
}
return Insert(new DynamicColumn
{
ColumnName = column,
Value = value,
});
}
/// <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 IDynamicInsertQueryBuilder Insert(object o)
{
if (o is DynamicColumn)
{
DynamicColumn column = (DynamicColumn)o;
DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName);
string main = FixObjectName(column.ColumnName, onlyColumn: true);
string value = Parse(column.Value, ref col, pars: Parameters, nulls: true);
_columns = _columns == null ? main : string.Format("{0}, {1}", _columns, main);
_values = _values == null ? value : string.Format("{0}, {1}", _values, value);
return this;
}
IDictionary<string, object> dict = o.ToDictionary();
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(o.GetType());
if (mapper != null)
{
foreach (KeyValuePair<string, object> con in dict)
if (!mapper.Ignored.Contains(con.Key))
{
string colName = mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key;
DynamicPropertyInvoker propMap = mapper.ColumnsMap.TryGetValue(colName.ToLower());
if (propMap == null || propMap.Column == null || !propMap.Column.IsNoInsert)
Insert(colName, con.Value);
}
}
else
foreach (KeyValuePair<string, object> con in dict)
Insert(con.Key, con.Value);
return this;
}
#endregion Insert
#region IExtendedDisposable
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public override void Dispose()
{
base.Dispose();
_columns = _values = null;
}
#endregion IExtendedDisposable
}
}

View File

@@ -1,977 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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.Linq.Expressions;
using System.Text;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Implementation
{
/// <summary>Implementation of dynamic query builder base interface.</summary>
internal abstract class DynamicQueryBuilder : IDynamicQueryBuilder
{
/// <summary>Empty interface to allow where query builder implementation use universal approach.</summary>
internal interface IQueryWithWhere
{
/// <summary>Gets or sets the where condition.</summary>
string WhereCondition { get; set; }
/// <summary>Gets or sets the amount of not closed brackets in where statement.</summary>
int WhereOpenBracketsCount { get; set; }
}
/// <summary>Empty interface to allow having query builder implementation use universal approach.</summary>
internal interface IQueryWithHaving
{
/// <summary>Gets or sets the having condition.</summary>
string HavingCondition { get; set; }
/// <summary>Gets or sets the amount of not closed brackets in having statement.</summary>
int HavingOpenBracketsCount { get; set; }
}
private DynamicQueryBuilder _parent = null;
#region TableInfo
/// <summary>Table information.</summary>
internal class TableInfo : ITableInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="TableInfo"/> class.
/// </summary>
internal TableInfo()
{
IsDisposed = false;
}
/// <summary>
/// Initializes a new instance of the <see cref="TableInfo" /> class.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="name">The name of table.</param>
/// <param name="alias">The table alias.</param>
/// <param name="owner">The table owner.</param>
public TableInfo(DynamicDatabase db, string name, string alias = null, string owner = null)
: this()
{
Name = name;
Alias = alias;
Owner = owner;
if (!name.ContainsAny(StringExtensions.InvalidMemberChars))
Schema = db.GetSchema(name, owner: owner);
}
/// <summary>
/// Initializes a new instance of the <see cref="TableInfo" /> class.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="type">The type which can be mapped to database.</param>
/// <param name="alias">The table alias.</param>
/// <param name="owner">The table owner.</param>
public TableInfo(DynamicDatabase db, Type type, string alias = null, string owner = null)
: this()
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type);
Name = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
mapper.Type.Name : mapper.Table.Name;
Owner = (mapper.Table != null) ? mapper.Table.Owner : owner;
Alias = alias;
Schema = db.GetSchema(type);
}
/// <summary>Gets or sets table owner name.</summary>
public string Owner { get; internal set; }
/// <summary>Gets or sets table name.</summary>
public string Name { get; internal set; }
/// <summary>Gets or sets table alias.</summary>
public string Alias { get; internal set; }
/// <summary>Gets or sets table schema.</summary>
public Dictionary<string, DynamicSchemaColumn> Schema { get; internal set; }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public virtual void Dispose()
{
IsDisposed = true;
if (Schema != null)
Schema.Clear();
Owner = Name = Alias = null;
Schema = null;
}
}
/// <summary>Generic based table information.</summary>
/// <typeparam name="T">Type of class that is represented in database.</typeparam>
internal class TableInfo<T> : TableInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="TableInfo{T}" /> class.
/// </summary>
/// <param name="db">The database.</param>
/// <param name="alias">The table alias.</param>
/// <param name="owner">The table owner.</param>
public TableInfo(DynamicDatabase db, string alias = null, string owner = null)
: base(db, typeof(T), alias, owner)
{
}
}
#endregion TableInfo
#region Parameter
/// <summary>Interface describing parameter info.</summary>
internal class Parameter : IParameter
{
/// <summary>Initializes a new instance of the
/// <see cref="Parameter"/> class.</summary>
public Parameter()
{
IsDisposed = false;
}
/// <summary>Gets or sets the parameter position in command.</summary>
/// <remarks>Available after filling the command.</remarks>
public int Ordinal { get; internal set; }
/// <summary>Gets or sets the parameter temporary name.</summary>
public string Name { get; internal set; }
/// <summary>Gets or sets the parameter value.</summary>
public object Value { get; set; }
/// <summary>Gets or sets a value indicating whether name of temporary parameter is well known.</summary>
public bool WellKnown { get; set; }
/// <summary>Gets or sets a value indicating whether this <see cref="Parameter"/> is virtual.</summary>
public bool Virtual { get; set; }
/// <summary>Gets or sets the parameter schema information.</summary>
public DynamicSchemaColumn? Schema { get; set; }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public virtual void Dispose()
{
IsDisposed = true;
Name = null;
Schema = null;
}
}
#endregion Parameter
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="DynamicQueryBuilder"/> class.
/// </summary>
/// <param name="db">The database.</param>
public DynamicQueryBuilder(DynamicDatabase db)
{
IsDisposed = false;
VirtualMode = false;
Tables = new List<ITableInfo>();
Parameters = new Dictionary<string, IParameter>();
OnCreateTemporaryParameter = new List<Action<IParameter>>();
OnCreateParameter = new List<Action<IParameter, IDbDataParameter>>();
WhereCondition = null;
WhereOpenBracketsCount = 0;
Database = db;
if (Database != null)
Database.AddToCache(this);
SupportSchema = (db.Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema;
}
/// <summary>Initializes a new instance of the <see cref="DynamicQueryBuilder"/> class.</summary>
/// <param name="db">The database.</param>
/// <param name="parent">The parent query.</param>
internal DynamicQueryBuilder(DynamicDatabase db, DynamicQueryBuilder parent)
: this(db)
{
_parent = parent;
}
#endregion Constructor
#region IQueryWithWhere
/// <summary>Gets or sets the where condition.</summary>
public string WhereCondition { get; set; }
/// <summary>Gets or sets the amount of not closed brackets in where statement.</summary>
public int WhereOpenBracketsCount { get; set; }
#endregion IQueryWithWhere
#region IDynamicQueryBuilder
/// <summary>Gets <see cref="DynamicDatabase"/> instance.</summary>
public DynamicDatabase Database { get; private set; }
/// <summary>Gets the tables used in this builder.</summary>
public IList<ITableInfo> Tables { get; private set; }
/// <summary>Gets the tables used in this builder.</summary>
public IDictionary<string, IParameter> Parameters { get; private set; }
/// <summary>Gets or sets a value indicating whether add virtual parameters.</summary>
public bool VirtualMode { get; set; }
/// <summary>Gets or sets the on create temporary parameter actions.</summary>
/// <remarks>This is exposed to allow setting schema of column.</remarks>
public List<Action<IParameter>> OnCreateTemporaryParameter { get; set; }
/// <summary>Gets or sets the on create real parameter actions.</summary>
/// <remarks>This is exposed to allow modification of parameter.</remarks>
public List<Action<IParameter, IDbDataParameter>> OnCreateParameter { get; set; }
/// <summary>Gets a value indicating whether database supports standard schema.</summary>
public bool SupportSchema { get; private set; }
/// <summary>
/// Generates the text this command will execute against the underlying database.
/// </summary>
/// <returns>The text to execute against the underlying database.</returns>
/// <remarks>This method must be override by derived classes.</remarks>
public abstract string CommandText();
/// <summary>Fill command with query.</summary>
/// <param name="command">Command to fill.</param>
/// <returns>Filled instance of <see cref="IDbCommand"/>.</returns>
public virtual IDbCommand FillCommand(IDbCommand command)
{
// End not ended where statement
if (this is IQueryWithWhere)
{
while (WhereOpenBracketsCount > 0)
{
WhereCondition += ")";
WhereOpenBracketsCount--;
}
}
// End not ended having statement
if (this is IQueryWithHaving)
{
IQueryWithHaving h = this as IQueryWithHaving;
while (h.HavingOpenBracketsCount > 0)
{
h.HavingCondition += ")";
h.HavingOpenBracketsCount--;
}
}
return command.SetCommand(CommandText()
.FillStringWithVariables(s =>
{
return Parameters.TryGetValue(s).NullOr(p =>
{
IDbDataParameter param = (IDbDataParameter)command
.AddParameter(this, p.Schema, p.Value)
.Parameters[command.Parameters.Count - 1];
(p as Parameter).Ordinal = command.Parameters.Count - 1;
if (OnCreateParameter != null)
OnCreateParameter.ForEach(x => x(p, param));
return param.ParameterName;
}, s);
}));
}
#endregion IDynamicQueryBuilder
#region Parser
/// <summary>Parses the arbitrary object given and translates it into a string with the appropriate
/// syntax for the database this parser is specific to.</summary>
/// <param name="node">The object to parse and translate. It can be any arbitrary object, including null values (if
/// permitted) and dynamic lambda expressions.</param>
/// <param name="pars">If not null, the parameters' list where to store the parameters extracted by the parsing.</param>
/// <param name="rawstr">If true, literal (raw) string are allowed. If false and the node is a literal then, as a
/// security measure, an exception is thrown.</param>
/// <param name="nulls">True to accept null values and translate them into the appropriate syntax accepted by the
/// database. If false and the value is null, then an exception is thrown.</param>
/// <param name="decorate">If set to <c>true</c> decorate element.</param>
/// <param name="isMultiPart">If set parse argument as alias. This is workaround for AS method.</param>
/// <returns>A string containing the result of the parsing, along with the parameters extracted in the
/// <paramref name="pars" /> instance if such is given.</returns>
/// <exception cref="System.ArgumentNullException">Null nodes are not accepted.</exception>
internal virtual string Parse(object node, IDictionary<string, IParameter> pars = null, bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true)
{
DynamicSchemaColumn? c = null;
return Parse(node, ref c, pars, rawstr, nulls, decorate, isMultiPart);
}
/// <summary>Parses the arbitrary object given and translates it into a string with the appropriate
/// syntax for the database this parser is specific to.</summary>
/// <param name="node">The object to parse and translate. It can be any arbitrary object, including null values (if
/// permitted) and dynamic lambda expressions.</param>
/// <param name="columnSchema">This parameter is used to determine type of parameter used in query.</param>
/// <param name="pars">If not null, the parameters' list where to store the parameters extracted by the parsing.</param>
/// <param name="rawstr">If true, literal (raw) string are allowed. If false and the node is a literal then, as a
/// security measure, an exception is thrown.</param>
/// <param name="nulls">True to accept null values and translate them into the appropriate syntax accepted by the
/// database. If false and the value is null, then an exception is thrown.</param>
/// <param name="decorate">If set to <c>true</c> decorate element.</param>
/// <param name="isMultiPart">If set parse argument as alias. This is workaround for AS method.</param>
/// <returns>A string containing the result of the parsing, along with the parameters extracted in the
/// <paramref name="pars" /> instance if such is given.</returns>
/// <exception cref="System.ArgumentNullException">Null nodes are not accepted.</exception>
internal virtual string Parse(object node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null, bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true)
{
// Null nodes are accepted or not depending upon the "nulls" flag...
if (node == null)
{
if (!nulls)
throw new ArgumentNullException("node", "Null nodes are not accepted.");
return Dispatch(node, ref columnSchema, pars, decorate);
}
// Nodes that are strings are parametrized or not depending the "rawstr" flag...
if (node is string)
{
if (rawstr) return (string)node;
else return Dispatch(node, ref columnSchema, pars, decorate);
}
// If node is a delegate, parse it to create the logical tree...
if (node is Delegate)
{
using (DynamicParser p = DynamicParser.Parse((Delegate)node))
{
node = p.Result;
return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string")
}
}
return Dispatch(node, ref columnSchema, pars, decorate, isMultiPart);
}
private string Dispatch(object node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null, bool decorate = true, bool isMultiPart = true)
{
if (node != null)
{
if (node is DynamicQueryBuilder) return ParseCommand((DynamicQueryBuilder)node, pars);
else if (node is DynamicParser.Node.Argument) return ParseArgument((DynamicParser.Node.Argument)node, isMultiPart);
else if (node is DynamicParser.Node.GetMember) return ParseGetMember((DynamicParser.Node.GetMember)node, ref columnSchema, pars, decorate, isMultiPart);
else if (node is DynamicParser.Node.SetMember) return ParseSetMember((DynamicParser.Node.SetMember)node, ref columnSchema, pars, decorate, isMultiPart);
else if (node is DynamicParser.Node.Unary) return ParseUnary((DynamicParser.Node.Unary)node, pars);
else if (node is DynamicParser.Node.Binary) return ParseBinary((DynamicParser.Node.Binary)node, pars);
else if (node is DynamicParser.Node.Method) return ParseMethod((DynamicParser.Node.Method)node, ref columnSchema, pars);
else if (node is DynamicParser.Node.Invoke) return ParseInvoke((DynamicParser.Node.Invoke)node, ref columnSchema, pars);
else if (node is DynamicParser.Node.Convert) return ParseConvert((DynamicParser.Node.Convert)node, pars);
}
// All other cases are considered constant parameters...
return ParseConstant(node, pars, columnSchema);
}
internal virtual string ParseCommand(DynamicQueryBuilder node, IDictionary<string, IParameter> pars = null)
{
// Getting the command's text...
string str = node.CommandText(); // Avoiding spurious "OUTPUT XXX" statements
// If there are parameters to transform, but cannot store them, it is an error
if (node.Parameters.Count != 0 && pars == null)
return string.Format("({0})", str);
// TODO: Make special condiion
////throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters));
// Copy parameters to new comand
foreach (KeyValuePair<string, IParameter> parameter in node.Parameters)
pars.Add(parameter.Key, parameter.Value);
return string.Format("({0})", str);
}
protected virtual string ParseArgument(DynamicParser.Node.Argument node, bool isMultiPart = true, bool isOwner = false)
{
if (!string.IsNullOrEmpty(node.Name) && (isOwner || (isMultiPart && IsTableAlias(node.Name))))
return node.Name;
return null;
}
protected virtual string ParseGetMember(DynamicParser.Node.GetMember node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null, bool decorate = true, bool isMultiPart = true)
{
if (node.Host is DynamicParser.Node.Argument && IsTableAlias(node.Name))
{
decorate = false;
isMultiPart = false;
}
// This hack allows to use argument as alias, but when it is not nesesary use other column.
// Let say we hace a table Users with alias usr, and we join to table with alias ua which also has a column Users
// This allow use of usr => usr.ua.Users to result in ua."Users" instead of "Users" or usr."ua"."Users", se tests for examples.
string parent = null;
if (node.Host != null)
{
if (isMultiPart && node.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, null))
{
if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, node.Host.Host.Name))
parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), Parse(node.Host, pars, isMultiPart: false));
else
parent = Parse(node.Host, pars, isMultiPart: false);
}
else if (isMultiPart)
parent = Parse(node.Host, pars, isMultiPart: isMultiPart);
}
////string parent = node.Host == null || !isMultiPart ? null : Parse(node.Host, pars, isMultiPart: !IsTable(node.Name, node.Host.Name));
string name = parent == null ?
decorate ? Database.DecorateName(node.Name) : node.Name :
string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name);
columnSchema = GetColumnFromSchema(name);
return name;
}
protected virtual string ParseSetMember(DynamicParser.Node.SetMember node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null, bool decorate = true, bool isMultiPart = true)
{
if (node.Host is DynamicParser.Node.Argument && IsTableAlias(node.Name))
{
decorate = false;
isMultiPart = false;
}
string parent = null;
if (node.Host != null)
{
if (isMultiPart && node.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, null))
{
if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && IsTable(node.Name, node.Host.Name))
parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), Parse(node.Host, pars, isMultiPart: false));
else
parent = Parse(node.Host, pars, isMultiPart: false);
}
else if (isMultiPart)
parent = Parse(node.Host, pars, isMultiPart: isMultiPart);
}
////string parent = node.Host == null || !isMultiPart ? null : Parse(node.Host, pars, isMultiPart: !IsTable(node.Name, node.Host.Name));
string name = parent == null ?
decorate ? Database.DecorateName(node.Name) : node.Name :
string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name);
columnSchema = GetColumnFromSchema(name);
string value = Parse(node.Value, ref columnSchema, pars, nulls: true);
return string.Format("{0} = ({1})", name, value);
}
protected virtual string ParseUnary(DynamicParser.Node.Unary node, IDictionary<string, IParameter> pars = null)
{
switch (node.Operation)
{
// Artifacts from the DynamicParser class that are not usefull here...
case ExpressionType.IsFalse:
case ExpressionType.IsTrue: return Parse(node.Target, pars);
// Unary supported operations...
case ExpressionType.Not: return string.Format("(NOT {0})", Parse(node.Target, pars));
case ExpressionType.Negate: return string.Format("!({0})", Parse(node.Target, pars));
}
throw new ArgumentException("Not supported unary operation: " + node);
}
protected virtual string ParseBinary(DynamicParser.Node.Binary node, IDictionary<string, IParameter> pars = null)
{
string op = string.Empty;
switch (node.Operation)
{
// Arithmetic binary operations...
case ExpressionType.Add: op = "+"; break;
case ExpressionType.Subtract: op = "-"; break;
case ExpressionType.Multiply: op = "*"; break;
case ExpressionType.Divide: op = "/"; break;
case ExpressionType.Modulo: op = "%"; break;
case ExpressionType.Power: op = "^"; break;
case ExpressionType.And: op = "AND"; break;
case ExpressionType.Or: op = "OR"; break;
// Logical comparisons...
case ExpressionType.GreaterThan: op = ">"; break;
case ExpressionType.GreaterThanOrEqual: op = ">="; break;
case ExpressionType.LessThan: op = "<"; break;
case ExpressionType.LessThanOrEqual: op = "<="; break;
// Comparisons against 'NULL' require the 'IS' or 'IS NOT' operator instead the numeric ones...
case ExpressionType.Equal: op = node.Right == null && !VirtualMode ? "IS" : "="; break;
case ExpressionType.NotEqual: op = node.Right == null && !VirtualMode ? "IS NOT" : "<>"; break;
default: throw new ArgumentException("Not supported operator: '" + node.Operation);
}
DynamicSchemaColumn? columnSchema = null;
string left = Parse(node.Left, ref columnSchema, pars); // Not nulls: left is assumed to be an object
string right = Parse(node.Right, ref columnSchema, pars, nulls: true);
return string.Format("({0} {1} {2})", left, op, right);
}
protected virtual string ParseMethod(DynamicParser.Node.Method node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null)
{
string method = node.Name.ToUpper();
string parent = node.Host == null ? null : Parse(node.Host, ref columnSchema, pars: pars);
string item = null;
// Root-level methods...
if (node.Host == null)
{
switch (method)
{
case "NOT":
if (node.Arguments == null || node.Arguments.Length != 1) throw new ArgumentNullException("NOT method expects one argument: " + node.Arguments.Sketch());
item = Parse(node.Arguments[0], ref columnSchema, pars: pars);
return string.Format("(NOT {0})", item);
}
}
// Column-level methods...
if (node.Host != null)
{
switch (method)
{
case "BETWEEN":
{
if (node.Arguments == null || node.Arguments.Length == 0)
throw new ArgumentException("BETWEEN method expects at least one argument: " + node.Arguments.Sketch());
if (node.Arguments.Length > 2)
throw new ArgumentException("BETWEEN method expects at most two arguments: " + node.Arguments.Sketch());
object[] arguments = node.Arguments;
if (arguments.Length == 1 && (arguments[0] is IEnumerable<object> || arguments[0] is Array) && !(arguments[0] is byte[]))
{
IEnumerable<object> vals = arguments[0] as IEnumerable<object>;
if (vals == null && arguments[0] is Array)
vals = ((Array)arguments[0]).Cast<object>() as IEnumerable<object>;
if (vals != null)
arguments = vals.ToArray();
else
throw new ArgumentException("BETWEEN method expects single argument to be enumerable of exactly two elements: " + node.Arguments.Sketch());
}
return string.Format("{0} BETWEEN {1} AND {2}", parent, Parse(arguments[0], ref columnSchema, pars: pars), Parse(arguments[1], ref columnSchema, pars: pars));
}
case "IN":
{
if (node.Arguments == null || node.Arguments.Length == 0)
throw new ArgumentException("IN method expects at least one argument: " + node.Arguments.Sketch());
bool firstParam = true;
StringBuilder sbin = new StringBuilder();
foreach (object arg in node.Arguments)
{
if (!firstParam)
sbin.Append(", ");
if ((arg is IEnumerable<object> || arg is Array) && !(arg is byte[]))
{
IEnumerable<object> vals = arg as IEnumerable<object>;
if (vals == null && arg is Array)
vals = ((Array)arg).Cast<object>() as IEnumerable<object>;
if (vals != null)
foreach (object val in vals)
{
if (!firstParam)
sbin.Append(", ");
else
firstParam = false;
sbin.Append(Parse(val, ref columnSchema, pars: pars));
}
else
sbin.Append(Parse(arg, ref columnSchema, pars: pars));
}
else
sbin.Append(Parse(arg, ref columnSchema, pars: pars));
firstParam = false;
}
return string.Format("{0} IN({1})", parent, sbin.ToString());
}
case "NOTIN":
{
if (node.Arguments == null || node.Arguments.Length == 0)
throw new ArgumentException("IN method expects at least one argument: " + node.Arguments.Sketch());
bool firstParam = true;
StringBuilder sbin = new StringBuilder();
foreach (object arg in node.Arguments)
{
if (!firstParam)
sbin.Append(", ");
if ((arg is IEnumerable<object> || arg is Array) && !(arg is byte[]))
{
IEnumerable<object> vals = arg as IEnumerable<object>;
if (vals == null && arg is Array)
vals = ((Array)arg).Cast<object>() as IEnumerable<object>;
if (vals != null)
foreach (object val in vals)
{
if (!firstParam)
sbin.Append(", ");
else
firstParam = false;
sbin.Append(Parse(val, ref columnSchema, pars: pars));
}
else
sbin.Append(Parse(arg, ref columnSchema, pars: pars));
}
else
sbin.Append(Parse(arg, ref columnSchema, pars: pars));
firstParam = false;
}
return string.Format("{0} NOT IN({1})", parent, sbin.ToString());
}
case "LIKE":
if (node.Arguments == null || node.Arguments.Length != 1)
throw new ArgumentException("LIKE method expects one argument: " + node.Arguments.Sketch());
return string.Format("{0} LIKE {1}", parent, Parse(node.Arguments[0], ref columnSchema, pars: pars));
case "NOTLIKE":
if (node.Arguments == null || node.Arguments.Length != 1)
throw new ArgumentException("NOT LIKE method expects one argument: " + node.Arguments.Sketch());
return string.Format("{0} NOT LIKE {1}", parent, Parse(node.Arguments[0], ref columnSchema, pars: pars));
case "AS":
if (node.Arguments == null || node.Arguments.Length != 1)
throw new ArgumentException("AS method expects one argument: " + node.Arguments.Sketch());
item = Parse(node.Arguments[0], pars: null, rawstr: true, isMultiPart: false); // pars=null to avoid to parameterize aliases
item = item.Validated("Alias"); // Intercepting null and empty aliases
return string.Format("{0} AS {1}", parent, item);
case "COUNT":
if (node.Arguments != null && node.Arguments.Length > 1)
throw new ArgumentException("COUNT method expects one or none argument: " + node.Arguments.Sketch());
if (node.Arguments == null || node.Arguments.Length == 0)
return "COUNT(*)";
return string.Format("COUNT({0})", Parse(node.Arguments[0], ref columnSchema, pars: Parameters, nulls: true));
case "COUNT0":
if (node.Arguments != null && node.Arguments.Length > 0)
throw new ArgumentException("COUNT0 method doesn't expect arguments");
return "COUNT(0)";
}
}
// Default case: parsing the method's name along with its arguments...
method = parent == null ? node.Name : string.Format("{0}.{1}", parent, node.Name);
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}(", method);
if (node.Arguments != null && node.Arguments.Length != 0)
{
bool first = true;
foreach (object argument in node.Arguments)
{
if (!first)
sb.Append(", ");
else
first = false;
sb.Append(Parse(argument, ref columnSchema, pars, nulls: true)); // We don't accept raw strings here!!!
}
}
sb.Append(")");
return sb.ToString();
}
protected virtual string ParseInvoke(DynamicParser.Node.Invoke node, ref DynamicSchemaColumn? columnSchema, IDictionary<string, IParameter> pars = null)
{
// This is used as an especial syntax to merely concatenate its arguments. It is used as a way to extend the supported syntax without the need of treating all the possible cases...
if (node.Arguments == null || node.Arguments.Length == 0)
return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (object arg in node.Arguments)
{
if (arg is string)
{
sb.Append((string)arg);
if (node.Arguments.Length == 1 && !columnSchema.HasValue)
columnSchema = GetColumnFromSchema((string)arg);
}
else
sb.Append(Parse(arg, ref columnSchema, pars, rawstr: true, nulls: true));
}
return sb.ToString();
}
protected virtual string ParseConvert(DynamicParser.Node.Convert node, IDictionary<string, IParameter> pars = null)
{
// The cast mechanism is left for the specific database implementation, that should override this method
// as needed...
string r = Parse(node.Target, pars);
return r;
}
protected virtual string ParseConstant(object node, IDictionary<string, IParameter> pars = null, DynamicSchemaColumn? columnSchema = null)
{
if (node == null && !VirtualMode)
return ParseNull();
if (pars != null)
{
bool wellKnownName = VirtualMode && node is String && ((String)node).StartsWith("[$") && ((String)node).EndsWith("]") && ((String)node).Length > 4;
// If we have a list of parameters to store it, let's parametrize it
Parameter par = new Parameter()
{
Name = wellKnownName ? ((String)node).Substring(2, ((String)node).Length - 3) : Guid.NewGuid().ToString(),
Value = wellKnownName ? null : node,
WellKnown = wellKnownName,
Virtual = VirtualMode,
Schema = columnSchema,
};
// If we are adding parameter we inform external sources about this.
if (OnCreateTemporaryParameter != null)
OnCreateTemporaryParameter.ForEach(x => x(par));
pars.Add(par.Name, par);
return string.Format("[${0}]", par.Name);
}
return node.ToString(); // Last resort case
}
protected virtual string ParseNull()
{
return "NULL"; // Override if needed
}
#endregion Parser
#region Helpers
internal bool IsTableAlias(string name)
{
DynamicQueryBuilder builder = this;
while (builder != null)
{
if (builder.Tables.Any(t => t.Alias == name))
return true;
builder = builder._parent;
}
return false;
}
internal bool IsTable(string name, string owner)
{
DynamicQueryBuilder builder = this;
while (builder != null)
{
if ((string.IsNullOrEmpty(owner) && builder.Tables.Any(t => t.Name.ToLower() == name.ToLower())) ||
(!string.IsNullOrEmpty(owner) && builder.Tables.Any(t => t.Name.ToLower() == name.ToLower() &&
!string.IsNullOrEmpty(t.Owner) && t.Owner.ToLower() == owner.ToLower())))
return true;
builder = builder._parent;
}
return false;
}
internal string FixObjectName(string main, bool onlyColumn = false)
{
if (main.IndexOf("(") > 0 && main.IndexOf(")") > 0)
return main.FillStringWithVariables(f => string.Format("({0})", FixObjectNamePrivate(f, onlyColumn)), "(", ")");
else
return FixObjectNamePrivate(main, onlyColumn);
}
private string FixObjectNamePrivate(string f, bool onlyColumn = false)
{
IEnumerable<string> objects = f.Split('.')
.Select(x => Database.StripName(x));
if (onlyColumn || objects.Count() == 1)
f = Database.DecorateName(objects.Last());
else if (!IsTableAlias(objects.First()))
f = string.Join(".", objects.Select(o => Database.DecorateName(o)));
else
f = string.Format("{0}.{1}", objects.First(), string.Join(".", objects.Skip(1).Select(o => Database.DecorateName(o))));
return f;
}
internal DynamicSchemaColumn? GetColumnFromSchema(string colName, DynamicTypeMap mapper = null, string table = null)
{
// This is tricky and will not always work unfortunetly.
////if (colName.ContainsAny(StringExtensions.InvalidMultipartMemberChars))
//// return null;
// First we need to get real column name and it's owner if exist.
string[] parts = colName.Split('.');
for (int i = 0; i < parts.Length; i++)
parts[i] = Database.StripName(parts[i]);
string columnName = parts.Last();
// Get table name from mapper
string tableName = table;
if (string.IsNullOrEmpty(tableName))
{
tableName = (mapper != null && mapper.Table != null) ? mapper.Table.Name : string.Empty;
if (parts.Length > 1 && string.IsNullOrEmpty(tableName))
{
// OK, we have a multi part identifier, that's good, we can get table name
tableName = string.Join(".", parts.Take(parts.Length - 1));
}
}
// Try to get table info from cache
ITableInfo tableInfo = !string.IsNullOrEmpty(tableName) ?
Tables.FirstOrDefault(x => !string.IsNullOrEmpty(x.Alias) && x.Alias.ToLower() == tableName) ??
Tables.FirstOrDefault(x => x.Name.ToLower() == tableName.ToLower()) ?? Tables.FirstOrDefault() :
this is DynamicModifyBuilder || Tables.Count == 1 ? Tables.FirstOrDefault() : null;
// Try to get column from schema
if (tableInfo != null && tableInfo.Schema != null)
return tableInfo.Schema.TryGetNullable(columnName.ToLower());
// Well, we failed to find a column
return null;
}
#endregion Helpers
#region IExtendedDisposable
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public virtual void Dispose()
{
IsDisposed = true;
if (Database != null)
Database.RemoveFromCache(this);
if (Parameters != null)
{
foreach (KeyValuePair<string, IParameter> p in Parameters)
p.Value.Dispose();
Parameters.Clear();
Parameters = null;
}
if (Tables != null)
{
foreach (ITableInfo t in Tables)
if (t != null)
t.Dispose();
Tables.Clear();
Tables = null;
}
WhereCondition = null;
Database = null;
}
#endregion IExtendedDisposable
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,342 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Some of methods in this code file is based on Kerosene ORM solution
* for parsing dynamic lambda expressions by Moisés Barba Cebeira
*
* 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.Builders.Extensions;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
namespace DynamORM.Builders.Implementation
{
/// <summary>Update query builder.</summary>
internal class DynamicUpdateQueryBuilder : DynamicModifyBuilder, IDynamicUpdateQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{
private string _columns;
internal DynamicUpdateQueryBuilder(DynamicDatabase db)
: base(db)
{
}
public DynamicUpdateQueryBuilder(DynamicDatabase db, string tableName)
: base(db, tableName)
{
}
/// <summary>Generates the text this command will execute against the underlying database.</summary>
/// <returns>The text to execute against the underlying database.</returns>
/// <remarks>This method must be override by derived classes.</remarks>
public override string CommandText()
{
ITableInfo info = Tables.Single();
return string.Format("UPDATE {0}{1} SET {2}{3}{4}",
string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)),
Database.DecorateName(info.Name), _columns,
string.IsNullOrEmpty(WhereCondition) ? string.Empty : " WHERE ",
WhereCondition);
}
#region Update
/// <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 IDynamicUpdateQueryBuilder Update(string column, object value)
{
DynamicSchemaColumn? col = GetColumnFromSchema(column);
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 IDynamicUpdateQueryBuilder Update(object conditions)
{
if (conditions is DynamicColumn)
{
DynamicColumn column = (DynamicColumn)conditions;
DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName);
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;
}
IDictionary<string, object> dict = conditions.ToDictionary();
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType());
foreach (KeyValuePair<string, object> 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 = GetColumnFromSchema(colName);
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;
}
}
DynamicPropertyInvoker propMap = mapper.ColumnsMap.TryGetValue(colName.ToLower());
if (propMap == null || propMap.Column == null || !propMap.Column.IsNoUpdate)
Values(colName, con.Value);
}
return this;
}
#endregion Update
#region Values
/// <summary>
/// Specifies the columns to update using the dynamic lambda expressions given. Each expression correspond to one
/// column, and can:
/// <para>- Resolve to a string, in this case a '=' must appear in the string.</para>
/// <para>- Resolve to a expression with the form: 'x =&gt; x.Column = Value'.</para>
/// </summary>
/// <param name="func">The specifications.</param>
/// <returns>This instance to permit chaining.</returns>
public virtual IDynamicUpdateQueryBuilder Set(params Func<dynamic, object>[] func)
{
if (func == null)
throw new ArgumentNullException("Array of specifications cannot be null.");
int index = -1;
foreach (Func<dynamic, object> f in func)
{
index++;
if (f == null)
throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index));
object result = null;
using (DynamicParser p = DynamicParser.Parse(f))
{
result = p.Result;
if (result == null)
throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index));
string main = null;
string value = null;
string str = null;
// When 'x => x.Table.Column = value' or 'x => x.Column = value'...
if (result is DynamicParser.Node.SetMember)
{
DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result;
DynamicSchemaColumn? col = GetColumnFromSchema(node.Name);
main = Database.DecorateName(node.Name);
value = Parse(node.Value, ref col, pars: Parameters, nulls: true);
str = string.Format("{0} = {1}", main, value);
_columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str);
continue;
}
else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType)
{
Values(result);
continue;
}
// Other specifications are considered invalid...
string err = string.Format("Specification '{0}' is invalid.", result);
str = Parse(result);
if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?";
throw new ArgumentException(err);
}
}
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 IDynamicUpdateQueryBuilder Values(string column, object value)
{
if (value is DynamicColumn)
{
DynamicColumn v = (DynamicColumn)value;
if (string.IsNullOrEmpty(v.ColumnName))
v.ColumnName = column;
return Values(v);
}
return Values(new DynamicColumn
{
ColumnName = column,
Value = value,
});
}
/// <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 IDynamicUpdateQueryBuilder Values(object o)
{
if (o is DynamicColumn)
{
DynamicColumn column = (DynamicColumn)o;
DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName);
string main = FixObjectName(column.ColumnName, onlyColumn: true);
string value = Parse(column.Value, ref col, pars: Parameters, nulls: true);
string str = string.Format("{0} = {1}", main, value);
_columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str);
return this;
}
IDictionary<string, object> dict = o.ToDictionary();
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(o.GetType());
if (mapper != null)
{
foreach (KeyValuePair<string, object> con in dict)
if (!mapper.Ignored.Contains(con.Key))
Values(mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key, con.Value);
}
else
foreach (KeyValuePair<string, object> con in dict)
Values(con.Key, con.Value);
return this;
}
#endregion Values
#region Where
/// <summary>
/// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition
/// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used
/// as needed.
/// <para>- If several Where() methods are chained their contents are, by default, concatenated with an 'AND' operator.</para>
/// <para>- The 'And()' and 'Or()' virtual method can be used to concatenate with an 'OR' or an 'AND' operator, as in:
/// 'Where( x => x.Or( condition ) )'.</para>
/// </summary>
/// <param name="func">The specification.</param>
/// <returns>This instance to permit chaining.</returns>
public virtual IDynamicUpdateQueryBuilder Where(Func<dynamic, object> func)
{
return this.InternalWhere(func);
}
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column with operator and value.</param>
/// <returns>Builder instance.</returns>
public virtual IDynamicUpdateQueryBuilder Where(DynamicColumn column)
{
return this.InternalWhere(column);
}
/// <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 IDynamicUpdateQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value)
{
return this.InternalWhere(column, op, value);
}
/// <summary>Add where condition.</summary>
/// <param name="column">Condition column.</param>
/// <param name="value">Condition value.</param>
/// <returns>Builder instance.</returns>
public virtual IDynamicUpdateQueryBuilder Where(string column, object value)
{
return this.InternalWhere(column, 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 IDynamicUpdateQueryBuilder Where(object conditions, bool schema = false)
{
return this.InternalWhere(conditions, schema);
}
#endregion Where
#region IExtendedDisposable
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public override void Dispose()
{
base.Dispose();
_columns = null;
}
#endregion IExtendedDisposable
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -13,11 +13,6 @@
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<SignAssembly>False</SignAssembly>
<DelaySign>False</DelaySign>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -29,31 +24,17 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>PdbOnly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DebugSymbols>true</DebugSymbols>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DocumentationFile>bin\Release\DynamORM.xml</DocumentationFile>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@@ -64,59 +45,30 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Builders\Extensions\DynamicHavingQueryExtensions.cs" /> <Compile Include="Builders\DynamicDeleteQueryBuilder.cs" />
<Compile Include="Builders\IDynamicInsertQueryBuilder.cs" /> <Compile Include="Builders\DynamicInsertQueryBuilder.cs" />
<Compile Include="Builders\IDynamicSelectQueryBuilder.cs" /> <Compile Include="Builders\DynamicQueryBuilder.cs" />
<Compile Include="Builders\IDynamicUpdateQueryBuilder.cs" /> <Compile Include="Builders\DynamicSelectQueryBuilder.cs" />
<Compile Include="Builders\Implementation\DynamicDeleteQueryBuilder.cs" /> <Compile Include="Builders\DynamicUpdateQueryBuilder.cs" />
<Compile Include="Builders\Implementation\DynamicInsertQueryBuilder.cs" />
<Compile Include="Builders\Implementation\DynamicModifyBuilder.cs" />
<Compile Include="Builders\Implementation\DynamicQueryBuilder.cs" />
<Compile Include="Builders\Extensions\DynamicModifyBuilderExtensions.cs" />
<Compile Include="Builders\Extensions\DynamicWhereQueryExtensions.cs" />
<Compile Include="Builders\Implementation\DynamicSelectQueryBuilder.cs" />
<Compile Include="Builders\Implementation\DynamicUpdateQueryBuilder.cs" />
<Compile Include="Builders\IDynamicDeleteQueryBuilder.cs" />
<Compile Include="Builders\IDynamicQueryBuilder.cs" /> <Compile Include="Builders\IDynamicQueryBuilder.cs" />
<Compile Include="Builders\IParameter.cs" />
<Compile Include="Builders\ITableInfo.cs" />
<Compile Include="DynamicCachedReader.cs" />
<Compile Include="DynamicColumn.cs" /> <Compile Include="DynamicColumn.cs" />
<Compile Include="DynamicCommand.cs" /> <Compile Include="DynamicCommand.cs" />
<Compile Include="DynamicConnection.cs" /> <Compile Include="DynamicConnection.cs" />
<Compile Include="DynamicDatabase.cs" /> <Compile Include="DynamicDatabase.cs" />
<Compile Include="DynamicDatabaseOptions.cs" /> <Compile Include="DynamicDatabaseOptions.cs" />
<Compile Include="DynamicExtensions.cs" /> <Compile Include="DynamicExtensions.cs" />
<Compile Include="DynamicProcedureInvoker.cs" />
<Compile Include="DynamicQueryException.cs" />
<Compile Include="DynamicSchemaColumn.cs" /> <Compile Include="DynamicSchemaColumn.cs" />
<Compile Include="DynamicTable.cs" /> <Compile Include="DynamicTable.cs" />
<Compile Include="DynamicTransaction.cs" /> <Compile Include="DynamicTransaction.cs" />
<Compile Include="Helpers\CollectionComparer.cs" /> <Compile Include="Helpers\CollectionComparer.cs" />
<Compile Include="Helpers\Dynamics\DynamicParser.cs" />
<Compile Include="Helpers\Dynamics\DynamicProxy.cs" />
<Compile Include="Helpers\IExtendedDisposable.cs" />
<Compile Include="Helpers\FrameworkTools.cs" /> <Compile Include="Helpers\FrameworkTools.cs" />
<Compile Include="Helpers\StringExtensions.cs" />
<Compile Include="Helpers\UnclassifiedExtensions.cs" />
<Compile Include="Mapper\ColumnAttribute.cs" /> <Compile Include="Mapper\ColumnAttribute.cs" />
<Compile Include="Mapper\DynamicMapperCache.cs" /> <Compile Include="Mapper\DynamicMapperCache.cs" />
<Compile Include="Mapper\DynamicMapperException.cs" />
<Compile Include="Mapper\DynamicPropertyInvoker.cs" /> <Compile Include="Mapper\DynamicPropertyInvoker.cs" />
<Compile Include="Mapper\DynamicTypeMap.cs" /> <Compile Include="Mapper\DynamicTypeMap.cs" />
<Compile Include="Mapper\IgnoreAttribute.cs" /> <Compile Include="Mapper\IgnoreAttribute.cs" />
<Compile Include="Objects\DynamicEntityBase.cs" />
<Compile Include="Objects\DynamicEntityState.cs" />
<Compile Include="Objects\DynamicPropertyChangingEventArgs.cs" />
<Compile Include="Objects\DynamicRepositoryBase.cs" />
<Compile Include="Validation\RequiredAttribute.cs" />
<Compile Include="Mapper\TableAttribute.cs" /> <Compile Include="Mapper\TableAttribute.cs" />
<Compile Include="Mapper\DynamicCast.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DynamicExpando.cs" />
<Compile Include="Helpers\IFinalizerDisposable.cs" />
<Compile Include="Validation\ValidateResult.cs" />
<Compile Include="Validation\ValidationResult.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -1,578 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.IO;
using DynamORM.Helpers;
using DynamORM.Mapper;
namespace DynamORM
{
/// <summary>Cache data reader in memory.</summary>
public class DynamicCachedReader : DynamicObject, IDataReader
{
#region Constructor and Data
private DataTable _schema;
private int _fields;
private int _rows;
private int _position;
private int _cachePos;
private IList<string> _names;
private IDictionary<string, int> _ordinals;
private IList<Type> _types;
private IList<object> _cache;
private DynamicCachedReader()
{
}
/// <summary>Initializes a new instance of the <see cref="DynamicCachedReader" /> class.</summary>
/// <param name="reader">Reader to cache.</param>
/// <param name="offset">The offset row.</param>
/// <param name="limit">The limit to number of tows. -1 is no limit.</param>
/// <param name="progress">The progress delegate.</param>
public DynamicCachedReader(IDataReader reader, int offset = 0, int limit = -1, Func<DynamicCachedReader, int, bool> progress = null)
{
InitDataReader(reader, offset, limit, progress);
}
#endregion Constructor and Data
#region Helpers
/// <summary>Create data reader from enumerable.</summary>
/// <typeparam name="T">Type of enumerated objects.</typeparam>
/// <param name="objects">List of objects.</param>
/// <returns>Instance of <see cref="DynamicCachedReader"/> containing objects data.</returns>
public static DynamicCachedReader FromEnumerable<T>(IEnumerable<T> objects)
{
var mapper = DynamicMapperCache.GetMapper<T>();
if (mapper == null)
throw new InvalidCastException(string.Format("Object type '{0}' can't be mapped.", typeof(T).FullName));
var r = new DynamicCachedReader();
r.Init(mapper.ColumnsMap.Count + 1);
r.CreateSchemaTable(mapper);
r.FillFromEnumerable(objects, mapper);
r.IsClosed = false;
r._position = -1;
r._cachePos = -1;
return r;
}
/// <summary>Create data reader from enumerable.</summary>
/// <param name="elementType">Type of enumerated objects.</param>
/// <param name="objects">List of objects.</param>
/// <returns>Instance of <see cref="DynamicCachedReader"/> containing objects data.</returns>
public static DynamicCachedReader FromEnumerable(Type elementType, IEnumerable objects)
{
var mapper = DynamicMapperCache.GetMapper(elementType);
if (mapper == null)
throw new InvalidCastException(string.Format("Object type '{0}' can't be mapped.", elementType.FullName));
var r = new DynamicCachedReader();
r.Init(mapper.ColumnsMap.Count + 1);
r.CreateSchemaTable(mapper);
r.FillFromEnumerable(elementType, objects, mapper);
r.IsClosed = false;
r._position = -1;
r._cachePos = -1;
return r;
}
private void InitDataReader(IDataReader reader, int offset = 0, int limit = -1, Func<DynamicCachedReader, int, bool> progress = null)
{
_schema = reader.GetSchemaTable();
RecordsAffected = reader.RecordsAffected;
Init(reader.FieldCount);
int i = 0;
for (i = 0; i < _fields; i++)
{
_names.Add(reader.GetName(i));
_types.Add(reader.GetFieldType(i));
if (!_ordinals.ContainsKey(reader.GetName(i).ToUpper()))
_ordinals.Add(reader.GetName(i).ToUpper(), i);
}
int current = 0;
while (reader.Read())
{
if (current < offset)
{
current++;
continue;
}
for (i = 0; i < _fields; i++)
_cache.Add(reader[i]);
_rows++;
current++;
if (limit >= 0 && _rows >= limit)
break;
if (progress != null && !progress(this, _rows))
break;
}
IsClosed = false;
_position = -1;
_cachePos = -1;
if (progress != null)
progress(this, _rows);
reader.Close();
}
private void FillFromEnumerable<T>(IEnumerable<T> objects, DynamicTypeMap mapper)
{
foreach (var elem in objects)
{
foreach (var col in mapper.ColumnsMap)
{
object val = null;
if (col.Value.Get != null)
val = col.Value.Get(elem);
_cache.Add(val);
}
_cache.Add(elem);
_rows++;
}
}
private void FillFromEnumerable(Type elementType, IEnumerable objects, DynamicTypeMap mapper)
{
foreach (var elem in objects)
{
foreach (var col in mapper.ColumnsMap)
{
object val = null;
if (col.Value.Get != null)
val = col.Value.Get(elem);
_cache.Add(val);
}
_cache.Add(elem);
_rows++;
}
}
private void CreateSchemaTable(DynamicTypeMap mapper)
{
_schema = new DataTable("DYNAMIC");
_schema.Columns.Add(new DataColumn("ColumnName", typeof(string)));
_schema.Columns.Add(new DataColumn("ColumnOrdinal", typeof(int)));
_schema.Columns.Add(new DataColumn("ColumnSize", typeof(int)));
_schema.Columns.Add(new DataColumn("NumericPrecision", typeof(short)));
_schema.Columns.Add(new DataColumn("NumericScale", typeof(short)));
_schema.Columns.Add(new DataColumn("DataType", typeof(Type)));
_schema.Columns.Add(new DataColumn("ProviderType", typeof(int)));
_schema.Columns.Add(new DataColumn("NativeType", typeof(int)));
_schema.Columns.Add(new DataColumn("AllowDBNull", typeof(bool)));
_schema.Columns.Add(new DataColumn("IsUnique", typeof(bool)));
_schema.Columns.Add(new DataColumn("IsKey", typeof(bool)));
_schema.Columns.Add(new DataColumn("IsAutoIncrement", typeof(bool)));
int ordinal = 0;
DataRow dr = null;
foreach (var column in mapper.ColumnsMap)
{
dr = _schema.NewRow();
dr[0] = column.Value.Column.NullOr(x => x.Name ?? column.Value.Name, column.Value.Name);
dr[1] = ordinal;
dr[2] = column.Value.Column.NullOr(x => x.Size ?? int.MaxValue, int.MaxValue);
dr[3] = column.Value.Column.NullOr(x => x.Precision ?? 0, 0);
dr[4] = column.Value.Column.NullOr(x => x.Scale ?? 0, 0);
dr[5] = column.Value.Column.NullOr(x => x.Type.HasValue ? x.Type.Value.ToType() : column.Value.Type, column.Value.Type);
dr[6] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType());
dr[7] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType());
dr[8] = column.Value.Column.NullOr(x => x.IsKey, false) ? true : column.Value.Column.NullOr(x => x.AllowNull, true);
dr[9] = column.Value.Column.NullOr(x => x.IsUnique, false);
dr[10] = column.Value.Column.NullOr(x => x.IsKey, false);
dr[11] = false;
_schema.Rows.Add(dr);
_names.Add(dr[0].ToString());
_ordinals.Add(dr[0].ToString().ToUpper(), ordinal++);
_types.Add((Type)dr[5]);
dr.AcceptChanges();
}
dr = _schema.NewRow();
dr[0] = "#O";
dr[1] = ordinal;
dr[2] = int.MaxValue;
dr[3] = 0;
dr[4] = 0;
dr[5] = mapper.Type;
dr[6] = DbType.Object;
dr[7] = DbType.Object;
dr[8] = true;
dr[9] = false;
dr[10] = false;
dr[11] = false;
_schema.Rows.Add(dr);
_names.Add("#O");
_ordinals.Add("#O".ToUpper(), ordinal++);
_types.Add(mapper.Type);
dr.AcceptChanges();
}
private void Init(int fieldCount)
{
_rows = 0;
_fields = fieldCount;
_names = new List<string>(_fields);
_ordinals = new Dictionary<string, int>(_fields);
_types = new List<Type>(_fields);
_cache = new List<object>(_fields * 100);
}
/// <summary>Sets the current position in reader.</summary>
/// <param name="pos">The position.</param>
public void SetPosition(int pos)
{
if (pos >= -1 && pos < _rows)
{
_position = pos;
_cachePos = _position * _fields;
}
else
throw new IndexOutOfRangeException();
}
#endregion Helpers
#region IDataReader Members
/// <summary>Closes the System.Data.IDataReader Object.</summary>
public void Close()
{
IsClosed = true;
_position = _rows;
_cachePos = -1;
}
/// <summary>Gets a value indicating the depth of nesting for the current row.</summary>
/// <remarks>This implementation use this field to indicate row count.</remarks>
public int Depth
{
get { return _rows; }
}
/// <summary>Returns a System.Data.DataTable that describes the column metadata of the
/// System.Data.IDataReader.</summary><returns>A System.Data.DataTable that describes
/// the column metadata.</returns><exception cref="System.InvalidOperationException">
/// The System.Data.IDataReader is closed.</exception>
public DataTable GetSchemaTable()
{
return _schema;
}
/// <summary>Gets a value indicating whether the data reader is closed.</summary>
public bool IsClosed { get; private set; }
/// <summary>Advances the data reader to the next result, when reading the results of batch SQL statements.</summary>
/// <returns>Returns true if there are more rows; otherwise, false.</returns>
public bool NextResult()
{
_cachePos = (++_position) * _fields;
return _position < _rows;
}
/// <summary>Advances the System.Data.IDataReader to the next record.</summary>
/// <returns>Returns true if there are more rows; otherwise, false.</returns>
public bool Read()
{
_cachePos = (++_position) * _fields;
return _position < _rows;
}
/// <summary>Gets the number of rows changed, inserted, or deleted by execution of the SQL statement.</summary>
/// <returns>The number of rows changed, inserted, or deleted; 0 if no rows were affected or the statement
/// failed; and -1 for SELECT statements.</returns>
public int RecordsAffected { get; private set; }
#endregion IDataReader Members
#region IDisposable Members
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
_names.Clear();
_types.Clear();
_cache.Clear();
_schema.Dispose();
}
#endregion IDisposable Members
#region IDataRecord Members
/// <summary>Gets the number of columns in the current row.</summary>
/// <remarks>When not positioned in a valid record set, 0; otherwise, the number of columns in the current record. The default is -1.</remarks>
public int FieldCount { get { return _fields; } }
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public bool GetBoolean(int i)
{
return (bool)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public byte GetByte(int i)
{
return (byte)_cache[_cachePos + i];
}
/// <summary>Reads a stream of bytes from the specified column offset into the buffer
/// as an array, starting at the given buffer offset.</summary>
/// <param name="i">The index of the field to find.</param>
/// <param name="fieldOffset">The index within the field from which to start the read operation.</param>
/// <param name="buffer">The buffer into which to read the stream of bytes.</param>
/// <param name="bufferoffset">The index for buffer to start the read operation.</param>
/// <param name="length">The number of bytes to read.</param>
/// <returns>The actual number of bytes read.</returns>
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
{
using (MemoryStream ms = new MemoryStream((byte[])_cache[_cachePos + i]))
return ms.Read(buffer, bufferoffset, length);
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public char GetChar(int i)
{
return (char)_cache[_cachePos + i];
}
/// <summary>Reads a stream of characters from the specified column offset into the buffer
/// as an array, starting at the given buffer offset.</summary>
/// <param name="i">The zero-based column ordinal.</param>
/// <param name="fieldoffset">The index within the row from which to start the read operation.</param>
/// <param name="buffer">The buffer into which to read the stream of bytes.</param>
/// <param name="bufferoffset">The index for buffer to start the read operation.</param>
/// <param name="length">The number of bytes to read.</param>
/// <returns>The actual number of characters read.</returns>
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
{
using (MemoryStream ms = new MemoryStream((byte[])_cache[_cachePos + i]))
{
byte[] buff = new byte[buffer.Length];
long ret = ms.Read(buff, bufferoffset, length);
for (int n = bufferoffset; n < ret; n++)
buffer[n] = (char)buff[n];
return ret;
}
}
/// <summary>Returns an System.Data.IDataReader for the specified column ordinal.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>An System.Data.IDataReader.</returns>
public IDataReader GetData(int i)
{
return null;
}
/// <summary>Gets the data type information for the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>The data type information for the specified field.</returns>
public string GetDataTypeName(int i)
{
return _types[i].Name;
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public DateTime GetDateTime(int i)
{
return (DateTime)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public decimal GetDecimal(int i)
{
return (decimal)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public double GetDouble(int i)
{
return (double)_cache[_cachePos + i];
}
/// <summary>Gets the System.Type information corresponding to the type of System.Object
/// that would be returned from System.Data.IDataRecord.GetValue(System.Int32).</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>The System.Type information corresponding to the type of System.Object that
/// would be returned from System.Data.IDataRecord.GetValue(System.Int32).</returns>
public Type GetFieldType(int i)
{
return _types[i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public float GetFloat(int i)
{
return (float)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public Guid GetGuid(int i)
{
return (Guid)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public short GetInt16(int i)
{
return (short)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public int GetInt32(int i)
{
return (int)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public long GetInt64(int i)
{
return (long)_cache[_cachePos + i];
}
/// <summary>Gets the name for the field to find.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>The name of the field or the empty string (""), if there is no value to return.</returns>
public string GetName(int i)
{
return _names[i];
}
/// <summary>Return the index of the named field.</summary>
/// <param name="name">The name of the field to find.</param>
/// <returns>The index of the named field.</returns>
public int GetOrdinal(string name)
{
if (_ordinals.ContainsKey(name.ToUpper()))
return _ordinals[name.ToUpper()];
return -1;
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public string GetString(int i)
{
return (string)_cache[_cachePos + i];
}
/// <summary>Return the value of the specified field.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Field value upon return.</returns>
public object GetValue(int i)
{
return _cache[_cachePos + i];
}
/// <summary>Gets all the attribute fields in the collection for the current record.</summary>
/// <param name="values">An array of System.Object to copy the attribute fields into.</param>
/// <returns>The number of instances of System.Object in the array.</returns>
public int GetValues(object[] values)
{
for (int i = 0; i < _fields; i++)
values[i] = _cache[_cachePos + i];
return _fields;
}
/// <summary>Return whether the specified field is set to null.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Returns true if the specified field is set to null; otherwise, false.</returns>
public bool IsDBNull(int i)
{
return _cache[_cachePos + i] == null || _cache[_cachePos + i] == DBNull.Value;
}
/// <summary>Gets or sets specified value in current record.</summary>
/// <param name="name">Name of column.</param>
/// <returns>Value of specified column.</returns>
public object this[string name]
{
get
{
if (_ordinals.ContainsKey(name.ToUpper()))
return _cache[_cachePos + _ordinals[name.ToUpper()]];
throw new IndexOutOfRangeException(String.Format("Field '{0}' not found.", name));
}
}
/// <summary>Gets or sets specified value in current record.</summary>
/// <param name="i">The index of the field to find.</param>
/// <returns>Value of specified column.</returns>
public object this[int i]
{
get { return _cache[_cachePos + i]; }
}
#endregion IDataRecord Members
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -145,7 +145,7 @@ namespace DynamORM
public bool EndBlock { get; set; } public bool EndBlock { get; set; }
/// <summary>Gets or sets a value indicating whether set parameters for null values.</summary> /// <summary>Gets or sets a value indicating whether set parameters for null values.</summary>
public bool? VirtualColumn { get; set; } public bool VirtualColumn { get; set; }
/// <summary>Gets or sets schema representation of a column.</summary> /// <summary>Gets or sets schema representation of a column.</summary>
/// <remarks>Workaround to providers issues which sometimes pass wrong /// <remarks>Workaround to providers issues which sometimes pass wrong
@@ -370,7 +370,7 @@ namespace DynamORM
/// <summary>Sets the virtual column.</summary> /// <summary>Sets the virtual column.</summary>
/// <param name="virt">Set virtual column value.</param> /// <param name="virt">Set virtual column value.</param>
/// <returns>Returns self.</returns> /// <returns>Returns self.</returns>
public DynamicColumn SetVirtualColumn(bool? virt) public DynamicColumn SetVirtualColumn(bool virt)
{ {
VirtualColumn = virt; VirtualColumn = virt;
return this; return this;
@@ -390,7 +390,7 @@ namespace DynamORM
public static DynamicColumn ParseSelectColumn(string column) public static DynamicColumn ParseSelectColumn(string column)
{ {
// Split column description // Split column description
string[] parts = column.Split(':'); var parts = column.Split(':');
if (parts.Length > 0) if (parts.Length > 0)
{ {
@@ -416,7 +416,7 @@ namespace DynamORM
public static DynamicColumn ParseOrderByColumn(string column) public static DynamicColumn ParseOrderByColumn(string column)
{ {
// Split column description // Split column description
string[] parts = column.Split(':'); var parts = column.Split(':');
if (parts.Length > 0) if (parts.Length > 0)
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,14 +27,12 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Helper class to easy manage command.</summary> /// <summary>Helper class to easy manage command.</summary>
public class DynamicCommand : IDbCommand, IExtendedDisposable public class DynamicCommand : IDbCommand
{ {
private IDbCommand _command; private IDbCommand _command;
private int? _commandTimeout = null; private int? _commandTimeout = null;
@@ -47,7 +45,6 @@ namespace DynamORM
/// <param name="db">The database manager.</param> /// <param name="db">The database manager.</param>
internal DynamicCommand(DynamicConnection con, DynamicDatabase db) internal DynamicCommand(DynamicConnection con, DynamicDatabase db)
{ {
IsDisposed = false;
_con = con; _con = con;
_db = db; _db = db;
@@ -58,7 +55,7 @@ namespace DynamORM
else else
{ {
_command = _con.Connection.CreateCommand(); _command = _con.Connection.CreateCommand();
_db.CommandsPool[_con.Connection].Add(this); _db.CommandsPool[_con.Connection].Add(_command);
} }
} }
} }
@@ -68,7 +65,6 @@ namespace DynamORM
/// <remarks>Used internally to create command without context.</remarks> /// <remarks>Used internally to create command without context.</remarks>
internal DynamicCommand(DynamicDatabase db) internal DynamicCommand(DynamicDatabase db)
{ {
IsDisposed = false;
_db = db; _db = db;
_command = db.Provider.CreateCommand(); _command = db.Provider.CreateCommand();
} }
@@ -90,10 +86,7 @@ namespace DynamORM
////_poolStamp = _db.PoolStamp; ////_poolStamp = _db.PoolStamp;
} }
if (_db.DumpCommands) return _db.DumpCommands ? _command.Dump(Console.Out) : _command;
_db.DumpCommand(_command);
return _command;
} }
#region IDbCommand Members #region IDbCommand Members
@@ -138,13 +131,11 @@ namespace DynamORM
////_poolStamp = 0; ////_poolStamp = 0;
_command.Connection = _con.Connection; _command.Connection = _con.Connection;
} }
else if (value == null) else
{ {
_command.Transaction = null; _command.Transaction = null;
_command.Connection = null; _command.Connection = null;
} }
else
throw new InvalidOperationException("Can't assign direct IDbConnection implementation. This property accepts only DynamORM implementation of IDbConnection.");
} }
} }
@@ -161,14 +152,7 @@ namespace DynamORM
/// <returns>The number of rows affected.</returns> /// <returns>The number of rows affected.</returns>
public int ExecuteNonQuery() public int ExecuteNonQuery()
{ {
try return PrepareForExecution().ExecuteNonQuery();
{
return PrepareForExecution().ExecuteNonQuery();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/> /// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
@@ -180,14 +164,7 @@ namespace DynamORM
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns> /// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
public IDataReader ExecuteReader(CommandBehavior behavior) public IDataReader ExecuteReader(CommandBehavior behavior)
{ {
try return PrepareForExecution().ExecuteReader(behavior);
{
return PrepareForExecution().ExecuteReader(behavior);
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/> /// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
@@ -196,14 +173,7 @@ namespace DynamORM
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns> /// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
public IDataReader ExecuteReader() public IDataReader ExecuteReader()
{ {
try return PrepareForExecution().ExecuteReader();
{
return PrepareForExecution().ExecuteReader();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the query, and returns the first column of the /// <summary>Executes the query, and returns the first column of the
@@ -212,14 +182,7 @@ namespace DynamORM
/// <returns>The first column of the first row in the result set.</returns> /// <returns>The first column of the first row in the result set.</returns>
public object ExecuteScalar() public object ExecuteScalar()
{ {
try return PrepareForExecution().ExecuteScalar();
{
return PrepareForExecution().ExecuteScalar();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Gets the <see cref="T:System.Data.IDataParameterCollection"/>.</summary> /// <summary>Gets the <see cref="T:System.Data.IDataParameterCollection"/>.</summary>
@@ -231,20 +194,13 @@ namespace DynamORM
/// <summary>Creates a prepared (or compiled) version of the command on the data source.</summary> /// <summary>Creates a prepared (or compiled) version of the command on the data source.</summary>
public void Prepare() public void Prepare()
{ {
try _command.Prepare();
{
_command.Prepare();
}
catch (Exception ex)
{
throw new DynamicQueryException("Error preparing command.", ex, this);
}
} }
/// <summary>Gets or sets the transaction within which the Command /// <summary>Gets or sets the transaction within which the Command
/// object of a data provider executes.</summary> /// object of a data provider executes.</summary>
/// <remarks>It's does nothing, transaction is peeked from transaction /// <remarks>It's does nothing, transaction is peeked from transaction
/// pool of a connection. This is only a dummy.</remarks> /// pool of a connection.</remarks>
public IDbTransaction Transaction { get { return null; } set { } } public IDbTransaction Transaction { get { return null; } set { } }
/// <summary>Gets or sets how command results are applied to the <see cref="T:System.Data.DataRow"/> /// <summary>Gets or sets how command results are applied to the <see cref="T:System.Data.DataRow"/>
@@ -258,7 +214,7 @@ namespace DynamORM
#endregion IDbCommand Members #endregion IDbCommand Members
#region IExtendedDisposable Members #region IDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
@@ -268,27 +224,16 @@ namespace DynamORM
{ {
if (_con != null) if (_con != null)
{ {
List<IDbCommand> pool = _db.CommandsPool.TryGetValue(_con.Connection); var pool = _db.CommandsPool.TryGetValue(_con.Connection);
if (pool != null && pool.Contains(this)) if (pool != null && pool.Contains(_command))
pool.Remove(this); pool.Remove(_command);
} }
IsDisposed = true; _command.Dispose();
if (_command != null)
{
_command.Parameters.Clear();
_command.Dispose();
_command = null;
}
} }
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary> #endregion IDisposable Members
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -28,14 +28,13 @@
using System; using System;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Connection wrapper.</summary> /// <summary>Connection wrapper.</summary>
/// <remarks>This class is only connection holder, connection is managed by /// <remarks>This class is only connection holder, connection is managed by
/// <see cref="DynamicDatabase"/> instance.</remarks> /// <see cref="DynamicDatabase"/> instance.</remarks>
public class DynamicConnection : IDbConnection, IExtendedDisposable public class DynamicConnection : IDbConnection, IDisposable
{ {
private DynamicDatabase _db; private DynamicDatabase _db;
private bool _singleTransaction; private bool _singleTransaction;
@@ -49,7 +48,6 @@ namespace DynamORM
/// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param> /// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param>
internal DynamicConnection(DynamicDatabase db, IDbConnection con, bool singleTransaction) internal DynamicConnection(DynamicDatabase db, IDbConnection con, bool singleTransaction)
{ {
IsDisposed = false;
_db = db; _db = db;
Connection = con; Connection = con;
_singleTransaction = singleTransaction; _singleTransaction = singleTransaction;
@@ -57,12 +55,11 @@ namespace DynamORM
/// <summary>Begins a database transaction.</summary> /// <summary>Begins a database transaction.</summary>
/// <param name="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param> /// <param name="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param>
/// <param name="custom">Custom parameter describing transaction options.</param>
/// <param name="disposed">This action is invoked when transaction is disposed.</param> /// <param name="disposed">This action is invoked when transaction is disposed.</param>
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns> /// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
internal DynamicTransaction BeginTransaction(IsolationLevel? il, object custom, Action disposed) internal DynamicTransaction BeginTransaction(IsolationLevel? il, Action disposed)
{ {
return new DynamicTransaction(_db, this, _singleTransaction, il, disposed, null); return new DynamicTransaction(_db, this, _singleTransaction, il, disposed);
} }
#region IDbConnection Members #region IDbConnection Members
@@ -78,7 +75,7 @@ namespace DynamORM
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns> /// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
public IDbTransaction BeginTransaction() public IDbTransaction BeginTransaction()
{ {
return BeginTransaction(null, null, null); return BeginTransaction(null, null);
} }
/// <summary>Begins a database transaction with the specified /// <summary>Begins a database transaction with the specified
@@ -87,16 +84,7 @@ namespace DynamORM
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns> /// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
public IDbTransaction BeginTransaction(IsolationLevel il) public IDbTransaction BeginTransaction(IsolationLevel il)
{ {
return BeginTransaction(il, null, null); return BeginTransaction(il, null);
}
/// <summary>Begins a database transaction with the specified
/// <see cref="System.Data.IsolationLevel"/> value.</summary>
/// <param name="custom">Custom parameter describing transaction options.</param>
/// <returns>Returns <see cref="DynamicTransaction"/> representation.</returns>
public IDbTransaction BeginTransaction(object custom)
{
return BeginTransaction(null, custom, null);
} }
/// <summary>Changes the current database for an open Connection object.</summary> /// <summary>Changes the current database for an open Connection object.</summary>
@@ -148,7 +136,7 @@ namespace DynamORM
/// to be used after a connection is opened.</summary> /// to be used after a connection is opened.</summary>
public string Database public string Database
{ {
get { return Connection.Database; } get { throw new NotImplementedException(); }
} }
/// <summary>Gets the current state of the connection.</summary> /// <summary>Gets the current state of the connection.</summary>
@@ -159,19 +147,11 @@ namespace DynamORM
#endregion IDbConnection Members #endregion IDbConnection Members
#region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with freeing, /// <summary>Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.</summary> /// releasing, or resetting unmanaged resources.</summary>
public void Dispose() public void Dispose()
{ {
_db.Close(Connection); _db.Close(Connection);
IsDisposed = true;
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -50,14 +50,11 @@ namespace DynamORM
/// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary> /// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary>
SupportLimitOffset = 0x00000040, SupportLimitOffset = 0x00000040,
/// <summary>Database supports limit offset syntax (SELECT FIRST x SKIP y ... FROM ...).</summary>
SupportFirstSkip = 0x00000020,
/// <summary>Database support standard schema.</summary> /// <summary>Database support standard schema.</summary>
SupportSchema = 0x00000010, SupportSchema = 0x00000010,
/// <summary>Database support stored procedures (EXEC procedure ...).</summary> /// <summary>Database support stored procedures (EXEC procedure ...).</summary>
SupportStoredProcedures = 0x00000100, SupportStoredProcedures = 0x00000020,
/// <summary>Debug option allowing to enable command dumps by default.</summary> /// <summary>Debug option allowing to enable command dumps by default.</summary>
DumpCommands = 0x01000000, DumpCommands = 0x01000000,

View File

@@ -1,204 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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;
using System.Collections.Generic;
using System.Dynamic;
namespace DynamORM
{
/// <summary>Dynamic expando is a simple and temporary class to resolve memory leaks inside ExpandoObject.</summary>
public class DynamicExpando : DynamicObject, IDictionary<string, object>, ICollection<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable
{
/// <summary>Class containing information about last accessed property of dynamic object.</summary>
public class PropertyAccess
{
/// <summary>Enum describing type of access to object.</summary>
public enum TypeOfAccess
{
/// <summary>Get member.</summary>
Get,
/// <summary>Set member.</summary>
Set,
}
/// <summary>Gets the type of operation.</summary>
public TypeOfAccess Operation { get; internal set; }
/// <summary>Gets the name of property.</summary>
public string Name { get; internal set; }
/// <summary>Gets the type from binder.</summary>
public Type RequestedType { get; internal set; }
/// <summary>Gets the type of value stored in object.</summary>
public Type Type { get; internal set; }
/// <summary>Gets the value stored in object.</summary>
public object Value { get; internal set; }
/// <summary>Gets the last access time.</summary>
public long Ticks { get; internal set; }
}
private Dictionary<string, object> _data = new Dictionary<string, object>();
private PropertyAccess _lastProp = new PropertyAccess();
/// <summary>Initializes a new instance of the <see cref="DynamicExpando"/> class.</summary>
public DynamicExpando()
{
}
/// <summary>Gets the last accesses property.</summary>
/// <returns>Description of last accessed property.</returns>
public PropertyAccess GetLastAccessesProperty()
{
return _lastProp;
}
/// <summary>Tries to get member value.</summary>
/// <returns>Returns <c>true</c>, if get member was tried, <c>false</c> otherwise.</returns>
/// <param name="binder">The context binder.</param>
/// <param name="result">The invocation result.</param>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _data.TryGetValue(binder.Name);
_lastProp.Operation = PropertyAccess.TypeOfAccess.Get;
_lastProp.RequestedType = binder.ReturnType;
_lastProp.Name = binder.Name;
_lastProp.Value = result;
_lastProp.Type = result == null ? typeof(void) : result.GetType();
_lastProp.Ticks = DateTime.Now.Ticks;
return true;
}
/// <summary>Tries to set member.</summary>
/// <returns>Returns <c>true</c>, if set member was tried, <c>false</c> otherwise.</returns>
/// <param name="binder">The context binder.</param>
/// <param name="value">Value which will be set.</param>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_data[binder.Name] = value;
_lastProp.Operation = PropertyAccess.TypeOfAccess.Set;
_lastProp.RequestedType = binder.ReturnType;
_lastProp.Name = binder.Name;
_lastProp.Value = value;
_lastProp.Type = value == null ? typeof(void) : value.GetType();
_lastProp.Ticks = DateTime.Now.Ticks;
return true;
}
#region IDictionary implementation
bool IDictionary<string, object>.ContainsKey(string key)
{
return _data.ContainsKey(key);
}
void IDictionary<string, object>.Add(string key, object value)
{
_data.Add(key, value);
}
bool IDictionary<string, object>.Remove(string key)
{
return _data.Remove(key);
}
bool IDictionary<string, object>.TryGetValue(string key, out object value)
{
return _data.TryGetValue(key, out value);
}
object IDictionary<string, object>.this[string index] { get { return _data[index]; } set { _data[index] = value; } }
ICollection<string> IDictionary<string, object>.Keys { get { return _data.Keys; } }
ICollection<object> IDictionary<string, object>.Values { get { return _data.Values; } }
#endregion IDictionary implementation
#region ICollection implementation
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
((ICollection<KeyValuePair<string, object>>)_data).Add(item);
}
void ICollection<KeyValuePair<string, object>>.Clear()
{
_data.Clear();
}
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
{
return ((ICollection<KeyValuePair<string, object>>)_data).Contains(item);
}
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, object>>)_data).CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
{
return ((ICollection<KeyValuePair<string, object>>)_data).Remove(item);
}
int ICollection<KeyValuePair<string, object>>.Count { get { return _data.Count; } }
bool ICollection<KeyValuePair<string, object>>.IsReadOnly { get { return ((ICollection<KeyValuePair<string, object>>)_data).IsReadOnly; } }
#endregion ICollection implementation
#region IEnumerable implementation
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
{
return _data.GetEnumerator();
}
#endregion IEnumerable implementation
#region IEnumerable implementation
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_data).GetEnumerator();
}
#endregion IEnumerable implementation
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,274 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.Linq;
using DynamORM.Helpers;
using DynamORM.Mapper;
namespace DynamORM
{
/// <summary>Dynamic procedure invoker.</summary>
/// <remarks>Unfortunately I can use <c>out</c> and <c>ref</c> to
/// return parameters, <see href="http://stackoverflow.com/questions/2475310/c-sharp-4-0-dynamic-doesnt-set-ref-out-arguments"/>.
/// But see example for workaround. If there aren't any return parameters execution will return scalar value.
/// Scalar result is not converted to provided generic type (if any). For output results there is possibility to map to provided class.
/// </remarks><example>You still can use out, return and both way parameters by providing variable prefix:<code>
/// dynamic res = db.Procedures.sp_Test_Scalar_In_Out(inp: Guid.NewGuid(), out_outp: Guid.Empty);
/// Console.Out.WriteLine(res.outp);</code>
/// Prefixes: <c>out_</c>, <c>ret_</c>, <c>both_</c>. Result will contain field without prefix.
/// Here is an example with result class:<code>
/// public class ProcResult { [Column("outp")] public Guid Output { get; set; } }
/// ProcResult res4 = db.Procedures.sp_Test_Scalar_In_Out&lt;ProcResult&gt;(inp: Guid.NewGuid(), out_outp: Guid.Empty) as ProcResult;
/// </code>As you can se, you can use mapper to do job for you.</example>
public class DynamicProcedureInvoker : DynamicObject, IDisposable
{
private DynamicDatabase _db;
private List<string> _prefixes;
internal DynamicProcedureInvoker(DynamicDatabase db, List<string> prefixes = null)
{
_prefixes = prefixes;
_db = db;
}
/// <summary>This is where the magic begins.</summary>
/// <param name="binder">Binder to create owner.</param>
/// <param name="result">Binder invoke result.</param>
/// <returns>Returns <c>true</c> if invoke was performed.</returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
List<string> pref = new List<string>();
if (_prefixes != null)
pref.AddRange(_prefixes);
pref.Add(binder.Name);
result = new DynamicProcedureInvoker(_db, pref);
return true;
}
/// <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
CallInfo info = binder.CallInfo;
// Get generic types
IList<Type> types = binder.GetGenericTypeArguments();
Dictionary<string, int> retParams = null;
using (IDbConnection con = _db.Open())
using (IDbCommand cmd = con.CreateCommand())
{
if (_prefixes == null || _prefixes.Count == 0)
cmd.SetCommand(CommandType.StoredProcedure, binder.Name);
else
cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), binder.Name));
#region Prepare arguments
int alen = args.Length;
if (alen > 0)
{
for (int i = 0; i < alen; i++)
{
object arg = args[i];
if (arg is DynamicExpando)
cmd.AddParameters(_db, (DynamicExpando)arg);
else if (arg is ExpandoObject)
cmd.AddParameters(_db, (ExpandoObject)arg);
else
{
if (info.ArgumentNames.Count > i && !string.IsNullOrEmpty(info.ArgumentNames[i]))
{
bool isOut = info.ArgumentNames[i].StartsWith("out_");
bool isRet = info.ArgumentNames[i].StartsWith("ret_");
bool isBoth = info.ArgumentNames[i].StartsWith("both_");
string paramName = isOut || isRet ?
info.ArgumentNames[i].Substring(4) :
isBoth ? info.ArgumentNames[i].Substring(5) :
info.ArgumentNames[i];
if (isOut || isBoth || isRet)
{
if (retParams == null)
retParams = new Dictionary<string, int>();
retParams.Add(paramName, cmd.Parameters.Count);
}
cmd.AddParameter(
_db.GetParameterName(paramName),
isOut ? ParameterDirection.Output :
isRet ? ParameterDirection.ReturnValue :
isBoth ? ParameterDirection.InputOutput : ParameterDirection.Input,
arg == null ? DbType.String : arg.GetType().ToDbType(), 0, isOut ? DBNull.Value : arg);
}
else
cmd.AddParameter(_db, arg);
}
}
}
#endregion Prepare arguments
#region Get main result
object mainResult = null;
if (types.Count > 0)
{
mainResult = types[0].GetDefaultValue();
if (types[0] == typeof(IDataReader))
{
using (IDataReader rdr = cmd.ExecuteReader())
mainResult = rdr.CachedReader();
}
else if (types[0].IsGenericEnumerable())
{
Type argType = types[0].GetGenericArguments().First();
if (argType == typeof(object))
{
IDataReader cache = null;
using (IDataReader rdr = cmd.ExecuteReader())
cache = rdr.CachedReader();
mainResult = cache.EnumerateReader().ToList();
}
else if (argType.IsValueType)
{
Type listType = typeof(List<>).MakeGenericType(new Type[] { argType });
IList listInstance = (IList)Activator.CreateInstance(listType);
object defVal = listType.GetDefaultValue();
IDataReader cache = null;
using (IDataReader rdr = cmd.ExecuteReader())
cache = rdr.CachedReader();
while (cache.Read())
listInstance.Add(cache[0] == DBNull.Value ? defVal : argType.CastObject(cache[0]));
mainResult = listInstance;
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(argType);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", argType.ToString()));
IDataReader cache = null;
using (IDataReader rdr = cmd.ExecuteReader())
cache = rdr.CachedReader();
mainResult = cache.EnumerateReader().MapEnumerable(argType).ToList();
}
}
else if (types[0].IsValueType)
{
mainResult = cmd.ExecuteScalar();
if (mainResult != DBNull.Value)
mainResult = types[0].CastObject(mainResult);
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[0]);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", types[0].ToString()));
using (IDataReader rdr = cmd.ExecuteReader())
if (rdr.Read())
mainResult = (rdr.ToDynamic() as object).Map(types[0]);
else
mainResult = null;
}
}
else
mainResult = cmd.ExecuteNonQuery();
#endregion Get main result
#region Handle out params
if (retParams != null)
{
Dictionary<string, object> res = new Dictionary<string, object>();
if (mainResult != null)
{
if (mainResult == DBNull.Value)
res.Add(binder.Name, null);
else
res.Add(binder.Name, mainResult);
}
foreach (KeyValuePair<string, int> pos in retParams)
res.Add(pos.Key, ((IDbDataParameter)cmd.Parameters[pos.Value]).Value);
if (types.Count > 1)
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[1]);
if (mapper != null)
result = mapper.Create(res.ToDynamic());
else
result = res.ToDynamic();
}
else
result = res.ToDynamic();
}
else
result = mainResult;
#endregion Handle out params
}
return true;
}
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
}
}
}

View File

@@ -1,102 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Runtime.Serialization;
namespace DynamORM
{
/// <summary>Dynamic query exception.</summary>
[Serializable]
public class DynamicQueryException : Exception, ISerializable
{
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(IDbCommand command = null)
: base(string.Format("Error executing command.{0}{1}", Environment.NewLine, command != null ? command.DumpToString() : string.Empty))
{
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="message">The message.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(string message, IDbCommand command = null)
: base(string.Format("{0}{1}{2}", message, Environment.NewLine, command != null ? command.DumpToString() : string.Empty))
{
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="innerException">The inner exception.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(Exception innerException, IDbCommand command = null)
: base(string.Format("Error executing command.{0}{1}", Environment.NewLine, command != null ? command.DumpToString() : string.Empty), innerException)
{
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="message">The message.</param>
/// <param name="innerException">The inner exception.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(string message, Exception innerException, IDbCommand command = null)
: base(string.Format("{0}{1}{2}", message, Environment.NewLine, command != null ? command.DumpToString() : string.Empty), innerException)
{
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" />
/// that contains contextual information about the source or destination.</param>
public DynamicQueryException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>When overridden in a derived class, sets the
/// <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// with information about the exception.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" />
/// that contains contextual information about the source or destination.</param>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SerializationFormatter" />
/// </PermissionSet>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -45,9 +45,6 @@ namespace DynamORM
/// <summary>Gets or sets a value indicating whether column should have unique value.</summary> /// <summary>Gets or sets a value indicating whether column should have unique value.</summary>
public bool IsUnique { get; set; } public bool IsUnique { get; set; }
/// <summary>Gets or sets a value indicating whether column allows null or not.</summary>
public bool AllowNull { get; set; }
/// <summary>Gets or sets column size.</summary> /// <summary>Gets or sets column size.</summary>
public int Size { get; set; } public int Size { get; set; }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -28,19 +28,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Dynamic; using System.Dynamic;
using System.Linq; using System.Linq;
using DynamORM.Builders; using DynamORM.Builders;
using DynamORM.Builders.Extensions;
using DynamORM.Builders.Implementation;
using DynamORM.Helpers; using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper; using DynamORM.Mapper;
namespace DynamORM namespace DynamORM
{ {
#if !DYNAMORM_OMMIT_OLDSYNTAX
/// <summary>Dynamic table is a simple ORM using dynamic objects.</summary> /// <summary>Dynamic table is a simple ORM using dynamic objects.</summary>
/// <example> /// <example>
/// <para>Assume that we have a table representing Users class.</para> /// <para>Assume that we have a table representing Users class.</para>
@@ -195,7 +191,7 @@ namespace DynamORM
/// });</code> /// });</code>
/// <code>x.Delete(where: new { id = 14, code = 14 });</code> /// <code>x.Delete(where: new { id = 14, code = 14 });</code>
/// </example> /// </example>
public class DynamicTable : DynamicObject, IExtendedDisposable, ICloneable public class DynamicTable : DynamicObject, IDisposable, ICloneable
{ {
private static HashSet<string> _allowedCommands = new HashSet<string> private static HashSet<string> _allowedCommands = new HashSet<string>
{ {
@@ -215,20 +211,6 @@ namespace DynamORM
/// <summary>Gets name of table.</summary> /// <summary>Gets name of table.</summary>
public virtual string TableName { get; private set; } public virtual string TableName { get; private set; }
/// <summary>Gets name of owner.</summary>
public virtual string OwnerName { get; private set; }
/// <summary>Gets full name of table containing owner and table name.</summary>
public virtual string FullName
{
get
{
return string.IsNullOrEmpty(TableName) ? null : string.IsNullOrEmpty(OwnerName) ?
Database.DecorateName(TableName) :
string.Format("{0}.{1}", Database.DecorateName(OwnerName), Database.DecorateName(TableName));
}
}
/// <summary>Gets table schema.</summary> /// <summary>Gets table schema.</summary>
/// <remarks>If database doesn't support schema, only key columns are listed here.</remarks> /// <remarks>If database doesn't support schema, only key columns are listed here.</remarks>
public virtual Dictionary<string, DynamicSchemaColumn> Schema { get; private set; } public virtual Dictionary<string, DynamicSchemaColumn> Schema { get; private set; }
@@ -240,14 +222,11 @@ namespace DynamORM
/// <summary>Initializes a new instance of the <see cref="DynamicTable" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="DynamicTable" /> class.</summary>
/// <param name="database">Database and connection management.</param> /// <param name="database">Database and connection management.</param>
/// <param name="table">Table name.</param> /// <param name="table">Table name.</param>
/// <param name="owner">Owner of the table.</param>
/// <param name="keys">Override keys in schema.</param> /// <param name="keys">Override keys in schema.</param>
public DynamicTable(DynamicDatabase database, string table = "", string owner = "", string[] keys = null) public DynamicTable(DynamicDatabase database, string table = "", string[] keys = null)
{ {
IsDisposed = false;
Database = database; Database = database;
TableName = Database.StripName(table); TableName = table;
OwnerName = Database.StripName(owner);
TableType = null; TableType = null;
BuildAndCacheSchema(keys); BuildAndCacheSchema(keys);
@@ -262,20 +241,15 @@ namespace DynamORM
if (type == null) if (type == null)
throw new ArgumentNullException("type", "Type can't be null."); throw new ArgumentNullException("type", "Type can't be null.");
IsDisposed = false;
Database = database; Database = database;
TableType = type; TableType = type;
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); var mapper = DynamicMapperCache.GetMapper(type);
if (mapper != null) if (mapper != null)
{
TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
type.Name : mapper.Table.Name; type.Name : mapper.Table.Name;
OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ?
null : mapper.Table.Owner;
}
BuildAndCacheSchema(keys); BuildAndCacheSchema(keys);
} }
@@ -287,17 +261,17 @@ namespace DynamORM
Dictionary<string, DynamicSchemaColumn> schema = null; Dictionary<string, DynamicSchemaColumn> schema = null;
schema = Database.GetSchema(TableType) ?? schema = Database.GetSchema(TableType) ??
Database.GetSchema(TableName, OwnerName); Database.GetSchema(TableName);
#region Fill currrent table schema #region Fill currrent table schema
if (keys == null && TableType != null) if (keys == null && TableType != null)
{ {
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(TableType); var mapper = DynamicMapperCache.GetMapper(TableType);
if (mapper != null) if (mapper != null)
{ {
IEnumerable<string> k = mapper.ColumnsMap.Where(p => p.Value.Column != null && p.Value.Column.IsKey).Select(p => p.Key); var k = mapper.ColumnsMap.Where(p => p.Value.Column != null && p.Value.Column.IsKey).Select(p => p.Key);
if (k.Count() > 0) if (k.Count() > 0)
keys = k.ToArray(); keys = k.ToArray();
} }
@@ -346,7 +320,16 @@ namespace DynamORM
/// <returns>Enumerator of objects expanded from query.</returns> /// <returns>Enumerator of objects expanded from query.</returns>
public virtual IEnumerable<dynamic> Query(string sql, params object[] args) public virtual IEnumerable<dynamic> Query(string sql, params object[] args)
{ {
return Database.Query(sql, 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> /// <summary>Enumerate the reader and yield the result.</summary>
@@ -354,20 +337,22 @@ namespace DynamORM
/// <returns>Enumerator of objects expanded from query.</returns> /// <returns>Enumerator of objects expanded from query.</returns>
public virtual IEnumerable<dynamic> Query(IDynamicQueryBuilder builder) public virtual IEnumerable<dynamic> Query(IDynamicQueryBuilder builder)
{ {
return Database.Query(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> /// <summary>Create new <see cref="DynamicSelectQueryBuilder"/>.</summary>
/// <returns>New <see cref="DynamicSelectQueryBuilder"/> instance.</returns> /// <returns>New <see cref="DynamicSelectQueryBuilder"/> instance.</returns>
public virtual IDynamicSelectQueryBuilder Query() public virtual DynamicSelectQueryBuilder Query()
{ {
IDynamicSelectQueryBuilder builder = new DynamicSelectQueryBuilder(this.Database); return new DynamicSelectQueryBuilder(this);
string name = this.FullName;
if (!string.IsNullOrEmpty(name))
builder.From(x => name);
return builder;
} }
/// <summary>Returns a single result.</summary> /// <summary>Returns a single result.</summary>
@@ -378,7 +363,13 @@ namespace DynamORM
/// <returns>Result of a query.</returns> /// <returns>Result of a query.</returns>
public virtual object Scalar(string sql, params object[] args) public virtual object Scalar(string sql, params object[] args)
{ {
return Database.Scalar(sql, 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> /// <summary>Returns a single result.</summary>
@@ -386,68 +377,31 @@ namespace DynamORM
/// <returns>Result of a query.</returns> /// <returns>Result of a query.</returns>
public virtual object Scalar(IDynamicQueryBuilder builder) public virtual object Scalar(IDynamicQueryBuilder builder)
{ {
return Database.Scalar(builder); using (var con = Database.Open())
} using (var cmd = con.CreateCommand())
{
#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE return cmd
.SetCommand(builder)
/// <summary>Returns a single result.</summary> .ExecuteScalar();
/// <typeparam name="T">What kind of result is expected.</typeparam> }
/// <param name="sql">SQL query containing numbered parameters in format provided by
/// <see cref="DynamicDatabase.GetParameterName(object)"/> methods. Also names should be formatted with
/// <see cref="DynamicDatabase.DecorateName(string)"/> method.</param>
/// <param name="args">Arguments (parameters).</param>
/// <returns>Result of a query.</returns>
public virtual T ScalarAs<T>(string sql, params object[] args)
{
return Database.ScalarAs<T>(sql, args);
}
/// <summary>Returns a single result.</summary>
/// <typeparam name="T">What kind of result is expected.</typeparam>
/// <param name="builder">Command builder.</param>
/// <param name="defaultValue">Default value.</param>
/// <returns>Result of a query.</returns>
public virtual T ScalarAs<T>(IDynamicQueryBuilder builder, T defaultValue = default(T))
{
return Database.ScalarAs<T>(builder, defaultValue);
}
#endif
/// <summary>Execute stored procedure.</summary>
/// <param name="procName">Name of stored procedure to execute.</param>
/// <returns>Number of affected rows.</returns>
public virtual int Procedure(string procName)
{
return Database.Procedure(procName);
} }
/// <summary>Execute stored procedure.</summary> /// <summary>Execute stored procedure.</summary>
/// <param name="procName">Name of stored procedure to execute.</param> /// <param name="procName">Name of stored procedure to execute.</param>
/// <param name="args">Arguments (parameters) in form of expando object.</param> /// <param name="args">Arguments (parameters) in form of expando object.</param>
/// <returns>Number of affected rows.</returns> /// <returns>Number of affected rows.</returns>
public virtual int Procedure(string procName, params object[] args) public virtual int Procedure(string procName, ExpandoObject args = null)
{ {
return Database.Procedure(procName, args); if ((Database.Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
} throw new InvalidOperationException("Database connection desn't support stored procedures.");
/// <summary>Execute stored procedure.</summary> using (var con = Database.Open())
/// <param name="procName">Name of stored procedure to execute.</param> using (var cmd = con.CreateCommand())
/// <param name="args">Arguments (parameters) in form of expando object.</param> {
/// <returns>Number of affected rows.</returns> return cmd
public virtual int Procedure(string procName, DynamicExpando args) .SetCommand(CommandType.StoredProcedure, procName).AddParameters(Database, args)
{ .ExecuteNonQuery();
return Database.Procedure(procName, args); }
}
/// <summary>Execute stored procedure.</summary>
/// <param name="procName">Name of stored procedure to execute.</param>
/// <param name="args">Arguments (parameters) in form of expando object.</param>
/// <returns>Number of affected rows.</returns>
public virtual int Procedure(string procName, ExpandoObject args)
{
return Database.Procedure(procName, args);
} }
/// <summary>Execute non query.</summary> /// <summary>Execute non query.</summary>
@@ -458,7 +412,13 @@ namespace DynamORM
/// <returns>Number of affected rows.</returns> /// <returns>Number of affected rows.</returns>
public virtual int Execute(string sql, params object[] args) public virtual int Execute(string sql, params object[] args)
{ {
return Database.Execute(sql, args); using (var con = Database.Open())
using (var cmd = con.CreateCommand())
{
return cmd
.SetCommand(sql).AddParameters(Database, args)
.ExecuteNonQuery();
}
} }
/// <summary>Execute non query.</summary> /// <summary>Execute non query.</summary>
@@ -466,15 +426,41 @@ namespace DynamORM
/// <returns>Number of affected rows.</returns> /// <returns>Number of affected rows.</returns>
public virtual int Execute(IDynamicQueryBuilder builder) public virtual int Execute(IDynamicQueryBuilder builder)
{ {
return Database.Execute(builder); using (var con = Database.Open())
using (var cmd = con.CreateCommand())
{
return cmd
.SetCommand(builder)
.ExecuteNonQuery();
}
} }
/// <summary>Execute non query.</summary> /// <summary>Execute non query.</summary>
/// <param name="builders">Command builders.</param> /// <param name="builers">Command builders.</param>
/// <returns>Number of affected rows.</returns> /// <returns>Number of affected rows.</returns>
public virtual int Execute(IDynamicQueryBuilder[] builders) public virtual int Execute(IDynamicQueryBuilder[] builers)
{ {
return Database.Execute(builders); 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 #endregion Basic Queries
@@ -483,9 +469,9 @@ namespace DynamORM
/// <summary>Create new <see cref="DynamicInsertQueryBuilder"/>.</summary> /// <summary>Create new <see cref="DynamicInsertQueryBuilder"/>.</summary>
/// <returns>New <see cref="DynamicInsertQueryBuilder"/> instance.</returns> /// <returns>New <see cref="DynamicInsertQueryBuilder"/> instance.</returns>
public dynamic Insert() public DynamicInsertQueryBuilder Insert()
{ {
return new DynamicProxy<IDynamicInsertQueryBuilder>(new DynamicInsertQueryBuilder(this.Database, this.FullName)); return new DynamicInsertQueryBuilder(this);
} }
/// <summary>Adds a record to the database. You can pass in an Anonymous object, an <see cref="ExpandoObject"/>, /// <summary>Adds a record to the database. You can pass in an Anonymous object, an <see cref="ExpandoObject"/>,
@@ -506,9 +492,9 @@ namespace DynamORM
/// <summary>Create new <see cref="DynamicUpdateQueryBuilder"/>.</summary> /// <summary>Create new <see cref="DynamicUpdateQueryBuilder"/>.</summary>
/// <returns>New <see cref="DynamicUpdateQueryBuilder"/> instance.</returns> /// <returns>New <see cref="DynamicUpdateQueryBuilder"/> instance.</returns>
public dynamic Update() public DynamicUpdateQueryBuilder Update()
{ {
return new DynamicProxy<IDynamicUpdateQueryBuilder>(new DynamicUpdateQueryBuilder(this.Database, this.FullName)); return new DynamicUpdateQueryBuilder(this);
} }
/// <summary>Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject, /// <summary>Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject,
@@ -544,9 +530,9 @@ namespace DynamORM
/// <summary>Create new <see cref="DynamicDeleteQueryBuilder"/>.</summary> /// <summary>Create new <see cref="DynamicDeleteQueryBuilder"/>.</summary>
/// <returns>New <see cref="DynamicDeleteQueryBuilder"/> instance.</returns> /// <returns>New <see cref="DynamicDeleteQueryBuilder"/> instance.</returns>
public dynamic Delete() public DynamicDeleteQueryBuilder Delete()
{ {
return new DynamicProxy<IDynamicDeleteQueryBuilder>(new DynamicDeleteQueryBuilder(this.Database, this.FullName)); return new DynamicDeleteQueryBuilder(this);
} }
/// <summary>Removes a record from the database. You can pass in an Anonymous object, an <see cref="ExpandoObject"/>, /// <summary>Removes a record from the database. You can pass in an Anonymous object, an <see cref="ExpandoObject"/>,
@@ -575,16 +561,16 @@ namespace DynamORM
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{ {
// parse the method // parse the method
CallInfo info = binder.CallInfo; var info = binder.CallInfo;
// Get generic types // Get generic types
IList<Type> types = binder.GetGenericTypeArguments(); var types = binder.GetGenericTypeArguments();
// accepting named args only... SKEET! // accepting named args only... SKEET!
if (info.ArgumentNames.Count != args.Length) if (info.ArgumentNames.Count != args.Length)
throw new InvalidOperationException("Please use named arguments for this type of query - the column name, orderby, columns, etc"); throw new InvalidOperationException("Please use named arguments for this type of query - the column name, orderby, columns, etc");
string op = binder.Name; var op = binder.Name;
// Avoid strange things // Avoid strange things
if (!_allowedCommands.Contains(op)) if (!_allowedCommands.Contains(op))
@@ -614,21 +600,17 @@ namespace DynamORM
private object DynamicInsert(object[] args, CallInfo info, IList<Type> types) private object DynamicInsert(object[] args, CallInfo info, IList<Type> types)
{ {
DynamicInsertQueryBuilder builder = new DynamicInsertQueryBuilder(this.Database); var builder = new DynamicInsertQueryBuilder(this);
if (types != null && types.Count == 1) if (types != null && types.Count == 1)
HandleTypeArgument<DynamicInsertQueryBuilder>(null, info, ref types, builder, 0); HandleTypeArgument<DynamicInsertQueryBuilder>(null, info, ref types, builder, 0);
if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0)
builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema);
// loop the named args - see if we have order, columns and constraints // loop the named args - see if we have order, columns and constraints
if (info.ArgumentNames.Count > 0) if (info.ArgumentNames.Count > 0)
{ {
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
string fullName = info.ArgumentNames[i]; var name = info.ArgumentNames[i].ToLower();
string name = fullName.ToLower();
switch (name) switch (name)
{ {
@@ -649,7 +631,7 @@ namespace DynamORM
break; break;
default: default:
builder.Insert(fullName, args[i]); builder.Insert(name, args[i]);
break; break;
} }
} }
@@ -661,21 +643,17 @@ namespace DynamORM
private object DynamicUpdate(object[] args, CallInfo info, IList<Type> types) private object DynamicUpdate(object[] args, CallInfo info, IList<Type> types)
{ {
DynamicUpdateQueryBuilder builder = new DynamicUpdateQueryBuilder(this.Database); var builder = new DynamicUpdateQueryBuilder(this);
if (types != null && types.Count == 1) if (types != null && types.Count == 1)
HandleTypeArgument<DynamicUpdateQueryBuilder>(null, info, ref types, builder, 0); HandleTypeArgument<DynamicUpdateQueryBuilder>(null, info, ref types, builder, 0);
if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0)
builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema);
// loop the named args - see if we have order, columns and constraints // loop the named args - see if we have order, columns and constraints
if (info.ArgumentNames.Count > 0) if (info.ArgumentNames.Count > 0)
{ {
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
string fullName = info.ArgumentNames[i]; var name = info.ArgumentNames[i].ToLower();
string name = fullName.ToLower();
switch (name) switch (name)
{ {
@@ -704,7 +682,7 @@ namespace DynamORM
break; break;
default: default:
builder.Update(fullName, args[i]); builder.Update(name, args[i]);
break; break;
} }
} }
@@ -716,21 +694,17 @@ namespace DynamORM
private object DynamicDelete(object[] args, CallInfo info, IList<Type> types) private object DynamicDelete(object[] args, CallInfo info, IList<Type> types)
{ {
DynamicDeleteQueryBuilder builder = new DynamicDeleteQueryBuilder(this.Database); var builder = new DynamicDeleteQueryBuilder(this);
if (types != null && types.Count == 1) if (types != null && types.Count == 1)
HandleTypeArgument<DynamicDeleteQueryBuilder>(null, info, ref types, builder, 0); HandleTypeArgument<DynamicDeleteQueryBuilder>(null, info, ref types, builder, 0);
if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0)
builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema);
// loop the named args - see if we have order, columns and constraints // loop the named args - see if we have order, columns and constraints
if (info.ArgumentNames.Count > 0) if (info.ArgumentNames.Count > 0)
{ {
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
string fullName = info.ArgumentNames[i]; var name = info.ArgumentNames[i].ToLower();
string name = fullName.ToLower();
switch (name) switch (name)
{ {
@@ -755,7 +729,7 @@ namespace DynamORM
break; break;
default: default:
builder.Where(fullName, args[i]); builder.Where(name, args[i]);
break; break;
} }
} }
@@ -768,76 +742,55 @@ namespace DynamORM
private object DynamicQuery(object[] args, CallInfo info, string op, IList<Type> types) private object DynamicQuery(object[] args, CallInfo info, string op, IList<Type> types)
{ {
object result; object result;
DynamicSelectQueryBuilder builder = new DynamicSelectQueryBuilder(this.Database); var builder = new DynamicSelectQueryBuilder(this);
if (types != null && types.Count == 1) if (types != null && types.Count == 1)
HandleTypeArgument<DynamicSelectQueryBuilder>(null, info, ref types, builder, 0); HandleTypeArgument<DynamicSelectQueryBuilder>(null, info, ref types, builder, 0);
if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0)
builder.From(x => string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName));
// loop the named args - see if we have order, columns and constraints // loop the named args - see if we have order, columns and constraints
if (info.ArgumentNames.Count > 0) if (info.ArgumentNames.Count > 0)
{ {
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
string fullName = info.ArgumentNames[i]; var name = info.ArgumentNames[i].ToLower();
string name = fullName.ToLower();
// TODO: Make this nicer // TODO: Make this nicer
switch (name) switch (name)
{ {
case "order": case "order":
if (args[i] is string) if (args[i] is string)
builder.OrderByColumn(((string)args[i]).Split(',')); builder.OrderBy(((string)args[i]).Split(','));
else if (args[i] is string[]) else if (args[i] is string[])
builder.OrderByColumn(args[i] as string); builder.OrderBy(args[i] as string);
else if (args[i] is DynamicColumn[]) else if (args[i] is DynamicColumn[])
builder.OrderByColumn((DynamicColumn[])args[i]); builder.OrderBy((DynamicColumn[])args[i]);
else if (args[i] is DynamicColumn) else if (args[i] is DynamicColumn)
builder.OrderByColumn((DynamicColumn)args[i]); builder.OrderBy((DynamicColumn)args[i]);
else goto default; else goto default;
break; break;
case "group": case "group":
if (args[i] is string) if (args[i] is string)
builder.GroupByColumn(((string)args[i]).Split(',')); builder.GroupBy(((string)args[i]).Split(','));
else if (args[i] is string[]) else if (args[i] is string[])
builder.GroupByColumn(args[i] as string); builder.GroupBy(args[i] as string);
else if (args[i] is DynamicColumn[]) else if (args[i] is DynamicColumn[])
builder.GroupByColumn((DynamicColumn[])args[i]); builder.GroupBy((DynamicColumn[])args[i]);
else if (args[i] is DynamicColumn) else if (args[i] is DynamicColumn)
builder.GroupByColumn((DynamicColumn)args[i]); builder.GroupBy((DynamicColumn)args[i]);
else goto default; else goto default;
break; break;
case "columns": case "columns":
{ if (args[i] is string)
string agregate = (op == "Sum" || op == "Max" || op == "Min" || op == "Avg" || op == "Count") ? builder.Select(((string)args[i]).Split(','));
op.ToUpper() : null; else if (args[i] is string[])
builder.Select(args[i] as string);
if (args[i] is string || args[i] is string[]) else if (args[i] is DynamicColumn[])
builder.SelectColumn((args[i] as String).NullOr(s => s.Split(','), args[i] as String[]) builder.Select((DynamicColumn[])args[i]);
.Select(c => else if (args[i] is DynamicColumn)
{ builder.Select((DynamicColumn)args[i]);
DynamicColumn col = DynamicColumn.ParseSelectColumn(c); else goto default;
if (string.IsNullOrEmpty(col.Aggregate))
col.Aggregate = agregate;
return col;
}).ToArray());
else if (args[i] is DynamicColumn || args[i] is DynamicColumn[])
builder.SelectColumn((args[i] as DynamicColumn).NullOr(c => new DynamicColumn[] { c }, args[i] as DynamicColumn[])
.Select(c =>
{
if (string.IsNullOrEmpty(c.Aggregate))
c.Aggregate = agregate;
return c;
}).ToArray());
else goto default;
}
break; break;
case "where": case "where":
@@ -846,7 +799,7 @@ namespace DynamORM
case "table": case "table":
if (args[i] is string) if (args[i] is string)
builder.From(x => args[i].ToString()); builder.Table(args[i].ToString());
else goto default; else goto default;
break; break;
@@ -857,15 +810,20 @@ namespace DynamORM
break; break;
default: default:
builder.Where(fullName, args[i]); builder.Where(name, args[i]);
break; break;
} }
} }
} }
if (op == "Count" && !builder.HasSelectColumns) if (op == "Count" && builder.Columns.Count == 0)
{ {
result = Scalar(builder.Select(x => x.Count())); result = Scalar(builder.Select(new DynamicColumn
{
ColumnName = "*",
Aggregate = op.ToUpper(),
Alias = "Count"
}));
if (result is long) if (result is long)
result = (int)(long)result; result = (int)(long)result;
@@ -873,23 +831,41 @@ namespace DynamORM
else if (op == "Sum" || op == "Max" || else if (op == "Sum" || op == "Max" ||
op == "Min" || op == "Avg" || op == "Count") op == "Min" || op == "Avg" || op == "Count")
{ {
if (!builder.HasSelectColumns) if (builder.Columns.Count == 0)
throw new InvalidOperationException("You must select one column to agregate."); throw new InvalidOperationException("You must select at least one column to agregate.");
result = Scalar(builder); foreach (var o in builder.Columns)
o.Aggregate = op.ToUpper();
if (op == "Count" && result is long) if (builder.Columns.Count == 1)
result = (int)(long)result; {
else if (result == DBNull.Value) result = Scalar(builder);
result = null;
if (op == "Count" && result is long)
result = (int)(long)result;
else if (result == DBNull.Value)
result = null;
}
else
{
result = Query(builder).FirstOrDefault(); // return lots
}
} }
else else
{ {
// build the SQL // build the SQL
bool justOne = op == "First" || op == "Last" || op == "Get" || op == "Single"; var justOne = op == "First" || op == "Last" || op == "Get" || op == "Single";
// Be sure to sort by DESC on selected columns // Be sure to sort by DESC on selected columns
if (justOne && !(op == "Last")) 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) if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
builder.Limit(1); builder.Limit(1);
@@ -899,7 +875,7 @@ namespace DynamORM
if (op == "Scalar") if (op == "Scalar")
{ {
if (!builder.HasSelectColumns) if (builder.Columns.Count != 1)
throw new InvalidOperationException("You must select one column in scalar statement."); throw new InvalidOperationException("You must select one column in scalar statement.");
result = Scalar(builder); result = Scalar(builder);
@@ -908,7 +884,7 @@ namespace DynamORM
{ {
if (justOne) if (justOne)
{ {
if (op == "Last") if (op == "Last" && builder.Order.Count == 0)
result = Query(builder).LastOrDefault(); // Last record fallback result = Query(builder).LastOrDefault(); // Last record fallback
else else
result = Query(builder).FirstOrDefault(); // return a single record result = Query(builder).FirstOrDefault(); // return a single record
@@ -932,7 +908,7 @@ namespace DynamORM
return result; return result;
} }
private void HandleTypeArgument<T>(object[] args, CallInfo info, ref IList<Type> types, T builder, int i) where T : DynamicQueryBuilder 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 != null)
{ {
@@ -948,7 +924,7 @@ namespace DynamORM
#endregion Universal Dynamic Invoker #endregion Universal Dynamic Invoker
#region IExtendedDisposable Members #region IDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
@@ -960,14 +936,9 @@ namespace DynamORM
Database.RemoveFromCache(this); Database.RemoveFromCache(this);
Database = null; Database = null;
} }
IsDisposed = true;
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary> #endregion IDisposable Members
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
#region ICloneable Members #region ICloneable Members
@@ -987,6 +958,4 @@ namespace DynamORM
#endregion ICloneable Members #endregion ICloneable Members
} }
#endif
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,23 +27,18 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq;
using System.Reflection;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Helper class to easy manage transaction.</summary> /// <summary>Helper class to easy manage transaction.</summary>
public class DynamicTransaction : IDbTransaction, IExtendedDisposable public class DynamicTransaction : IDbTransaction, IDisposable
{ {
private DynamicDatabase _db; private DynamicDatabase _db;
private DynamicConnection _con; private DynamicConnection _con;
private bool _singleTransaction; private bool _singleTransaction;
private Action _disposed; private Action _disposed;
private bool _isDisposed = false; private bool _operational = false;
private bool _isOperational = false;
/// <summary>Initializes a new instance of the <see cref="DynamicTransaction" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="DynamicTransaction" /> class.</summary>
/// <param name="db">Database connection manager.</param> /// <param name="db">Database connection manager.</param>
@@ -51,8 +46,7 @@ namespace DynamORM
/// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</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="il">One of the <see cref="System.Data.IsolationLevel"/> values.</param>
/// <param name="disposed">This action is invoked when transaction is disposed.</param> /// <param name="disposed">This action is invoked when transaction is disposed.</param>
/// <param name="customParams">Pass custom transaction parameters.</param> internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed)
internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed, object customParams)
{ {
_db = db; _db = db;
_con = con; _con = con;
@@ -64,39 +58,12 @@ namespace DynamORM
if (!_db.TransactionPool.ContainsKey(_con.Connection)) if (!_db.TransactionPool.ContainsKey(_con.Connection))
throw new InvalidOperationException("Can't create transaction using disposed connection."); throw new InvalidOperationException("Can't create transaction using disposed connection.");
else if (_singleTransaction && _db.TransactionPool[_con.Connection].Count > 0) else if (_singleTransaction && _db.TransactionPool[_con.Connection].Count > 0)
{ _operational = false;
_isOperational = false;
if (_db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "BEGIN TRAN [NON OPERATIONAL]");
}
else else
{ {
if (customParams != null) _db.TransactionPool[_con.Connection].Push(_con.Connection.BeginTransaction());
{
MethodInfo mi = _con.Connection.GetType().GetMethods().Where(m => m.GetParameters().Count() == 1 && m.GetParameters().First().ParameterType == customParams.GetType()).FirstOrDefault();
if (mi != null)
{
_db.TransactionPool[_con.Connection].Push((IDbTransaction)mi.Invoke(_con.Connection, new object[] { customParams, }));
if (_db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "BEGIN TRAN [CUSTOM ARGS]");
}
else
throw new MissingMethodException(string.Format("Method 'BeginTransaction' accepting parameter of type '{0}' in '{1}' not found.",
customParams.GetType().FullName, _con.Connection.GetType().FullName));
}
else
{
_db.TransactionPool[_con.Connection]
.Push(il.HasValue ? _con.Connection.BeginTransaction(il.Value) : _con.Connection.BeginTransaction());
if (_db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "BEGIN TRAN");
}
_db.PoolStamp = DateTime.Now.Ticks; _db.PoolStamp = DateTime.Now.Ticks;
_isOperational = true; _operational = true;
} }
} }
} }
@@ -106,9 +73,9 @@ namespace DynamORM
{ {
lock (_db.SyncLock) lock (_db.SyncLock)
{ {
if (_isOperational) if (_operational)
{ {
Stack<IDbTransaction> t = _db.TransactionPool.TryGetValue(_con.Connection); var t = _db.TransactionPool.TryGetValue(_con.Connection);
if (t != null && t.Count > 0) if (t != null && t.Count > 0)
{ {
@@ -118,15 +85,10 @@ namespace DynamORM
trans.Commit(); trans.Commit();
trans.Dispose(); trans.Dispose();
if (_db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "COMMIT");
} }
_isOperational = false; _operational = false;
} }
else if (!_isDisposed && _db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "COMMIT [NON OPERATIONAL]");
} }
} }
@@ -135,9 +97,9 @@ namespace DynamORM
{ {
lock (_db.SyncLock) lock (_db.SyncLock)
{ {
if (_isOperational) if (_operational)
{ {
Stack<IDbTransaction> t = _db.TransactionPool.TryGetValue(_con.Connection); var t = _db.TransactionPool.TryGetValue(_con.Connection);
if (t != null && t.Count > 0) if (t != null && t.Count > 0)
{ {
@@ -147,15 +109,10 @@ namespace DynamORM
trans.Rollback(); trans.Rollback();
trans.Dispose(); trans.Dispose();
if (_db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "ROLLBACK");
} }
_isOperational = false; _operational = false;
} }
else if (!_isDisposed && _db.DumpCommands && _db.DumpCommandDelegate != null)
_db.DumpCommandDelegate(null, "ROLLBACK [NON OPERATIONAL]");
} }
} }
@@ -168,22 +125,14 @@ namespace DynamORM
/// <summary>Gets <see cref="System.Data.IsolationLevel"/> for this transaction.</summary> /// <summary>Gets <see cref="System.Data.IsolationLevel"/> for this transaction.</summary>
public IsolationLevel IsolationLevel { get; private set; } public IsolationLevel IsolationLevel { get; private set; }
#region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose() public void Dispose()
{ {
_isDisposed = true;
Rollback(); Rollback();
if (_disposed != null) if (_disposed != null)
_disposed(); _disposed();
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get { return !_isOperational; } }
#endregion IExtendedDisposable Members
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -91,13 +91,13 @@ namespace DynamORM.Helpers
int firstCount; int firstCount;
int secondCount; int secondCount;
Dictionary<T, int> firstElementCounts = GetElementCounts(first, out firstCount); var firstElementCounts = GetElementCounts(first, out firstCount);
Dictionary<T, int> secondElementCounts = GetElementCounts(second, out secondCount); var secondElementCounts = GetElementCounts(second, out secondCount);
if (firstCount != secondCount) if (firstCount != secondCount)
return true; return true;
foreach (KeyValuePair<T, int> kvp in firstElementCounts) foreach (var kvp in firstElementCounts)
if (kvp.Value != (secondElementCounts.TryGetNullable(kvp.Key) ?? 0)) if (kvp.Value != (secondElementCounts.TryGetNullable(kvp.Key) ?? 0))
return true; return true;
@@ -106,7 +106,7 @@ namespace DynamORM.Helpers
private static Dictionary<T, int> GetElementCounts(IEnumerable<T> enumerable, out int nullCount) private static Dictionary<T, int> GetElementCounts(IEnumerable<T> enumerable, out int nullCount)
{ {
Dictionary<T, int> dictionary = new Dictionary<T, int>(); var dictionary = new Dictionary<T, int>();
nullCount = 0; nullCount = 0;
foreach (T element in enumerable) foreach (T element in enumerable)

File diff suppressed because it is too large Load Diff

View File

@@ -1,334 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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 System.Linq.Expressions;
using System.Reflection;
using DynamORM.Mapper;
namespace DynamORM.Helpers.Dynamics
{
/// <summary>Class that allows to use interfaces as dynamic objects.</summary>
/// <typeparam name="T">Type of class to proxy.</typeparam>
/// <remarks>This is temporary solution. Which allows to use builders as a dynamic type.</remarks>
public class DynamicProxy<T> : DynamicObject, IDisposable
{
private T _proxy;
private Type _type;
private Dictionary<string, DynamicPropertyInvoker> _properties;
private Dictionary<MethodInfo, Delegate> _methods;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicProxy{T}" /> class.
/// </summary>
/// <param name="proxiedObject">The object to which proxy should be created.</param>
/// <exception cref="System.ArgumentNullException">The object to which proxy should be created is null.</exception>
public DynamicProxy(T proxiedObject)
{
if (proxiedObject == null)
throw new ArgumentNullException("proxiedObject");
_proxy = proxiedObject;
_type = typeof(T);
DynamicTypeMap mapper = Mapper.DynamicMapperCache.GetMapper<T>();
_properties = mapper
.ColumnsMap
.ToDictionary(
k => k.Value.Name,
v => v.Value);
_methods = GetAllMembers(_type)
.Where(x => x is MethodInfo)
.Cast<MethodInfo>()
.Where(m => !((m.Name.StartsWith("set_") && m.ReturnType == typeof(void)) || m.Name.StartsWith("get_")))
.Where(m => !m.IsStatic && !m.IsGenericMethod)
.ToDictionary(
k => k,
v =>
{
try
{
Type type = v.ReturnType == typeof(void) ?
Expression.GetActionType(v.GetParameters().Select(t => t.ParameterType).ToArray()) :
Expression.GetDelegateType(v.GetParameters().Select(t => t.ParameterType).Concat(new[] { v.ReturnType }).ToArray());
return Delegate.CreateDelegate(type, _proxy, v.Name);
}
catch (ArgumentException)
{
return null;
}
});
}
/// <summary>Provides implementation for type conversion operations.
/// Classes derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class can override this method to specify dynamic behavior for
/// operations that convert an object from one type to another.</summary>
/// <param name="binder">Provides information about the conversion operation.
/// The binder.Type property provides the type to which the object must be
/// converted. For example, for the statement (String)sampleObject in C#
/// (CType(sampleObject, Type) in Visual Basic), where sampleObject is an
/// instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class, binder.Type returns the <see cref="T:System.String" /> type.
/// The binder.Explicit property provides information about the kind of
/// conversion that occurs. It returns true for explicit conversion and
/// false for implicit conversion.</param>
/// <param name="result">The result of the type conversion operation.</param>
/// <returns>Returns <c>true</c> if the operation is successful; otherwise, <c>false</c>.
/// If this method returns false, the run-time binder of the language determines the
/// behavior. (In most cases, a language-specific run-time exception is thrown).</returns>
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type == typeof(T))
{
result = _proxy;
return true;
}
if (_proxy != null &&
binder.Type.IsAssignableFrom(_proxy.GetType()))
{
result = _proxy;
return true;
}
return base.TryConvert(binder, out result);
}
/// <summary>Provides the implementation for operations that get member
/// values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class can override this method to specify dynamic behavior for
/// operations such as getting a value for a property.</summary>
/// <param name="binder">Provides information about the object that
/// called the dynamic operation. The binder.Name property provides
/// the name of the member on which the dynamic operation is performed.
/// For example, for the Console.WriteLine(sampleObject.SampleProperty)
/// statement, where sampleObject is an instance of the class derived
/// from the <see cref="T:System.Dynamic.DynamicObject" /> class,
/// binder.Name returns "SampleProperty". The binder.IgnoreCase property
/// specifies whether the member name is case-sensitive.</param>
/// <param name="result">The result of the get operation. For example,
/// if the method is called for a property, you can assign the property
/// value to <paramref name="result" />.</param>
/// <returns>Returns <c>true</c> if the operation is successful; otherwise,
/// <c>false</c>. If this method returns false, the run-time binder of the
/// language determines the behavior. (In most cases, a run-time exception
/// is thrown).</returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
try
{
DynamicPropertyInvoker prop = _properties.TryGetValue(binder.Name);
result = prop.NullOr(p => p.Get.NullOr(g => g(_proxy), null), null);
return prop != null && prop.Get != null;
}
catch (Exception ex)
{
throw new InvalidOperationException(string.Format("Cannot get member {0}", binder.Name), ex);
}
}
/// <summary>Provides the implementation for operations that set member
/// values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class can override this method to specify dynamic behavior for operations
/// such as setting a value for a property.</summary>
/// <param name="binder">Provides information about the object that called
/// the dynamic operation. The binder.Name property provides the name of
/// the member to which the value is being assigned. For example, for the
/// statement sampleObject.SampleProperty = "Test", where sampleObject is
/// an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class, binder.Name returns "SampleProperty". The binder.IgnoreCase
/// property specifies whether the member name is case-sensitive.</param>
/// <param name="value">The value to set to the member. For example, for
/// sampleObject.SampleProperty = "Test", where sampleObject is an instance
/// of the class derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class, the <paramref name="value" /> is "Test".</param>
/// <returns>Returns <c>true</c> if the operation is successful; otherwise,
/// <c>false</c>. If this method returns false, the run-time binder of the
/// language determines the behavior. (In most cases, a language-specific
/// run-time exception is thrown).</returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
try
{
DynamicPropertyInvoker prop = _properties.TryGetValue(binder.Name);
if (prop != null && prop.Setter != null)
{
prop.Set(_proxy, value);
return true;
}
return false;
}
catch (Exception ex)
{
throw new InvalidOperationException(string.Format("Cannot set member {0} to '{1}'", binder.Name, value), ex);
}
}
/// <summary>Provides the implementation for operations that invoke a member.
/// Classes derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class can override this method to specify dynamic behavior for
/// operations such as calling a method.</summary>
/// <param name="binder">Provides information about the dynamic operation.
/// The binder.Name property provides the name of the member on which the
/// dynamic operation is performed. For example, for the statement
/// sampleObject.SampleMethod(100), where sampleObject is an instance of
/// the class derived from the <see cref="T:System.Dynamic.DynamicObject" />
/// class, binder.Name returns "SampleMethod". The binder.IgnoreCase property
/// specifies whether the member name is case-sensitive.</param>
/// <param name="args">The arguments that are passed to the object member
/// during the invoke operation. For example, for the statement
/// sampleObject.SampleMethod(100), where sampleObject is derived from the
/// <see cref="T:System.Dynamic.DynamicObject" /> class,
/// First element of <paramref name="args" /> is equal to 100.</param>
/// <param name="result">The result of the member invocation.</param>
/// <returns>Returns <c>true</c> if the operation is successful; otherwise,
/// <c>false</c>. If this method returns false, the run-time binder of the
/// language determines the behavior. (In most cases, a language-specific
/// run-time exception is thrown).</returns>
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
return TryInvokeMethod(binder.Name, out result, args) || base.TryInvokeMember(binder, args, out result);
}
private bool TryInvokeMethod(string name, out object result, object[] args)
{
result = null;
MethodInfo mi = _methods.Keys
.Where(m => m.Name == name)
.FirstOrDefault(m =>
CompareTypes(m.GetParameters().ToArray(),
args.Select(a => a.GetType()).ToArray()));
Delegate d = _methods.TryGetValue(mi);
if (d != null)
{
result = d.DynamicInvoke(CompleteArguments(mi.GetParameters().ToArray(), args));
if (d.Method.ReturnType == _type && result is T)
result = new DynamicProxy<T>((T)result);
return true;
}
else if (mi != null)
{
result = mi.Invoke(_proxy, CompleteArguments(mi.GetParameters().ToArray(), args));
if (mi.ReturnType == _type && result is T)
result = new DynamicProxy<T>((T)result);
return true;
}
return false;
}
private bool CompareTypes(ParameterInfo[] parameters, Type[] types)
{
if (parameters.Length < types.Length || parameters.Count(p => !p.IsOptional) > types.Length)
return false;
for (int i = 0; i < types.Length; i++)
if (types[i] != parameters[i].ParameterType && !parameters[i].ParameterType.IsAssignableFrom(types[i]))
return false;
return true;
}
private object[] CompleteArguments(ParameterInfo[] parameters, object[] arguments)
{
return arguments.Concat(parameters.Skip(arguments.Length).Select(p => p.DefaultValue)).ToArray();
}
private IEnumerable<MemberInfo> GetAllMembers(Type type)
{
if (type.IsInterface)
{
List<MemberInfo> members = new List<MemberInfo>();
List<Type> considered = new List<Type>();
Queue<Type> queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
Type subType = queue.Dequeue();
foreach (Type subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface)) continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
MemberInfo[] typeProperties = subType.GetMembers(
BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance);
IEnumerable<MemberInfo> newPropertyInfos = typeProperties
.Where(x => !members.Contains(x));
members.InsertRange(0, newPropertyInfos);
}
return members;
}
return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
}
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
object res;
TryInvokeMethod("Dispose", out res, new object[] { });
_properties.Clear();
_methods = null;
_properties = null;
_type = null;
_proxy = default(T);
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,7 @@ namespace DynamORM.Helpers
// HACK: Creating binders assuming types are correct... this may fail. // HACK: Creating binders assuming types are correct... this may fail.
if (IsMono) if (IsMono)
{ {
Type binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder"); var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder");
if (binderType != null) if (binderType != null)
{ {
@@ -76,16 +76,16 @@ namespace DynamORM.Helpers
} }
else else
{ {
Type inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null) if (inter != null)
{ {
PropertyInfo prop = inter.GetProperty("TypeArguments"); var prop = inter.GetProperty("TypeArguments");
if (!prop.CanRead) if (!prop.CanRead)
return null; return null;
ParameterExpression objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o"); var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o");
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>( return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
Expression.TypeAs( Expression.TypeAs(
@@ -121,7 +121,7 @@ namespace DynamORM.Helpers
// In mono this is trivial. // In mono this is trivial.
// First we get field info. // First we get field info.
FieldInfo field = binder.GetType().GetField("typeArguments", BindingFlags.Instance | var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
// If this was a success get and return it's value // If this was a success get and return it's value
@@ -134,12 +134,12 @@ namespace DynamORM.Helpers
// In this case, we need more aerobic :D // In this case, we need more aerobic :D
// First, get the interface // First, get the interface
Type inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null) if (inter != null)
{ {
// Now get property. // Now get property.
PropertyInfo prop = inter.GetProperty("TypeArguments"); var prop = inter.GetProperty("TypeArguments");
// If we have a property, return it's value // If we have a property, return it's value
if (prop != null) if (prop != null)

View File

@@ -1,44 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Helpers
{
/// <summary>Extends <see cref="IDisposable"/> interface.</summary>
public interface IExtendedDisposable : IDisposable
{
/// <summary>
/// Gets a value indicating whether this instance is disposed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
/// </value>
bool IsDisposed { get; }
}
}

View File

@@ -1,39 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.
*/
namespace DynamORM.Helpers
{
/// <summary>Extends <see cref="IExtendedDisposable"/> interface.</summary>
public interface IFinalizerDisposable : IExtendedDisposable
{
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
/// <param name="disposing">If set to <c>true</c> dispose object.</param>
void Dispose(bool disposing);
}
}

View File

@@ -1,332 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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;
using System.Reflection;
using System.Text;
namespace DynamORM.Helpers
{
/// <summary>Class containing useful string extensions.</summary>
internal static class StringExtensions
{
static StringExtensions()
{
InvalidMultipartMemberChars = _InvalidMultipartMemberChars.ToCharArray();
InvalidMemberChars = _InvalidMemberChars.ToCharArray();
}
private static readonly string _InvalidMultipartMemberChars = " +-*/^%[]{}()!\"\\&=?¿";
private static readonly string _InvalidMemberChars = "." + _InvalidMultipartMemberChars;
/// <summary>
/// Gets an array with some invalid characters that cannot be used with multipart names for class members.
/// </summary>
public static char[] InvalidMultipartMemberChars { get; private set; }
/// <summary>
/// Gets an array with some invalid characters that cannot be used with names for class members.
/// </summary>
public static char[] InvalidMemberChars { get; private set; }
/// <summary>
/// Provides with an alternate and generic way to obtain an alternate string representation for this instance,
/// applying the following rules:
/// <para>- Null values are returned as with the <paramref name="nullString"/> value, or a null object.</para>
/// <para>- Enum values are translated into their string representation.</para>
/// <para>- If the type has override the 'ToString' method then it is used.</para>
/// <para>- If it is a dictionary, then a collection of key/value pairs where the value part is also translated.</para>
/// <para>- If it is a collection, then a collection of value items also translated.</para>
/// <para>- If it has public public properties (or if not, if it has public fields), the collection of name/value
/// pairs, with the values translated.</para>
/// <para>- Finally it falls back to the standard 'type.FullName' mechanism.</para>
/// </summary>
/// <param name="obj">The object to obtain its alternate string representation from.</param>
/// <param name="brackets">The brackets to use if needed. If not null it must be at least a 2-chars' array containing
/// the opening and closing brackets.</param>
/// <param name="nullString">Representation of null string..</param>
/// <returns>The alternate string representation of this object.</returns>
public static string Sketch(this object obj, char[] brackets = null, string nullString = "(null)")
{
if (obj == null) return nullString;
if (obj is string) return (string)obj;
Type type = obj.GetType();
if (type.IsEnum) return obj.ToString();
// If the ToString() method has been overriden (by the type itself, or by its parents), let's use it...
MethodInfo method = type.GetMethod("ToString", Type.EmptyTypes);
if (method.DeclaringType != typeof(object)) return obj.ToString();
// For alll other cases...
StringBuilder sb = new StringBuilder();
bool first = true;
// Dictionaries...
if (obj is IDictionary)
{
if (brackets == null || brackets.Length < 2)
brackets = "[]".ToCharArray();
sb.AppendFormat("{0}", brackets[0]); first = true; foreach (DictionaryEntry kvp in (IDictionary)obj)
{
if (!first) sb.Append(", "); else first = false;
sb.AppendFormat("'{0}'='{1}'", kvp.Key.Sketch(), kvp.Value.Sketch());
}
sb.AppendFormat("{0}", brackets[1]);
return sb.ToString();
}
// IEnumerables...
IEnumerator ator = null;
if (obj is IEnumerable)
ator = ((IEnumerable)obj).GetEnumerator();
else
{
method = type.GetMethod("GetEnumerator", Type.EmptyTypes);
if (method != null)
ator = (IEnumerator)method.Invoke(obj, null);
}
if (ator != null)
{
if (brackets == null || brackets.Length < 2) brackets = "[]".ToCharArray();
sb.AppendFormat("{0}", brackets[0]); first = true; while (ator.MoveNext())
{
if (!first) sb.Append(", "); else first = false;
sb.AppendFormat("{0}", ator.Current.Sketch());
}
sb.AppendFormat("{0}", brackets[1]);
if (ator is IDisposable)
((IDisposable)ator).Dispose();
return sb.ToString();
}
// As a last resort, using the public properties (or fields if needed, or type name)...
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
PropertyInfo[] props = type.GetProperties(flags);
FieldInfo[] infos = type.GetFields(flags);
if (props.Length == 0 && infos.Length == 0) sb.Append(type.FullName); // Fallback if needed
else
{
if (brackets == null || brackets.Length < 2) brackets = "{}".ToCharArray();
sb.AppendFormat("{0}", brackets[0]);
first = true;
if (props.Length != 0)
{
foreach (PropertyInfo prop in props)
{
if (!first) sb.Append(", "); else first = false;
sb.AppendFormat("{0}='{1}'", prop.Name, prop.GetValue(obj, null).Sketch());
}
}
else
{
if (infos.Length != 0)
{
foreach (FieldInfo info in infos)
{
if (!first) sb.Append(", "); else first = false;
sb.AppendFormat("{0}='{1}'", info.Name, info.GetValue(obj).Sketch());
}
}
}
sb.AppendFormat("{0}", brackets[1]);
}
// And returning...
return sb.ToString();
}
/// <summary>
/// Returns true if the target string contains any of the characters given.
/// </summary>
/// <param name="source">The target string. It cannot be null.</param>
/// <param name="items">An array containing the characters to test. It cannot be null. If empty false is returned.</param>
/// <returns>True if the target string contains any of the characters given, false otherwise.</returns>
public static bool ContainsAny(this string source, char[] items)
{
if (source == null) throw new ArgumentNullException("source", "Source string cannot be null.");
if (items == null) throw new ArgumentNullException("items", "Array of characters to test cannot be null.");
if (items.Length == 0) return false; // No characters to validate
int ix = source.IndexOfAny(items);
return ix >= 0 ? true : false;
}
/// <summary>
/// Returns a new validated string using the rules given.
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="desc">A description of the source string to build errors and exceptions if needed.</param>
/// <param name="canbeNull">True if the returned string can be null.</param>
/// <param name="canbeEmpty">True if the returned string can be empty.</param>
/// <param name="trim">True to trim the returned string.</param>
/// <param name="trimStart">True to left-trim the returned string.</param>
/// <param name="trimEnd">True to right-trim the returned string.</param>
/// <param name="minLen">If >= 0, the min valid length for the returned string.</param>
/// <param name="maxLen">If >= 0, the max valid length for the returned string.</param>
/// <param name="padLeft">If not '\0', the character to use to left-pad the returned string if needed.</param>
/// <param name="padRight">If not '\0', the character to use to right-pad the returned string if needed.</param>
/// <param name="invalidChars">If not null, an array containing invalid chars that must not appear in the returned
/// string.</param>
/// <param name="validChars">If not null, an array containing the only characters that are considered valid for the
/// returned string.</param>
/// <returns>A new validated string.</returns>
public static string Validated(this string source, string desc = null,
bool canbeNull = false, bool canbeEmpty = false,
bool trim = true, bool trimStart = false, bool trimEnd = false,
int minLen = -1, int maxLen = -1, char padLeft = '\0', char padRight = '\0',
char[] invalidChars = null, char[] validChars = null)
{
// Assuring a valid descriptor...
if (string.IsNullOrWhiteSpace(desc)) desc = "Source";
// Validating if null sources are accepted...
if (source == null)
{
if (!canbeNull) throw new ArgumentNullException(desc, string.Format("{0} cannot be null.", desc));
return null;
}
// Trimming if needed...
if (trim && !(trimStart || trimEnd)) source = source.Trim();
else
{
if (trimStart) source = source.TrimStart(' ');
if (trimEnd) source = source.TrimEnd(' ');
}
// Adjusting lenght...
if (minLen > 0)
{
if (padLeft != '\0') source = source.PadLeft(minLen, padLeft);
if (padRight != '\0') source = source.PadRight(minLen, padRight);
}
if (maxLen > 0)
{
if (padLeft != '\0') source = source.PadLeft(maxLen, padLeft);
if (padRight != '\0') source = source.PadRight(maxLen, padRight);
}
// Validating emptyness and lenghts...
if (source.Length == 0)
{
if (!canbeEmpty) throw new ArgumentException(string.Format("{0} cannot be empty.", desc));
return string.Empty;
}
if (minLen >= 0 && source.Length < minLen) throw new ArgumentException(string.Format("Lenght of {0} '{1}' is lower than '{2}'.", desc, source, minLen));
if (maxLen >= 0 && source.Length > maxLen) throw new ArgumentException(string.Format("Lenght of {0} '{1}' is bigger than '{2}'.", desc, source, maxLen));
// Checking invalid chars...
if (invalidChars != null)
{
int n = source.IndexOfAny(invalidChars);
if (n >= 0) throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", source[n], desc, source));
}
// Checking valid chars...
if (validChars != null)
{
int n = validChars.ToString().IndexOfAny(source.ToCharArray());
if (n >= 0) throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", validChars.ToString()[n], desc, source));
}
return source;
}
/// <summary>
/// Splits the given string with the 'something AS alias' format, returning a tuple containing its 'something' and 'alias' parts.
/// If no alias is detected, then its component in the tuple returned is null and all the contents from the source
/// string are considered as the 'something' part.
/// </summary>
/// <param name="source">The source string.</param>
/// <returns>A tuple containing the 'something' and 'alias' parts.</returns>
public static Tuple<string, string> SplitSomethingAndAlias(this string source)
{
source = source.Validated("[Something AS Alias]");
string something = null;
string alias = null;
int n = source.LastIndexOf(" AS ", StringComparison.OrdinalIgnoreCase);
if (n < 0)
something = source;
else
{
something = source.Substring(0, n);
alias = source.Substring(n + 4);
}
return new Tuple<string, string>(something, alias);
}
/// <summary>Allows to replace parameters inside of string.</summary>
/// <param name="stringToFill">String containing parameters in format <c>[$ParameterName]</c>.</param>
/// <param name="getValue">Function that should return value that will be placed in string in place of placed parameter.</param>
/// <param name="prefix">Prefix of the parameter. This value can't be null or empty, default value <code>[$</code>.</param>
/// <param name="sufix">Suffix of the parameter. This value can't be null or empty, default value <code>]</code>.</param>
/// <returns>Parsed string.</returns>
public static string FillStringWithVariables(this string stringToFill, Func<string, string> getValue, string prefix = "[$", string sufix = "]")
{
int startPos = 0, endPos = 0;
prefix.Validated();
sufix.Validated();
startPos = stringToFill.IndexOf(prefix, startPos);
while (startPos >= 0)
{
endPos = stringToFill.IndexOf(sufix, startPos + prefix.Length);
int nextStartPos = stringToFill.IndexOf(prefix, startPos + prefix.Length);
if (endPos > startPos + prefix.Length + 1 && (nextStartPos > endPos || nextStartPos == -1))
{
string paramName = stringToFill.Substring(startPos + prefix.Length, endPos - (startPos + prefix.Length));
stringToFill = stringToFill
.Remove(startPos, (endPos - startPos) + sufix.Length)
.Insert(startPos, getValue(paramName));
}
startPos = stringToFill.IndexOf(prefix, startPos + prefix.Length);
}
return stringToFill;
}
}
}

View File

@@ -1,90 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Helpers
{
/// <summary>Class contains unclassified extensions.</summary>
internal static class UnclassifiedExtensions
{
/// <summary>Easy way to use conditional value.</summary>
/// <remarks>Includes <see cref="DBNull.Value"/>.</remarks>
/// <typeparam name="T">Input object type to check.</typeparam>
/// <typeparam name="R">Result type.</typeparam>
/// <param name="obj">The object to check.</param>
/// <param name="func">The select function.</param>
/// <param name="elseValue">The else value.</param>
/// <returns>Selected value or default value.</returns>
/// <example>It lets you do this:
/// <code>var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower());</code>
/// which is more fluent and (IMO) easier to read than this:
/// <code>var lname = (thingy != null ? thingy.Name : null) != null ? thingy.Name.ToLower() : null;</code>
/// </example>
public static R NullOr<T, R>(this T obj, Func<T, R> func, R elseValue = default(R)) where T : class
{
return obj != null && obj != DBNull.Value ?
func(obj) : elseValue;
}
/// <summary>Easy way to use conditional value.</summary>
/// <remarks>Includes <see cref="DBNull.Value"/>.</remarks>
/// <typeparam name="T">Input object type to check.</typeparam>
/// <typeparam name="R">Result type.</typeparam>
/// <param name="obj">The object to check.</param>
/// <param name="func">The select function.</param>
/// <param name="elseFunc">The else value function.</param>
/// <returns>Selected value or default value.</returns>
/// <example>It lets you do this:
/// <code>var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower());</code>
/// which is more fluent and (IMO) easier to read than this:
/// <code>var lname = (thingy != null ? thingy.Name : null) != null ? thingy.Name.ToLower() : null;</code>
/// </example>
public static R NullOrFn<T, R>(this T obj, Func<T, R> func, Func<R> elseFunc = null) where T : class
{
// Old if to avoid recurency.
return obj != null && obj != DBNull.Value ?
func(obj) : elseFunc != null ? elseFunc() : default(R);
}
/// <summary>Simple distinct by selector extension.</summary>
/// <returns>The enumerator of elements distinct by specified selector.</returns>
/// <param name="source">Source collection.</param>
/// <param name="keySelector">Distinct key selector.</param>
/// <typeparam name="R">The enumerable element type parameter.</typeparam>
/// <typeparam name="T">The selector type parameter.</typeparam>
public static IEnumerable<R> DistinctBy<R, T>(this IEnumerable<R> source, Func<R, T> keySelector)
{
HashSet<T> seenKeys = new HashSet<T>();
foreach (R element in source)
if (seenKeys.Add(keySelector(element)))
yield return element;
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -45,10 +45,6 @@ namespace DynamORM.Mapper
/// <summary>Gets or sets a value indicating whether column is a key.</summary> /// <summary>Gets or sets a value indicating whether column is a key.</summary>
public bool IsKey { get; set; } public bool IsKey { get; set; }
/// <summary>Gets or sets a value indicating whether column allows null or not.</summary>
/// <remarks>Information only.</remarks>
public bool AllowNull { get; set; }
/// <summary>Gets or sets a value indicating whether column should have unique value.</summary> /// <summary>Gets or sets a value indicating whether column should have unique value.</summary>
/// <remarks>Used when overriding schema.</remarks> /// <remarks>Used when overriding schema.</remarks>
public bool? IsUnique { get; set; } public bool? IsUnique { get; set; }
@@ -65,38 +61,18 @@ namespace DynamORM.Mapper
/// <remarks>Used when overriding schema.</remarks> /// <remarks>Used when overriding schema.</remarks>
public byte? Scale { get; set; } public byte? Scale { get; set; }
/// <summary>Gets or sets a value indicating whether this column is no allowed to be inserted.</summary>
/// <remarks>This is only a suggestion to automated mapping.</remarks>
public bool IsNoInsert { get; set; }
/// <summary>Gets or sets a value indicating whether this column is no allowed to be updated.</summary>
/// <remarks>This is only a suggestion to automated mapping.</remarks>
public bool IsNoUpdate { get; set; }
#region Constructors #region Constructors
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
public ColumnAttribute() public ColumnAttribute() { }
{
AllowNull = true;
}
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
/// <param name="name">Name of column.</param> /// <param name="name">Name of column.</param>
public ColumnAttribute(string name) public ColumnAttribute(string name)
: this()
{ {
Name = name; Name = name;
} }
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
/// <param name="isKey">Set column as a key column.</param>
public ColumnAttribute(bool isKey)
: this()
{
IsKey = isKey;
}
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
/// <param name="name">Name of column.</param> /// <param name="name">Name of column.</param>
/// <param name="isKey">Set column as a key column.</param> /// <param name="isKey">Set column as a key column.</param>
@@ -106,15 +82,6 @@ namespace DynamORM.Mapper
IsKey = isKey; IsKey = isKey;
} }
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
/// <param name="isKey">Set column as a key column.</param>
/// <param name="type">Set column type.</param>
public ColumnAttribute(bool isKey, DbType type)
: this(isKey)
{
Type = type;
}
/// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="ColumnAttribute" /> class.</summary>
/// <param name="name">Name of column.</param> /// <param name="name">Name of column.</param>
/// <param name="isKey">Set column as a key column.</param> /// <param name="isKey">Set column as a key column.</param>

View File

@@ -1,120 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Concurrent;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace DynamORM.Mapper
{
/// <summary>Type cast helper.</summary>
public static class DynamicCast
{
/// <summary>Gets the default value.</summary>
/// <param name="type">The type.</param>
/// <returns>Default instance.</returns>
public static object GetDefaultValue(this Type type)
{
return type.IsValueType ? TypeDefaults.GetOrAdd(type, t => Activator.CreateInstance(t)) : null;
}
/// <summary>Casts the object to this type.</summary>
/// <param name="type">The type to which cast value.</param>
/// <param name="val">The value to cast.</param>
/// <returns>Value casted to new type.</returns>
public static object CastObject(this Type type, object val)
{
return GetConverter(type, val)(val);
}
private static readonly ConcurrentDictionary<Type, object> TypeDefaults = new ConcurrentDictionary<Type, object>();
private static readonly ConcurrentDictionary<Type, Func<object, object>> TypeAsCasts = new ConcurrentDictionary<Type, Func<object, object>>();
private static readonly ConcurrentDictionary<PairOfTypes, Func<object, object>> TypeConvert = new ConcurrentDictionary<PairOfTypes, Func<object, object>>();
private static readonly ParameterExpression ConvParameter = Expression.Parameter(typeof(object), "val");
[MethodImpl(MethodImplOptions.Synchronized)]
private static Func<object, object> GetConverter(Type targetType, object val)
{
Func<object, object> fn;
if (!targetType.IsValueType && !val.GetType().IsValueType)
{
if (!TypeAsCasts.TryGetValue(targetType, out fn))
{
UnaryExpression instanceCast = Expression.TypeAs(ConvParameter, targetType);
fn = Expression.Lambda<Func<object, object>>(Expression.TypeAs(instanceCast, typeof(object)), ConvParameter).Compile();
TypeAsCasts.AddOrUpdate(targetType, fn, (t, f) => fn);
}
}
else
{
var fromType = val != null ? val.GetType() : typeof(object);
var key = new PairOfTypes(fromType, targetType);
if (TypeConvert.TryGetValue(key, out fn))
return fn;
fn = (Func<object, object>)Expression.Lambda(Expression.Convert(Expression.Convert(Expression.Convert(ConvParameter, fromType), targetType), typeof(object)), ConvParameter).Compile();
TypeConvert.AddOrUpdate(key, fn, (t, f) => fn);
}
return fn;
}
private class PairOfTypes
{
private readonly Type _first;
private readonly Type _second;
public PairOfTypes(Type first, Type second)
{
this._first = first;
this._second = second;
}
public override int GetHashCode()
{
return (31 * _first.GetHashCode()) + _second.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == this)
return true;
var other = obj as PairOfTypes;
if (other == null)
return false;
return _first.Equals(other._first)
&& _second.Equals(other._second);
}
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,35 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace DynamORM.Mapper
{
/// <summary>Exception thrown when mapper fails to set or get a property.</summary>
/// <seealso cref="System.Exception" />
public class DynamicMapperException : Exception
{
/// <summary>Initializes a new instance of the <see cref="DynamicMapperException"/> class.</summary>
public DynamicMapperException()
{
}
/// <summary>Initializes a new instance of the <see cref="DynamicMapperException"/> class.</summary>
/// <param name="message">The message that describes the error.</param>
public DynamicMapperException(string message) : base(message)
{
}
/// <summary>Initializes a new instance of the <see cref="DynamicMapperException"/> class.</summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
public DynamicMapperException(string message, Exception innerException) : base(message, innerException)
{
}
/// <summary>Initializes a new instance of the <see cref="DynamicMapperException"/> class.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
protected DynamicMapperException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,44 +27,19 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using DynamORM.Validation;
namespace DynamORM.Mapper namespace DynamORM.Mapper
{ {
/// <summary>Dynamic property invoker.</summary> /// <summary>Dynamic property invoker.</summary>
public class DynamicPropertyInvoker public class DynamicPropertyInvoker
{ {
internal class ParameterSpec
{
public string Name { get; set; }
public DbType Type { get; set; }
public int Ordinal { get; set; }
}
/// <summary>Gets the array type of property if main type is a form of collection.</summary>
public Type ArrayType { get; private set; }
/// <summary>Gets a value indicating whether this property is in fact a generic list.</summary>
public bool IsGnericEnumerable { get; private set; }
/// <summary>Gets the type of property.</summary>
public Type Type { get; private set; }
/// <summary>Gets value getter.</summary> /// <summary>Gets value getter.</summary>
public Func<object, object> Get { get; private set; } public Func<object, object> Get { get; private set; }
/// <summary>Gets value setter.</summary> /// <summary>Gets value setter.</summary>
public Action<object, object> Setter { get; private set; } public Action<object, object> Set { get; private set; }
/// <summary>Gets the property information.</summary>
public PropertyInfo PropertyInfo { get; private set; }
/// <summary>Gets name of property.</summary> /// <summary>Gets name of property.</summary>
public string Name { get; private set; } public string Name { get; private set; }
@@ -72,53 +47,24 @@ namespace DynamORM.Mapper
/// <summary>Gets type column description.</summary> /// <summary>Gets type column description.</summary>
public ColumnAttribute Column { get; private set; } public ColumnAttribute Column { get; private set; }
/// <summary>Gets type list of property requirements.</summary>
public List<RequiredAttribute> Requirements { get; private set; }
/// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary> /// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary>
public bool Ignore { get; private set; } public bool Ignore { get; private set; }
/// <summary>Gets a value indicating whether this instance hold data contract type.</summary>
public bool IsDataContract { get; private set; }
/// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary> /// <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="property">Property info to be invoked in the future.</param>
/// <param name="attr">Column attribute if exist.</param> /// <param name="attr">Column attribute if exist.</param>
public DynamicPropertyInvoker(PropertyInfo property, ColumnAttribute attr) public DynamicPropertyInvoker(PropertyInfo property, ColumnAttribute attr)
{ {
PropertyInfo = property;
Name = property.Name; Name = property.Name;
Type = property.PropertyType;
object[] ignore = property.GetCustomAttributes(typeof(IgnoreAttribute), false); var ignore = property.GetCustomAttributes(typeof(IgnoreAttribute), false);
Requirements = property.GetCustomAttributes(typeof(RequiredAttribute), false).Cast<RequiredAttribute>().ToList();
Ignore = ignore != null && ignore.Length > 0; Ignore = ignore != null && ignore.Length > 0;
IsGnericEnumerable = Type.IsGenericEnumerable();
ArrayType = Type.IsArray ? Type.GetElementType() :
IsGnericEnumerable ? Type.GetGenericArguments().First() :
Type;
IsDataContract = ArrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute");
if (ArrayType.IsArray)
throw new InvalidOperationException("Jagged arrays are not supported");
if (ArrayType.IsGenericEnumerable())
throw new InvalidOperationException("Enumerables of enumerables are not supported");
Column = attr; Column = attr;
if (attr != null && attr.AllowNull && Type.IsNullableType()) Get = CreateGetter(property);
attr.AllowNull = false; Set = CreateSetter(property);
if (property.CanRead)
Get = CreateGetter(property);
if (property.CanWrite)
Setter = CreateSetter(property);
} }
private Func<object, object> CreateGetter(PropertyInfo property) private Func<object, object> CreateGetter(PropertyInfo property)
@@ -126,7 +72,7 @@ namespace DynamORM.Mapper
if (!property.CanRead) if (!property.CanRead)
return null; return null;
ParameterExpression objParm = Expression.Parameter(typeof(object), "o"); var objParm = Expression.Parameter(typeof(object), "o");
return Expression.Lambda<Func<object, object>>( return Expression.Lambda<Func<object, object>>(
Expression.Convert( Expression.Convert(
@@ -141,8 +87,8 @@ namespace DynamORM.Mapper
if (!property.CanWrite) if (!property.CanWrite)
return null; return null;
ParameterExpression objParm = Expression.Parameter(typeof(object), "o"); var objParm = Expression.Parameter(typeof(object), "o");
ParameterExpression valueParm = Expression.Parameter(typeof(object), "value"); var valueParm = Expression.Parameter(typeof(object), "value");
return Expression.Lambda<Action<object, object>>( return Expression.Lambda<Action<object, object>>(
Expression.Assign( Expression.Assign(
@@ -152,109 +98,5 @@ namespace DynamORM.Mapper
Expression.Convert(valueParm, property.PropertyType)), Expression.Convert(valueParm, property.PropertyType)),
objParm, valueParm).Compile(); objParm, valueParm).Compile();
} }
/// <summary>Sets the specified value to destination object.</summary>
/// <param name="dest">The destination object.</param>
/// <param name="val">The value.</param>
public void Set(object dest, object val)
{
object value = null;
try
{
if (!Type.IsAssignableFrom(val.GetType()))
{
if (Type.IsArray || IsGnericEnumerable)
{
if (val != null)
{
var lst = (val as IEnumerable<object>).Select(x => GetElementVal(ArrayType, x)).ToList();
value = Array.CreateInstance(ArrayType, lst.Count);
int i = 0;
foreach (var e in lst)
((Array)value).SetValue(e, i++);
}
else
value = Array.CreateInstance(ArrayType, 0);
}
else
value = GetElementVal(Type, val);
}
else
value = val;
Setter(dest, value);
}
catch (Exception ex)
{
throw new DynamicMapperException(
string.Format("Error trying to convert and set value '{0}' of type '{1}' to type '{2}' in object of type '{3}'",
val == null ? string.Empty : val.ToString(), val.GetType(), Type.FullName, dest.GetType().FullName),
ex);
}
}
private object GetElementVal(System.Type etype, object val)
{
bool nullable = etype.IsGenericType && etype.GetGenericTypeDefinition() == typeof(Nullable<>);
Type type = Nullable.GetUnderlyingType(etype) ?? etype;
if (val == null && type.IsValueType)
{
if (nullable)
return null;
else
return Activator.CreateInstance(Type);
}
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType()))
return val;
else if (type.IsEnum && val.GetType().IsValueType)
return Enum.ToObject(type, val);
else if (type.IsEnum)
try
{
return Enum.Parse(type, val.ToString());
}
catch (ArgumentException)
{
if (nullable)
return null;
throw;
}
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
return val.ToString();
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
{
Guid g;
return Guid.TryParse((string)val, out g) ? g : Guid.Empty;
}
else if (IsDataContract)
return val.Map(type);
else
try
{
return Convert.ChangeType(val, type);
}
catch
{
if (nullable)
return null;
throw;
}
}
#region Type command cache
internal ParameterSpec InsertCommandParameter { get; set; }
internal ParameterSpec UpdateCommandParameter { get; set; }
internal ParameterSpec DeleteCommandParameter { get; set; }
#endregion Type command cache
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,9 @@
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection;
using DynamORM.Validation;
namespace DynamORM.Mapper namespace DynamORM.Mapper
{ {
@@ -49,11 +46,9 @@ namespace DynamORM.Mapper
public Func<object> Creator { get; private set; } public Func<object> Creator { get; private set; }
/// <summary>Gets map of columns to properties.</summary> /// <summary>Gets map of columns to properties.</summary>
/// <remarks>Key: Column name (lower), Value: <see cref="DynamicPropertyInvoker"/>.</remarks>
public Dictionary<string, DynamicPropertyInvoker> ColumnsMap { get; private set; } public Dictionary<string, DynamicPropertyInvoker> ColumnsMap { get; private set; }
/// <summary>Gets map of properties to column.</summary> /// <summary>Gets map of properties to column.</summary>
/// <remarks>Key: Property name, Value: Column name.</remarks>
public Dictionary<string, string> PropertyMap { get; private set; } public Dictionary<string, string> PropertyMap { get; private set; }
/// <summary>Gets list of ignored properties.</summary> /// <summary>Gets list of ignored properties.</summary>
@@ -65,7 +60,7 @@ namespace DynamORM.Mapper
{ {
Type = type; Type = type;
object[] attr = type.GetCustomAttributes(typeof(TableAttribute), false); var attr = type.GetCustomAttributes(typeof(TableAttribute), false);
if (attr != null && attr.Length > 0) if (attr != null && attr.Length > 0)
Table = (TableAttribute)attr[0]; Table = (TableAttribute)attr[0];
@@ -76,43 +71,35 @@ namespace DynamORM.Mapper
private void CreateColumnAndPropertyMap() private void CreateColumnAndPropertyMap()
{ {
Dictionary<string, DynamicPropertyInvoker> columnMap = new Dictionary<string, DynamicPropertyInvoker>(); var columnMap = new Dictionary<string, DynamicPropertyInvoker>();
Dictionary<string, string> propertyMap = new Dictionary<string, string>(); var propertyMap = new Dictionary<string, string>();
List<string> ignored = new List<string>();
foreach (PropertyInfo pi in GetAllMembers(Type).Where(x => x is PropertyInfo).Cast<PropertyInfo>()) foreach (var pi in Type.GetProperties())
{ {
ColumnAttribute attr = null; ColumnAttribute attr = null;
object[] attrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true); var attrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (attrs != null && attrs.Length > 0) if (attrs != null && attrs.Length > 0)
attr = (ColumnAttribute)attrs[0]; attr = (ColumnAttribute)attrs[0];
string col = attr == null || string.IsNullOrEmpty(attr.Name) ? pi.Name : attr.Name; string col = attr == null || string.IsNullOrEmpty(attr.Name) ? pi.Name : attr.Name;
DynamicPropertyInvoker val = new DynamicPropertyInvoker(pi, attr); var val = new DynamicPropertyInvoker(pi, attr);
columnMap.Add(col.ToLower(), val); columnMap.Add(col.ToLower(), val);
propertyMap.Add(pi.Name, col); propertyMap.Add(pi.Name, col);
if (val.Ignore)
ignored.Add(pi.Name);
} }
ColumnsMap = columnMap; ColumnsMap = columnMap;
PropertyMap = propertyMap; PropertyMap = propertyMap;
Ignored = ignored; ////columnMap.Where(i => i.Value.Ignore).Select(i => i.Value.Name).ToList(); Ignored = columnMap.Where(i => i.Value.Ignore).Select(i => i.Value.Name).ToList();
} }
private Func<object> CreateCreator() private Func<object> CreateCreator()
{ {
var c = Type.GetConstructor(Type.EmptyTypes); if (Type.GetConstructor(Type.EmptyTypes) != null)
if (c == null)
c = Type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (c != null)
return Expression.Lambda<Func<object>>(Expression.New(Type)).Compile(); return Expression.Lambda<Func<object>>(Expression.New(Type)).Compile();
return null; return null;
@@ -126,15 +113,6 @@ namespace DynamORM.Mapper
return Map(source, Creator()); return Map(source, Creator());
} }
/// <summary>Create object of <see cref="DynamicTypeMap.Type"/> type and fill values from <c>source</c> using property names.</summary>
/// <param name="source">Object containing values that will be mapped to newly created object.</param>
/// <returns>New object of <see cref="DynamicTypeMap.Type"/> type with matching values from <c>source</c>.</returns>
public object CreateByProperty(object source)
{
return MapByProperty(source, Creator());
}
/// <summary>Fill values from <c>source</c> to <see cref="DynamicTypeMap.Type"/> object in <c>destination</c>.</summary> /// <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 newly created object.</param> /// <param name="source">Object containing values that will be mapped to newly created object.</param>
/// <param name="destination">Object of <see cref="DynamicTypeMap.Type"/> type to which copy values from <c>source</c>.</param> /// <param name="destination">Object of <see cref="DynamicTypeMap.Type"/> type to which copy values from <c>source</c>.</param>
@@ -143,170 +121,14 @@ namespace DynamORM.Mapper
{ {
DynamicPropertyInvoker dpi = null; DynamicPropertyInvoker dpi = null;
foreach (KeyValuePair<string, object> item in source.ToDictionary()) foreach (var item in source.ToDictionary())
{ {
if (ColumnsMap.TryGetValue(item.Key.ToLower(), out dpi) && item.Value != null) if (ColumnsMap.TryGetValue(item.Key.ToLower(), out dpi) && item.Value != null)
if (dpi.Setter != null) if (dpi.Set != null)
dpi.Set(destination, item.Value); dpi.Set(destination, item.Value);
} }
return destination; return destination;
} }
/// <summary>Fill values from <c>source</c> to <see cref="DynamicTypeMap.Type"/> object in <c>destination</c> using property names.</summary>
/// <param name="source">Object containing values that will be mapped to newly 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 MapByProperty(object source, object destination)
{
string cn = null;
DynamicPropertyInvoker dpi = null;
foreach (KeyValuePair<string, object> item in source.ToDictionary())
{
if (PropertyMap.TryGetValue(item.Key, out cn) && item.Value != null)
if (ColumnsMap.TryGetValue(cn.ToLower(), out dpi) && item.Value != null)
if (dpi.Setter != null)
dpi.Set(destination, item.Value);
}
return destination;
}
/// <summary>Validates the object.</summary>
/// <param name="val">The value.</param>
/// <returns>List of not valid results.</returns>
public IList<ValidationResult> ValidateObject(object val)
{
var result = new List<ValidationResult>();
if (val == null || val.GetType() != Type)
return null;
foreach (var prop in ColumnsMap.Values)
{
if (prop.Requirements == null || !prop.Requirements.Any())
continue;
var v = prop.Get(val);
foreach (var r in prop.Requirements.Where(x => !x.ElementRequirement))
{
var valid = r.ValidateSimpleValue(prop, v);
if (valid == ValidateResult.Valid)
{
if (prop.Type.IsArray || prop.IsGnericEnumerable)
{
var map = DynamicMapperCache.GetMapper(prop.ArrayType);
var list = v as IEnumerable<object>;
if (list == null)
{
var enumerable = v as IEnumerable;
if (enumerable != null)
list = enumerable.Cast<object>();
}
if (list != null)
foreach (var item in list)
{
if (prop.Requirements.Any(x => x.ElementRequirement))
{
foreach (var re in prop.Requirements.Where(x => x.ElementRequirement))
{
var validelem = re.ValidateSimpleValue(prop.ArrayType, prop.ArrayType.IsGenericEnumerable(), item);
if (validelem == ValidateResult.NotSupported)
{
result.AddRange(map.ValidateObject(item));
break;
}
else if (validelem != ValidateResult.Valid)
result.Add(new ValidationResult()
{
Property = prop,
Requirement = r,
Value = item,
Result = validelem,
});
}
}
else
result.AddRange(map.ValidateObject(item));
}
}
continue;
}
if (valid == ValidateResult.NotSupported)
{
result.AddRange(DynamicMapperCache.GetMapper(prop.Type).ValidateObject(v));
continue;
}
result.Add(new ValidationResult()
{
Property = prop,
Requirement = r,
Value = v,
Result = valid,
});
}
}
return result;
}
private IEnumerable<MemberInfo> GetAllMembers(Type type)
{
if (type.IsInterface)
{
List<MemberInfo> members = new List<MemberInfo>();
List<Type> considered = new List<Type>();
Queue<Type> queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
Type subType = queue.Dequeue();
foreach (Type subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface)) continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
MemberInfo[] typeProperties = subType.GetMembers(
BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance);
IEnumerable<MemberInfo> newPropertyInfos = typeProperties
.Where(x => !members.Contains(x));
members.InsertRange(0, newPropertyInfos);
}
return members;
}
return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
}
#region Type command cache
internal string InsertCommandText { get; set; }
internal string UpdateCommandText { get; set; }
internal string DeleteCommandText { get; set; }
#endregion Type command cache
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,6 @@ namespace DynamORM.Mapper
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute public class TableAttribute : Attribute
{ {
/// <summary>Gets or sets table owner name.</summary>
public string Owner { get; set; }
/// <summary>Gets or sets name.</summary> /// <summary>Gets or sets name.</summary>
public string Name { get; set; } public string Name { get; set; }

View File

@@ -1,280 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DynamORM.Builders;
using DynamORM.Mapper;
using DynamORM.Validation;
namespace DynamORM.Objects
{
/// <summary>Base class for strong typed objects.</summary>
public class DynamicEntityBase
{
private Dictionary<string, object> _changedFields = new Dictionary<string, object>();
private DynamicEntityState _dynamicEntityState = DynamicEntityState.Unknown;
/// <summary>Occurs when object property is changing.</summary>
public event EventHandler<DynamicPropertyChangingEventArgs> PropertyChanging;
/// <summary>Gets the state of the dynamic entity.</summary>
/// <returns>Current state of entity.</returns>
public virtual DynamicEntityState GetDynamicEntityState() { return _dynamicEntityState; }
/// <summary>Sets the state of the dynamic entity.</summary>
/// <remarks>Using this method will reset modified fields list.</remarks>
/// <param name="state">The state.</param>
public virtual void SetDynamicEntityState(DynamicEntityState state)
{
_dynamicEntityState = state;
if (_changedFields != null)
_changedFields.Clear();
}
/// <summary>Called when object property is changing.</summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="oldValue">The old property value.</param>
/// <param name="newValue">The new property value.</param>
protected virtual void OnPropertyChanging(string propertyName, object oldValue, object newValue)
{
OnPropertyChanging(new DynamicPropertyChangingEventArgs(propertyName, oldValue, newValue));
}
/// <summary>Raises the <see cref="E:PropertyChanging"/> event.</summary>
/// <param name="e">The <see cref="DynamicPropertyChangingEventArgs"/> instance containing the event data.</param>
protected virtual void OnPropertyChanging(DynamicPropertyChangingEventArgs e)
{
_changedFields[e.PropertyName] = e.NewValue;
if (PropertyChanging != null)
PropertyChanging(this, e);
}
/// <summary>Validates this object instance.</summary>
/// <returns>Returns list of <see cref="ValidationResult"/> containing results of validation.</returns>
public virtual IList<ValidationResult> Validate()
{
return DynamicMapperCache.GetMapper(this.GetType()).ValidateObject(this);
}
/// <summary>Saves this object to database.</summary>
/// <param name="database">The database.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
/// <exception cref="InvalidOperationException">Can be thrown when object is in invalid state.</exception>
public virtual bool Save(DynamicDatabase database)
{
switch (GetDynamicEntityState())
{
default:
case DynamicEntityState.Unknown:
throw new InvalidOperationException("Unknown object state. Unable to decide whish action should be performed.");
case DynamicEntityState.New:
return Insert(database);
case DynamicEntityState.Existing:
if (IsModified())
return Update(database);
return true;
case DynamicEntityState.ToBeDeleted:
return Delete(database);
case DynamicEntityState.Deleted:
throw new InvalidOperationException("Unable to do any database action on deleted object.");
}
}
/// <summary>Determines whether this instance is in existing state and fields was modified since this state was set modified.</summary>
/// <returns>Returns <c>true</c> if this instance is modified; otherwise, <c>false</c>.</returns>
public virtual bool IsModified()
{
if (GetDynamicEntityState() != DynamicEntityState.Existing)
return false;
return _changedFields != null && _changedFields.Any();
}
#region Insert/Update/Delete
/// <summary>Inserts this object to database.</summary>
/// <param name="db">The database.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Insert(DynamicDatabase db)
{
if (db.Insert(this.GetType())
.Values(x => this)
.Execute() > 0)
{
_changedFields.Clear();
SetDynamicEntityState(DynamicEntityState.Existing);
return true;
}
return false;
}
/// <summary>Updates this object in database.</summary>
/// <param name="db">The database.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Update(DynamicDatabase db)
{
var t = GetType();
var mapper = DynamicMapperCache.GetMapper(t);
var query = db.Update(t);
MakeQueryWhere(mapper, query);
if (_changedFields.Any())
{
bool any = false;
foreach (var cf in _changedFields)
{
var cn = mapper.PropertyMap[cf.Key];
var pm = mapper.ColumnsMap[cn.ToLower()];
if (pm.Ignore)
continue;
if (pm.Column != null)
{
if (pm.Column.IsKey)
continue;
if (!pm.Column.AllowNull && cf.Value == null)
continue;
}
query.Values(cn, cf.Value);
any = true;
}
if (!any)
query.Set(x => this);
}
else
query.Set(x => this);
if (query.Execute() == 0)
return false;
SetDynamicEntityState(DynamicEntityState.Existing);
_changedFields.Clear();
return true;
}
/// <summary>Deletes this object from database.</summary>
/// <param name="db">The database.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Delete(DynamicDatabase db)
{
var t = this.GetType();
var mapper = DynamicMapperCache.GetMapper(t);
var query = db.Delete(t);
MakeQueryWhere(mapper, query);
if (query.Execute() == 0)
return false;
SetDynamicEntityState(DynamicEntityState.Deleted);
return true;
}
#endregion Insert/Update/Delete
#region Select
/// <summary>Refresh non key data from database.</summary>
/// <param name="db">The database.</param>
/// <remarks>All properties that are primary key values must be filled.</remarks>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Refresh(DynamicDatabase db)
{
var t = this.GetType();
var mapper = DynamicMapperCache.GetMapper(t);
var query = db.From(t);
MakeQueryWhere(mapper, query);
var o = (query.Execute() as IEnumerable<dynamic>).FirstOrDefault();
if (o == null)
return false;
mapper.Map(o, this);
SetDynamicEntityState(DynamicEntityState.Existing);
_changedFields.Clear();
return true;
}
#endregion Select
#region Query Helpers
private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicUpdateQueryBuilder query)
{
bool keyNotDefined = true;
foreach (var cm in mapper.ColumnsMap)
{
if (cm.Value.Column != null && cm.Value.Column.IsKey)
{
query.Where(cm.Key, DynamicColumn.CompareOperator.Eq, cm.Value.Get(this));
keyNotDefined = false;
}
}
if (keyNotDefined)
throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined",
this.GetType().FullName));
}
private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicDeleteQueryBuilder query)
{
bool keyNotDefined = true;
foreach (var cm in mapper.ColumnsMap)
{
if (cm.Value.Column != null && cm.Value.Column.IsKey)
{
query.Where(cm.Key, DynamicColumn.CompareOperator.Eq, cm.Value.Get(this));
keyNotDefined = false;
}
}
if (keyNotDefined)
throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined",
this.GetType().FullName));
}
private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicSelectQueryBuilder query)
{
bool keyNotDefined = true;
foreach (var cm in mapper.ColumnsMap)
{
if (cm.Value.Column != null && cm.Value.Column.IsKey)
{
var v = cm.Value.Get(this);
if (v == null)
throw new InvalidOperationException(String.Format("Class '{0}' have key columns {1} not filled with data.",
this.GetType().FullName, cm.Value.Name));
query.Where(cm.Key, DynamicColumn.CompareOperator.Eq, cm.Value.Get(this));
keyNotDefined = false;
}
}
if (keyNotDefined)
throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined",
this.GetType().FullName));
}
#endregion Query Helpers
}
}

View File

@@ -1,23 +0,0 @@
namespace DynamORM.Objects
{
/// <summary>Possible states of dynamic database objects.</summary>
public enum DynamicEntityState
{
/// <summary>Default state. This state will only permit to refresh data from database.</summary>
/// <remarks>In this state repository will be unable to tell if object with this state should be added
/// or updated in database, but you can still manually perform update or insert on such object.</remarks>
Unknown,
/// <summary>This state should be set to new objects in database.</summary>
New,
/// <summary>This state is ser when data is refreshed from database or object was loaded from repository.</summary>
Existing,
/// <summary>You can set this state to an object if you want repository to perform delete from database.</summary>
ToBeDeleted,
/// <summary>This state is set for objects that were deleted from database.</summary>
Deleted,
}
}

View File

@@ -1,32 +0,0 @@
using System;
namespace DynamORM.Objects
{
/// <summary>Class containing changed property data.</summary>
/// <seealso cref="System.EventArgs" />
public class DynamicPropertyChangingEventArgs : EventArgs
{
/// <summary>Gets the name of the property.</summary>
/// <value>The name of the property.</value>
public string PropertyName { get; private set; }
/// <summary>Gets the old property value.</summary>
/// <value>The old value.</value>
public object OldValue { get; private set; }
/// <summary>Gets the new property value.</summary>
/// <value>The new value.</value>
public object NewValue { get; private set; }
/// <summary>Initializes a new instance of the <see cref="DynamicPropertyChangingEventArgs"/> class.</summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="oldValue">The old property value.</param>
/// <param name="newValue">The new property value.</param>
public DynamicPropertyChangingEventArgs(string propertyName, object oldValue, object newValue)
{
PropertyName = propertyName;
OldValue = oldValue;
NewValue = newValue;
}
}
}

View File

@@ -1,128 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DynamORM.Builders;
using DynamORM.Mapper;
namespace DynamORM.Objects
{
/// <summary>Base repository class for specified object type.</summary>
/// <typeparam name="T">Type of stored object.</typeparam>
public class DynamicRepositoryBase<T> : IDisposable where T : DynamicEntityBase
{
private DynamicDatabase _database;
/// <summary>Initializes a new instance of the <see cref="DynamicRepositoryBase{T}"/> class.</summary>
/// <param name="database">The database.</param>
public DynamicRepositoryBase(DynamicDatabase database)
{
_database = database;
}
/// <summary>Get all rows from database.</summary>
/// <returns>Objects enumerator.</returns>
public virtual IEnumerable<T> GetAll()
{
return EnumerateQuery(_database.From<T>());
}
/// <summary>Get rows from database by custom query.</summary>
/// <param name="query">The query.</param>
/// <remarks>Query must be based on object type.</remarks>
/// <returns>Objects enumerator.</returns>
public virtual IEnumerable<T> GetByQuery(IDynamicSelectQueryBuilder query)
{
return EnumerateQuery(query);
}
private IEnumerable<T> EnumerateQuery(IDynamicSelectQueryBuilder query, bool forceType = true)
{
if (forceType)
{
var mapper = DynamicMapperCache.GetMapper(typeof(T));
var tn = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
mapper.Type.Name : mapper.Table.Name;
if (!query.Tables.Any(t => t.Name == tn))
throw new InvalidOperationException(string.Format("Query is not related to '{0}' class.", typeof(T).FullName));
}
foreach (var o in query.Execute<T>())
{
o.SetDynamicEntityState(DynamicEntityState.Existing);
yield return o;
}
}
/// <summary>Saves single object to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Save(T element)
{
return element.Save(_database);
}
/// <summary>Saves collection of objects to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Save(IEnumerable<T> element)
{
return element.All(x => x.Save(_database));
}
/// <summary>Insert single object to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Insert(T element)
{
return element.Insert(_database);
}
/// <summary>Insert collection of objects to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Insert(IEnumerable<T> element)
{
return element.All(x => x.Insert(_database));
}
/// <summary>Update single object to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Update(T element)
{
return element.Update(_database);
}
/// <summary>Update collection of objects to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Update(IEnumerable<T> element)
{
return element.All(x => x.Update(_database));
}
/// <summary>Delete single object to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Delete(T element)
{
return element.Delete(_database);
}
/// <summary>Delete collection of objects to database.</summary>
/// <param name="element">The element.</param>
/// <returns>Returns <c>true</c> if operation was successful.</returns>
public virtual bool Delete(IEnumerable<T> element)
{
return element.All(x => x.Delete(_database));
}
/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
public virtual void Dispose()
{
_database = null;
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,9 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
* *
* See: http://opensource.org/licenses/bsd-license.php * See: http://opensource.org/licenses/bsd-license.php
*
* Supported preprocessor flags:
* * DYNAMORM_OMMIT_OLDSYNTAX - Remove dynamic table functionality
* * DYNAMORM_OMMIT_GENERICEXECUTION - Remove generic execution functionality
* * DYNAMORM_OMMIT_TRYPARSE - Remove TryParse helpers (also applies DYNAMORM_OMMIT_GENERICEXECUTION)
*/ */
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
@@ -67,11 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0.1")] [assembly: AssemblyVersion("1.0.0.1")]
[assembly: AssemblyFileVersion("1.1.0.1")] [assembly: AssemblyFileVersion("1.0.0.1")]
[assembly: InternalsVisibleTo("DynamORM.Tests")]
[assembly: Obfuscation(Feature = "encrypt symbol names with password #dr4cul4#", Exclude = false)]
[assembly: Obfuscation(Feature = "code control flow obfuscation", Exclude = false)]
[assembly: Obfuscation(Feature = "rename serializable symbols", Exclude = false)]
[assembly: Obfuscation(Feature = "anonymous type properties renaming", Exclude = true)]
[assembly: Obfuscation(Feature = "optimization", Exclude = true)]

View File

@@ -1,160 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using DynamORM.Mapper;
namespace DynamORM.Validation
{
/// <summary>Required attribute can be used to validate fields in objects using mapper class.</summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class RequiredAttribute : Attribute
{
/// <summary>Gets or sets minimum value or length of field.</summary>
public decimal? Min { get; set; }
/// <summary>Gets or sets maximum value or length of field.</summary>
public decimal? Max { get; set; }
/// <summary>Gets or sets pattern to verify.</summary>
public Regex Pattern { get; set; }
/// <summary>Gets or sets a value indicating whether property value is required or not.</summary>
public bool Required { get; set; }
/// <summary>Gets or sets a value indicating whether this is an element requirement.</summary>
public bool ElementRequirement { get; set; }
/// <summary>Initializes a new instance of the <see cref="RequiredAttribute" /> class.</summary>
/// <param name="required">This field will be required.</param>
public RequiredAttribute(bool required = true)
{
Required = required;
}
/// <summary>Initializes a new instance of the <see cref="RequiredAttribute" /> class.</summary>
/// <param name="val">Limiting value to set.</param>
/// <param name="max">Whether set maximum parameter (true) or minimum parameter (false).</param>
/// <param name="required">This field will be required.</param>
public RequiredAttribute(float val, bool max, bool required = true)
{
if (max)
Max = (decimal)val;
else
Min = (decimal)val;
Required = required;
}
/// <summary>Initializes a new instance of the <see cref="RequiredAttribute" /> class.</summary>
/// <param name="min">Minimum value to set.</param>
/// <param name="max">Maximum value to set.</param>
/// <param name="required">This field will be required.</param>
public RequiredAttribute(float min, float max, bool required = true)
{
Min = (decimal)min;
Max = (decimal)max;
Required = required;
}
/// <summary>Initializes a new instance of the <see cref="RequiredAttribute" /> class.</summary>
/// <param name="min">Minimum value to set.</param>
/// <param name="max">Maximum value to set.</param>
/// <param name="pattern">Pattern to check.</param>
/// <param name="required">This field will be required.</param>
public RequiredAttribute(float min, float max, string pattern, bool required = true)
{
Min = (decimal)min;
Max = (decimal)max;
Pattern = new Regex(pattern, RegexOptions.Compiled);
Required = required;
}
internal ValidateResult ValidateSimpleValue(DynamicPropertyInvoker dpi, object val)
{
return ValidateSimpleValue(dpi.Type, dpi.IsGnericEnumerable, val);
}
internal ValidateResult ValidateSimpleValue(Type type, bool isGnericEnumerable, object val)
{
if (val == null)
{
if (Required)
return ValidateResult.ValueIsMissing;
else
return ValidateResult.Valid;
}
if (type.IsValueType)
{
if (val is decimal || val is long || val is int || val is float || val is double || val is short || val is byte ||
val is decimal? || val is long? || val is int? || val is float? || val is double? || val is short? || val is byte?)
{
decimal dec = Convert.ToDecimal(val);
if (Min.HasValue && Min.Value > dec)
return ValidateResult.ValueTooSmall;
if (Max.HasValue && Max.Value < dec)
return ValidateResult.ValueTooLarge;
return ValidateResult.Valid;
}
else
{
var str = val.ToString();
if (Min.HasValue && Min.Value > str.Length)
return ValidateResult.ValueTooShort;
if (Max.HasValue && Max.Value < str.Length)
return ValidateResult.ValueTooLong;
if (Pattern != null && !Pattern.IsMatch(str))
return ValidateResult.ValueDontMatchPattern;
return ValidateResult.Valid;
}
}
else if (type.IsArray || isGnericEnumerable)
{
int? cnt = null;
var list = val as IEnumerable<object>;
if (list != null)
cnt = list.Count();
else
{
var enumerable = val as IEnumerable;
if (enumerable != null)
cnt = enumerable.Cast<object>().Count();
}
if (Min.HasValue && Min.Value > cnt)
return ValidateResult.TooFewElementsInCollection;
if (Max.HasValue && Max.Value < cnt)
return ValidateResult.TooManyElementsInCollection;
return ValidateResult.Valid;
}
else if (type == typeof(string))
{
var str = (string)val;
if (Min.HasValue && Min.Value > str.Length)
return ValidateResult.ValueTooShort;
if (Max.HasValue && Max.Value < str.Length)
return ValidateResult.ValueTooLong;
if (Pattern != null && !Pattern.IsMatch(str))
return ValidateResult.ValueDontMatchPattern;
return ValidateResult.Valid;
}
return ValidateResult.NotSupported;
}
}
}

View File

@@ -1,36 +0,0 @@
namespace DynamORM.Validation
{
/// <summary>Validation result enum.</summary>
public enum ValidateResult
{
/// <summary>The valid value.</summary>
Valid,
/// <summary>The value is missing.</summary>
ValueIsMissing,
/// <summary>The value too small.</summary>
ValueTooSmall,
/// <summary>The value too large.</summary>
ValueTooLarge,
/// <summary>The too few elements in collection.</summary>
TooFewElementsInCollection,
/// <summary>The too many elements in collection.</summary>
TooManyElementsInCollection,
/// <summary>The value too short.</summary>
ValueTooShort,
/// <summary>The value too long.</summary>
ValueTooLong,
/// <summary>The value don't match pattern.</summary>
ValueDontMatchPattern,
/// <summary>The not supported.</summary>
NotSupported,
}
}

View File

@@ -1,20 +0,0 @@
using DynamORM.Mapper;
namespace DynamORM.Validation
{
/// <summary>Validation result.</summary>
public class ValidationResult
{
/// <summary>Gets the property invoker.</summary>
public DynamicPropertyInvoker Property { get; internal set; }
/// <summary>Gets the requirement definition.</summary>
public RequiredAttribute Requirement { get; internal set; }
/// <summary>Gets the value that is broken.</summary>
public object Value { get; internal set; }
/// <summary>Gets the result.</summary>
public ValidateResult Result { get;internal set;}
}
}

View File

@@ -1,234 +0,0 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
<CollectionProperty Name="RecognizedWords">
<Value>aspx</Value>
<Value>behaviour</Value>
<Value>bindable</Value>
<Value>cloneable</Value>
<Value>Cron</Value>
<Value>Crontab</Value>
<Value>Csv</Value>
<Value>Decapsulate</Value>
<Value>decapsulated</Value>
<Value>decapsulation</Value>
<Value>decrypter</Value>
<Value>Dequeue</Value>
<Value>dll</Value>
<Value>DynamORM</Value>
<Value>encrypter</Value>
<Value>enum</Value>
<Value>Enum</Value>
<Value>expando</Value>
<Value>fr</Value>
<Value>inequivalent</Value>
<Value>int</Value>
<Value>Int</Value>
<Value>Json</Value>
<Value>Linq</Value>
<Value>nd</Value>
<Value>Nullable</Value>
<Value>Prismo</Value>
<Value>queryable</Value>
<Value>Reinitialization</Value>
<Value>Remoting</Value>
<Value>Rijndael</Value>
<Value>rubyforge</Value>
<Value>singelton</Value>
<Value>th</Value>
<Value>tu</Value>
<Value>xmlns</Value>
</CollectionProperty>
</GlobalSettings>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="FieldNamesMustNotBeginWithUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustNotContainUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>en</Value>
<Value>il</Value>
<Value>is</Value>
<Value>on</Value>
<Value>ui</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustBeginWithACapitalLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">True</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustEndWithAPeriod">
<RuleSettings>
<BooleanProperty Name="Enabled">True</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<BooleanProperty Name="IgnorePrivates">True</BooleanProperty>
<BooleanProperty Name="IgnoreInternals">True</BooleanProperty>
<BooleanProperty Name="IncludeFields">False</BooleanProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.OrderingRules">
<Rules>
<Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustAppearInTheCorrectOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeOrderedByAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StaticElementsMustAppearBeforeInstanceElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ProtectedMustComeBeforeInternal">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<BooleanProperty Name="GeneratedCodeElementOrder">False</BooleanProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="CurlyBracketsMustNotBeOmitted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeSeparatedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="PrefixLocalCallsWithThis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustFollowComma">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustNotSpanMultipleLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DoNotPlaceRegionsWithinElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainMultipleStatementsOnOneLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="BlockStatementsMustNotContainEmbeddedRegions">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UseBuiltInTypeAlias">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PrefixCallsCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

View File

@@ -1,48 +0,0 @@
using System.Linq;
using DynamORM;
namespace Tester
{
internal class Program
{
private static DynamORM.DynamicDatabase GetORM()
{
return new DynamORM.DynamicDatabase(System.Data.SqlClient.SqlClientFactory.Instance,
//"packet size=4096;User Id=sa;Password=Sa123;data source=192.168.1.9,1434;initial catalog=MAH_Melle-GAGARIN;",
"packet size=4096;User Id=sa;Password=sa123;data source=192.168.1.9,1433;initial catalog=MOM_NEXT_Florentyna_WMS_PROD;",
DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction | DynamORM.DynamicDatabaseOptions.SupportStoredProcedures |
DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportTop);
////return new DynamORM.DynamicDatabase(System.Data.SQLite.SQLiteFactory.Instance,
//// "Data Source=test.db3;",
//// DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction |
//// DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportLimitOffset);
}
private static void Main(string[] args)
{
DynamicDatabase db = new DynamicDatabase(System.Data.SqlClient.SqlClientFactory.Instance, "packet size=4096;User Id=sa;Password=Sa123;data source=127.0.0.1,1434;initial catalog=MAH_Levant;",
DynamicDatabaseOptions.SingleConnection | DynamicDatabaseOptions.SingleTransaction | DynamicDatabaseOptions.SupportSchema |
DynamicDatabaseOptions.SupportStoredProcedures | DynamicDatabaseOptions.SupportTop | DynamicDatabaseOptions.DumpCommands);
try
{
db.Execute("DROP TABLE Experiments ");
}
catch { }
db.Execute("CREATE TABLE Experiments (t1 nvarchar(50) NOT NULL DEFAULT N'', t2 varchar(50) NOT NULL DEFAULT '');");
var q = db.From(x => x.Experiments.As(x.e1));
q
.Where(x => x.t2 = "Dupą")
.Where(x => x.Exists(
q.SubQuery()
.From(y => y.Experiments.As(x.e2))
.Where(y => y.e2.t1 == y.e1.t1)))
.Execute().ToList();
db.Execute("DROP TABLE Experiments ");
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Tester")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Tester")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
[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("dbff9475-06f5-400e-bc17-57c14d9d9cb9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,71 +0,0 @@
<?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)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{F747AA57-BEA7-4FB8-B371-546296789AEF}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tester</RootNamespace>
<AssemblyName>Tester</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.94.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64">
<HintPath>C:\Program Files\System.Data.SQLite\2010\bin\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="ProfilingSessions\Session20141128_203722.sdps" />
</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>