mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Merge remote-tracking branch 'orchard/dev' into features/dev/6986
# Conflicts: # src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj # src/Orchard.Web/Modules/Orchard.MediaProcessing/packages.config
This commit is contained in:
commit
cbb9a4ddba
.deployment
.github/workflows
.gitignoreCREDITS.txtCalculateBindingRedirects.ps1ClickToBuild.cmdDeploymentUtility.psm1Orchard.projREADME.mdSECURITY.mddeploy.cmddeploy.ps1lib
src
.editorconfigGulpfile.js
Libraries/NHibernate/NHibernate.Linq
AssemblyInfo.csCriteriaResultReader.cs
NuGet.configExpressions
CollectionAccessExpression.csEntityExpression.csNHibernateExpression.csNHibernateExpressionType.csPropertyAccessExpression.csQuerySourceExpression.csSqlAggregateFunctionProjection.csSqlFunctionAttribute.csSqlFunctionExpression.cs
IDbMethods.csINHibernateQueryable.csNHibernate.Linq.buildNHibernate.Linq.csprojNHibernateContext.csNHibernateExtensions.csNHibernateQueryProvider.csQuery.csQueryOptions.csQueryProvider.csSqlClient
Transform
LinqGroupingResultTransformer.csLinqJoinResultsTransformer.csTypeSafeConstructorMemberInitResultTransformer.cs
Util
Visitors
AssociationVisitor.csBinaryBooleanReducer.csBinaryCriterionDelegates.csBinaryCriterionType.csBinaryCriterionVisitor.csBinaryExpressionOrderer.csCollectionAliasVisitor.csEntityExpressionVisitor.csEvaluator.csExpressionVisitor.csGroupingArgumentsVisitor.csImmediateResultsVisitor.csInheritanceVisitor.csMemberNameVisitor.csNHibernateExpressionVisitor.csNHibernateQueryTranslator.csPropertyToMethodVisitor.csRootVisitor.csSelectArgumentsVisitor.csSelectManyVisitor.csWhereArgumentsVisitor.cs
packages.configOrchard.Azure.Tests
Orchard.Core.Tests
Orchard.Profile
Orchard.Specs
33
.deployment
33
.deployment
@ -1,3 +1,34 @@
|
||||
; .deployment is actually an INI file and parsed by the following file
|
||||
; https://raw.githubusercontent.com/projectkudu/kudu/master/Kudu.Core/Infrastructure/IniFile.cs
|
||||
|
||||
; Document of deployment with custom script
|
||||
; https://github.com/projectkudu/kudu/wiki/Customizing-deployments#deploying-with-custom-script
|
||||
|
||||
; Document of configurable settings https://github.com/projectkudu/kudu/wiki/Configurable-settings
|
||||
; Runtime settings cannot be overridden in .deployment e.g. WEBSITE_NODE_DEFAULT_VERSION
|
||||
; More info https://github.com/projectkudu/kudu/wiki/Configurable-settings#runtime-settings
|
||||
|
||||
# Define default node version in WEBSITE_NODE_DEFAULT_VERSION APP Setting
|
||||
# Find all Node.js versions from your AppService Kudu api/diagnostics/runtime
|
||||
# More info https://codesanook-reactjs-server-side-rendering.scm.azurewebsites.net/api/diagnostics/runtime
|
||||
|
||||
; You can define a custom environment variable as
|
||||
; CUSTOM_VARIABLE = my custom variable value
|
||||
; and read in a deploy.ps1 script as
|
||||
; $Env:CUSTOM_VARIABLE
|
||||
|
||||
; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe?view=powershell-5.1#examples
|
||||
[config]
|
||||
command = deploy.cmd
|
||||
COMMAND = PowerShell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -Command "& "$(Join-Path -Path $(Get-Location) -ChildPath deploy.ps1)" 2>&1 | Write-Output"
|
||||
|
||||
; Set additional environment variables
|
||||
; Timeout in seconds
|
||||
; Set to one hour
|
||||
SCM_COMMAND_IDLE_TIMEOUT = 3600
|
||||
|
||||
; Variables for MSBuild
|
||||
MSBUILD_PATH = D:\Program Files (x86)\MSBuild-16.4\MSBuild\Current\Bin\MSBuild.exe
|
||||
SOLUTION_PATH = src/Orchard.sln
|
||||
|
||||
; For Azure deployment, we use custom MS Build at root of the project.
|
||||
PROJECT_PATH = Orchard.proj
|
||||
|
30
.github/workflows/build-crowdin-translation-packages.yml
vendored
Normal file
30
.github/workflows/build-crowdin-translation-packages.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Build Crowdin Translation Packages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 6 * * *"
|
||||
|
||||
jobs:
|
||||
build-crowdin-translation-packages:
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Orchard CMS
|
||||
uses: andrii-bodnar/crowdin-request-action@aac9a865d62b37060b0ce530db5ac5cfca02dd2c # 0.0.2
|
||||
with:
|
||||
route: POST /projects/{projectId}/translations/builds
|
||||
projectId: 46524
|
||||
env:
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }}
|
||||
|
||||
- name: Orchard CMS Gallery
|
||||
uses: andrii-bodnar/crowdin-request-action@aac9a865d62b37060b0ce530db5ac5cfca02dd2c # 0.0.2
|
||||
with:
|
||||
route: POST /projects/{projectId}/translations/builds
|
||||
projectId: 63766
|
||||
env:
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }}
|
70
.github/workflows/compile.yml
vendored
Normal file
70
.github/workflows/compile.yml
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
name: Compile
|
||||
# Compiles the solution and runs unit tests.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- 1.10.x
|
||||
|
||||
jobs:
|
||||
compile-dotnet:
|
||||
name: Compile .NET solution
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: nuget restore src/Orchard.sln
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Compile
|
||||
run: msbuild Orchard.proj /m /v:minimal /t:Compile /p:MvcBuildViews=true /p:TreatWarningsAsErrors=true -WarnAsError
|
||||
|
||||
- name: Test
|
||||
run: msbuild Orchard.proj /m /v:minimal /t:Test
|
||||
|
||||
compile-node:
|
||||
name: Compile client-side assets
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version: '7'
|
||||
|
||||
- name: Setup NPM packages
|
||||
working-directory: ./src
|
||||
run: |
|
||||
npm install --loglevel warn
|
||||
|
||||
# Install gulp globally to be able to run the rebuild task, using the same version as in the project.
|
||||
$gulpVersion = (Get-Content Package.json -Raw | ConvertFrom-Json).devDependencies.gulp
|
||||
Start-Process npm -NoNewWindow -Wait -ArgumentList "install gulp@$gulpVersion -g --loglevel warn"
|
||||
|
||||
- name: Rebuild client-side assets
|
||||
working-directory: ./src
|
||||
run: |
|
||||
gulp rebuild
|
||||
|
||||
git add . # To make line ending changes "disappear".
|
||||
$gitStatus = (git status --porcelain)
|
||||
if ($gitStatus)
|
||||
{
|
||||
throw ("Client-side assets are not up-to-date. Please run 'gulp rebuild' and commit the changes.`n" +
|
||||
[System.String]::Join([System.Environment]::NewLine, $gitStatus))
|
||||
}
|
39
.github/workflows/specflow.yml
vendored
Normal file
39
.github/workflows/specflow.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: SpecFlow tests
|
||||
# Compiles the solution and runs unit tests, as well the SpecFlow tests on the main development branches.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Every day at midnight.
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
name: SpecFlow tests
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
branch: [dev, 1.10.x]
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
ref: ${{ matrix.branch }}
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: nuget restore src/Orchard.sln
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
|
||||
|
||||
- name: Compile
|
||||
run: msbuild Orchard.proj /m /v:minimal /t:Compile /p:MvcBuildViews=true /p:TreatWarningsAsErrors=true -WarnAsError
|
||||
|
||||
- name: Test
|
||||
run: msbuild Orchard.proj /m /v:minimal /t:Test
|
||||
|
||||
- name: Spec
|
||||
run: msbuild Orchard.proj /m /v:minimal /t:Spec
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,5 +1,7 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
**/.vs/**
|
||||
src/Rebracer.xml
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
@ -68,6 +70,9 @@ ipch/
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# CodeRush is a .NET coding add-in
|
||||
.cr*/
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
@ -172,7 +177,7 @@ profiling/
|
||||
src/Orchard.Web/Modules-temp/*
|
||||
src/Backup/*
|
||||
src/packages/*
|
||||
src/node_modules
|
||||
src/**/node_modules
|
||||
src/UpgradeLog.*
|
||||
*.itrace.csdef
|
||||
*.build.csdef
|
||||
@ -187,5 +192,3 @@ src/Orchard.Azure/Orchard.Azure.CloudService/Staging/
|
||||
|
||||
#enable all /lib artifacts
|
||||
!lib/**/*.*
|
||||
*/.vs/*
|
||||
src/Rebracer.xml
|
||||
|
12
CREDITS.txt
12
CREDITS.txt
@ -187,15 +187,15 @@ License: Apache Software Foundation License 2.0
|
||||
|
||||
Lucene.net
|
||||
-----
|
||||
Website: http://incubator.apache.org/projects/lucene.net.html
|
||||
Website: https://lucenenet.apache.org/
|
||||
Copyright: Copyright (c) 2009 Apache Software Foundation
|
||||
License: Apache Software Foundation License 2.0
|
||||
|
||||
MarkdownSharp
|
||||
Markdig
|
||||
-----
|
||||
Website: http://code.google.com/p/markdownsharp/
|
||||
Copyright: Copyright (c) 2009-2011 Jeff Atwood
|
||||
License: MIT
|
||||
Website: https://github.com/lunet-io/markdig
|
||||
Copyright: Copyright (c) 2018-2019, Alexandre Mutel
|
||||
License: BSD 2-Clause
|
||||
|
||||
Mono Class Library
|
||||
-----
|
||||
@ -293,4 +293,4 @@ YUI
|
||||
-----
|
||||
Website: http://developer.yahoo.com/yui/
|
||||
Copyright: Copyright (c) 2010, Yahoo! Inc.
|
||||
License: New BSD
|
||||
License: New BSD
|
||||
|
34
CalculateBindingRedirects.ps1
Normal file
34
CalculateBindingRedirects.ps1
Normal file
@ -0,0 +1,34 @@
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
|
||||
[System.Xml.Linq.XNamespace]$ns1 = "urn:schemas-microsoft-com:asm.v1"
|
||||
|
||||
$currentPath = (Get-Item -Path ".\").FullName
|
||||
$orchardWebConfigFullPath = $currentPath+"\src\Orchard.Web\Web.Config"
|
||||
[XML] $orchardWebConfig = Get-Content ($orchardWebConfigFullPath)
|
||||
$configFiles = Get-ChildItem -Path ($currentPath +"\src\") -Filter web.config -Recurse -ErrorAction SilentlyContinue -Force
|
||||
foreach ($configFile in $configFiles) {
|
||||
$configFullPath = $configFile.FullName
|
||||
Write-Host "Processing $configFullPath ..."
|
||||
|
||||
if ($configFullPath.ToLower().EndsWith("\orchard.web\web.config")) { #skip orchard.web config files
|
||||
continue
|
||||
}
|
||||
[XML] $projectWebConfig = Get-Content ($configFullPath)
|
||||
$elements = $projectWebConfig.configuration.runtime.assemblyBinding.dependentAssembly
|
||||
foreach ($element in $elements){
|
||||
Write-Host "Checking" $element.assemblyIdentity.name
|
||||
$hasBinding = $orchardWebConfig.configuration.runtime.assemblyBinding.dependentAssembly.assemblyIdentity.Where({ $_.name -eq $element.assemblyIdentity.name -and $_.publicKeyToken -eq $element.assemblyIdentity.publicKeyToken -and $_.culture -eq $element.assemblyIdentity.culture }, 'First').Count -gt 0
|
||||
if (-not $hasBinding){
|
||||
# add the node in $webConfig
|
||||
Write-Host "Adding" $element.assemblyIdentity.name
|
||||
$newNode = $orchardWebConfig.ImportNode($element, $true);
|
||||
$orchardWebConfig.configuration.runtime.assemblyBinding.AppendChild($newNode)
|
||||
Write-Host "Added " $element.assemblyIdentity.name
|
||||
} else {
|
||||
Write-Host "Skipped" $element.assemblyIdentity.name
|
||||
}
|
||||
}
|
||||
Write-Host "Processed $configFullPath ..."
|
||||
}
|
||||
|
||||
$orchardWebConfig.Save($orchardWebConfigFullPath)
|
@ -1,22 +1,20 @@
|
||||
FOR %%b in (
|
||||
"%VS140COMNTOOLS%..\..\VC\vcvarsall.bat"
|
||||
"%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
"%ProgramFiles%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
@echo off
|
||||
|
||||
"%VS120COMNTOOLS%..\..\VC\vcvarsall.bat"
|
||||
"%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"
|
||||
"%ProgramFiles%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"
|
||||
REM Necessary for the InstallDir variable to work inside the MsBuild-finding loop below.
|
||||
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||
|
||||
"%VS110COMNTOOLS%..\..\VC\vcvarsall.bat"
|
||||
"%ProgramFiles(x86)%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"
|
||||
"%ProgramFiles%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"
|
||||
) do (
|
||||
if exist %%b (
|
||||
call %%b x86
|
||||
goto build
|
||||
)
|
||||
for /f "usebackq tokens=1* delims=: " %%i in (`lib\vswhere\vswhere -latest -version "[16.0,18.0)" -requires Microsoft.Component.MSBuild`) do (
|
||||
if /i "%%i"=="installationPath" (
|
||||
set InstallDir=%%j
|
||||
echo !InstallDir!
|
||||
if exist "!InstallDir!\MSBuild\Current\Bin\MSBuild.exe" (
|
||||
echo "Using MSBuild from !InstallDir!"
|
||||
set msbuild="!InstallDir!\MSBuild\Current\Bin\MSBuild.exe"
|
||||
goto build
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
echo "Unable to detect suitable environment. Build may not succeed."
|
||||
|
||||
:build
|
||||
@ -31,6 +29,8 @@ IF "%solution%" == "" SET solution=src\Orchard.sln
|
||||
|
||||
lib\nuget\nuget.exe restore %solution%
|
||||
|
||||
msbuild /t:%target% %project% /p:Solution=%solution%
|
||||
%msbuild% /t:%target% %project% /p:Solution=%solution% /m
|
||||
|
||||
:end
|
||||
|
||||
pause
|
83
DeploymentUtility.psm1
Normal file
83
DeploymentUtility.psm1
Normal file
@ -0,0 +1,83 @@
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
# Continue a build process even though there is a warning wrote to std err.
|
||||
# We will check exit code in Invoke-ExternalCommand to design whether it fail or not
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
function Add-NpmToPathVariable {
|
||||
$path = "$env:Appdata\npm"
|
||||
$escapedPath = [Regex]::Escape($path)
|
||||
|
||||
# Remove existing npm path safe to add npm path again
|
||||
$paths = $env:Path -split ';' | Where-Object {
|
||||
$_ -notmatch "^$escapedPath\\?$"
|
||||
}
|
||||
|
||||
# Update a path variable to this session
|
||||
$env:Path = ($paths + $path) -join ";" # array + element item
|
||||
}
|
||||
|
||||
function Invoke-ExternalCommand {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock
|
||||
)
|
||||
|
||||
# Displays an error message and continue executing if there is a standard error.
|
||||
# This is because there are some external command tools write warning message to standard error.
|
||||
# Use Write-Output also fix "Window title cannot be longer than 1023 characters" issue
|
||||
# https://github.com/projectkudu/kudu/issues/2635
|
||||
& $ScriptBlock 2>&1 | Write-Output
|
||||
|
||||
# If last exit code is not 0, throw an exception to stop a script
|
||||
if ($LastExitCode) {
|
||||
throw "Failed with exit code = $LastExitCode and command = $($ScriptBlock.ToString())"
|
||||
}
|
||||
}
|
||||
|
||||
function Write-EnviromentValue {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)] [String[]] $EnvironmentName
|
||||
)
|
||||
|
||||
"----------------- Begin of environment variables ---------------------------------"
|
||||
Get-Item -Path Env:* | Where-Object {
|
||||
$EnvironmentName -contains $_.Name
|
||||
} | Format-Table Name, Value -Wrap
|
||||
|
||||
"----------------- End of environment variables ---------------------------------"
|
||||
}
|
||||
|
||||
function Install-Yarn {
|
||||
"Verify if yarn installed"
|
||||
if (Get-Command -Name yarn -ErrorAction Ignore) {
|
||||
"Updating yarn as a global tool to the latest version"
|
||||
# https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters
|
||||
# issue https://github.com/projectkudu/kudu/issues/2635
|
||||
Invoke-ExternalCommand -ScriptBlock { npm update yarn -g }
|
||||
}
|
||||
else {
|
||||
"Installing yarn as a global tool"
|
||||
Invoke-ExternalCommand -ScriptBlock { npm install yarn -g }
|
||||
Add-NpmToPathVariable
|
||||
}
|
||||
}
|
||||
|
||||
function Install-KuduSync {
|
||||
"Verify if kudusync installed"
|
||||
if (Get-Command -Name kudusync -ErrorAction Ignore) {
|
||||
"Updating kudusync as a global tool to the latest version"
|
||||
# https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters
|
||||
# issue https://github.com/projectkudu/kudu/issues/2635
|
||||
Invoke-ExternalCommand -ScriptBlock { npm update kudusync -g }
|
||||
}
|
||||
else {
|
||||
"Installing kudusync as a global tool"
|
||||
Invoke-ExternalCommand -ScriptBlock { npm install kudusync -g }
|
||||
Add-NpmToPathVariable
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Invoke-ExternalCommand
|
||||
Export-ModuleMember -Function Write-EnviromentValue
|
||||
Export-ModuleMember -Function Install-Yarn
|
||||
Export-ModuleMember -Function Install-KuduSync
|
35
Orchard.proj
35
Orchard.proj
@ -13,9 +13,10 @@
|
||||
<SourceArtifactFolder>$(ArtifactsFolder)\Source</SourceArtifactFolder>
|
||||
<MsDeployArtifactFolder>$(ArtifactsFolder)\MsDeploy</MsDeployArtifactFolder>
|
||||
<GalleryArtifactFolder>$(ArtifactsFolder)\Gallery</GalleryArtifactFolder>
|
||||
<ModulesSrcFolder>$(MSBuildProjectDirectory)\src\Orchard.Web\Modules</ModulesSrcFolder>
|
||||
<OrchardCoreSrcFolder>$(MSBuildProjectDirectory)\src\Orchard.Web\Core</OrchardCoreSrcFolder>
|
||||
<ThemesSrcFolder>$(MSBuildProjectDirectory)\src\Orchard.Web\Themes</ThemesSrcFolder>
|
||||
<OrchardWebFolder>$(SrcFolder)\Orchard.Web</OrchardWebFolder>
|
||||
<ModulesSrcFolder>$(OrchardWebFolder)\Modules</ModulesSrcFolder>
|
||||
<OrchardCoreSrcFolder>$(OrchardWebFolder)\Core</OrchardCoreSrcFolder>
|
||||
<ThemesSrcFolder>$(OrchardWebFolder)\Themes</ThemesSrcFolder>
|
||||
|
||||
<CompileFolder>$(BuildFolder)\Compile</CompileFolder>
|
||||
<WebSitesFolder>$(CompileFolder)\_PublishedWebsites</WebSitesFolder>
|
||||
@ -112,15 +113,25 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="Compile">
|
||||
<CallTarget Targets="DevCompile"/>
|
||||
<!-- Compile to "OutputFolder" -->
|
||||
<MSBuild
|
||||
Projects="$(Solution)"
|
||||
Targets="Build"
|
||||
Properties="Configuration=$(Configuration);OutputPath=$(CompileFolder)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="DevCompile">
|
||||
<!-- To make sure that Roslyn tools are available, since it's included with Orchard.Web, which is not referenced by
|
||||
other projects, so it will be built towards the end. -->
|
||||
<MSBuild
|
||||
Projects="$(OrchardWebFolder)\Orchard.Web.csproj"
|
||||
Targets="CopyRoslynCompilerFilesToOutputDirectory" />
|
||||
<!-- Compile to "regular" output folder for devs using VS locally -->
|
||||
<MSBuild
|
||||
Projects="$(Solution)"
|
||||
Targets="Build"/>
|
||||
Targets="Build"
|
||||
Properties="Configuration=$(Configuration);MvcBuildViews=$(MvcBuildViews)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileMsBuildTasks">
|
||||
@ -150,12 +161,13 @@
|
||||
<NUnit Assemblies="@(TestAssemblies)" ToolPath="@(NUnitPackageToolsFolder)" WorkingDirectory="$(CompileFolder)" OutputXmlFile="$(BuildFolder)\Orchard.Tests.xml" ExcludeCategory="longrunning" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Spec" DependsOnTargets="Package-Stage">
|
||||
|
||||
<CreateItem Include="$(CompileFolder)\*.Specs.dll">
|
||||
<Target Name="Spec" DependsOnTargets="Compile">
|
||||
<!-- Running SpecFlow tests -->
|
||||
<CreateItem Include="$(CompileFolder)\*.Specs.*dll">
|
||||
<Output TaskParameter="Include" ItemName="SpecAssemblies" />
|
||||
</CreateItem>
|
||||
<NUnit Assemblies="@(SpecAssemblies)" ToolPath="$(NUnitPackageToolsFolder)" />
|
||||
|
||||
<NUnit Assemblies="@(SpecAssemblies)" ToolPath="@(NUnitPackageToolsFolder)" WorkingDirectory="$(CompileFolder)" OutputXmlFile="$(BuildFolder)\Orchard.Specs.xml" />
|
||||
</Target>
|
||||
|
||||
<!-- Packaging (Stage) -->
|
||||
@ -367,11 +379,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(Profiling-Web)" DestinationFolder="$(ProfilingFolder)\%(RecursiveDir)"/>
|
||||
|
||||
<XmlUpdate XmlFileName="$(ProfilingFolder)\web.config"
|
||||
XPath="/configuration/system.web/trust/@level"
|
||||
Value="Full" />
|
||||
|
||||
</Target>
|
||||
|
||||
<Target Name="Profiling-Setup">
|
||||
@ -379,7 +386,7 @@
|
||||
<Output TaskParameter="Lines" ItemName="ProfilingSetupCommands"/>
|
||||
</ReadLinesFromFile>
|
||||
|
||||
<Exec Command="$(ProfilingFolder)\bin\Orchard.exe %(ProfilingSetupCommands.Identity)" WorkingDirectory="$(ProfilingFolder)"/>
|
||||
<Exec Command=""$(ProfilingFolder)\bin\Orchard.exe" %(ProfilingSetupCommands.Identity)" WorkingDirectory="$(ProfilingFolder)"/>
|
||||
</Target>
|
||||
|
||||
<!-- Gallery Packaging -->
|
||||
|
37
README.md
37
README.md
@ -6,54 +6,47 @@ Orchard is a free, open source, community-focused Content Management System buil
|
||||
|
||||
You can try it for free on [DotNest.com](https://dotnest.com) or on Microsoft Azure by clicking on this button.
|
||||
|
||||
[](https://portal.azure.com/#create/OutercurveFoundation.OrchardCMS.1.0.4)
|
||||
[](https://portal.azure.com/#create/OutercurveFoundation.OrchardCMS)
|
||||
|
||||
## About The Orchard Project
|
||||
|
||||
#### Please visit our website at http://orchardproject.net for the most current information about this project.
|
||||
#### Please visit our website at https://orchardproject.net for the most current information about this project.
|
||||
|
||||
Orchard is a free, open source, community-focused **Content Management System** built on the ASP.NET MVC platform.
|
||||
|
||||
Orchard is built on a modern architecture that puts extensibility up-front, as its number one concern. All components in Orchard can be replaced or extended. Content is built from easily composable building blocks. Modules extend the system in a very decoupled fashion, where a commenting module for example can as easily apply to pages, blog posts, photos or products. A rich UI composition system completes the picture and ensures that you can get the exact presentation that you need for your content.
|
||||
|
||||
Orchard is delivered under the [.NET Foundation](http://www.dotnetfoundation.org/orchard). It is licensed under a [New BSD license](http://www.opensource.org/licenses/bsd-license.php), which is approved by the OSI.
|
||||
Orchard is delivered under the [.NET Foundation](https://www.dotnetfoundation.org/projects?searchquery=Orchard&type=project). It is licensed under a [New BSD license](https://www.opensource.org/licenses/bsd-license.php), which is approved by the OSI.
|
||||
|
||||
Our mission is to empower our users and foster a dedicated and diverse community that builds the CMS that we all want to use.
|
||||
|
||||
## Project Status
|
||||
|
||||
Orchard is currently in version **1.10** and **1.9.3**:
|
||||
|
||||
- *1.10* is the latest major version which introduces more impactful changes and new features as well. If you're new to Orchard, you should start with this version.
|
||||
- *1.9.3* contains further bugfixes in addition to *1.9.2* and these versions are based on the feature set of Orchard *1.9*.
|
||||
Orchard is currently in version **[1.10.3](https://github.com/OrchardCMS/Orchard/releases/tag/1.10.3)**: It contains bugfixes and the more impactful changes and new features added in the latest major version (*1.10*).
|
||||
|
||||
We invite participation by the developer community in shaping the project’s direction, so that we can publicly validate our designs and development approach.
|
||||
All our releases are available on our [Releases](https://github.com/OrchardCMS/Orchard/releases) page, and it's easy to [Install Orchard using the Web Platform Installer](http://docs.orchardproject.net/Documentation/Installing-Orchard) as well. We encourage interested developers to check out the source code on the Orchard GitHub site and get involved with the project.
|
||||
All our releases are available on our [Releases](https://github.com/OrchardCMS/Orchard/releases) page, and we encourage interested developers to check out the source code on the Orchard GitHub site and get involved with the project.
|
||||
|
||||
* [Download the latest release](https://github.com/OrchardCMS/Orchard/releases)
|
||||
* [Feature roadmap](http://docs.orchardproject.net/Documentation/feature-roadmap)
|
||||
* [Docs and designs/specs](http://www.orchardproject.net/docs)
|
||||
* [About us](http://www.orchardproject.net/about)
|
||||
* [Contact us](mailto:ofeedbk@microsoft.com)
|
||||
* [Feature roadmap](https://docs.orchardproject.net/en/latest/Documentation/Feature-roadmap/)
|
||||
* [Docs and designs/specs](https://docs.orchardproject.net)
|
||||
|
||||
## How To Get Involved
|
||||
|
||||
We hope that by engaging with the community we will continue to shape Orchard into a valuable set of tools and applications. The Orchard team is committed to open community participation and accepts code contributions. We encourage community participation at all levels from general project feedback to bug fixes and patches.
|
||||
|
||||
There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution):
|
||||
There are many ways you can contribute to Orchard:
|
||||
|
||||
* [Check out the code](https://github.com/OrchardCMS/Orchard)
|
||||
* [Write documentation](https://github.com/OrchardCMS/OrchardDoc)
|
||||
* [Find and file a bug](https://github.com/OrchardCMS/Orchard/issues)
|
||||
* [Propose a feature idea](http://orchard.uservoice.com)
|
||||
* [Ask and answer questions in our forums](http://www.orchardproject.net/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms)
|
||||
* [Propose a feature idea](https://github.com/OrchardCMS/Orchard/issues/new)
|
||||
* [Ask and answer questions on Stack Overflow](https://stackoverflow.com/questions/tagged/orchardcms)
|
||||
* [Participate in our gitter.im chatroom](https://gitter.im/OrchardCMS/Orchard)
|
||||
* [Participate in forum discussions](http://orchard.codeplex.com/discussions)
|
||||
* [Submit a pull request](http://docs.orchardproject.net/Documentation/Contributing-patches)
|
||||
* [Translate Orchard](http://orchardproject.net/localization)
|
||||
* [Contribute modules and themes to our gallery](http://gallery.orchardproject.net/)
|
||||
* [Send us feedback](mailto:ofeedbk@microsoft.com)
|
||||
* [Submit a pull request](https://docs.orchardproject.net/en/latest/Documentation/Contributing-patches/)
|
||||
* [Translate Orchard](https://crowdin.com/project/orchard-cms)
|
||||
* [Contribute modules and themes to our gallery](https://gallery.orchardproject.net/)
|
||||
|
||||
## The Future Of Orchard CMS: Orchard 2
|
||||
## The Future Of Orchard CMS: Orchard Core
|
||||
|
||||
As the underlying frameworks (.NET, ASP.NET and ASP.NET MVC) are constantly evolving, Orchard of course keeps track of the changes and improvements of these: Orchard 2 is the next generation of Orchard releases that is based on [ASP.NET Core](http://www.asp.net/core). Just like the current Orchard project, it's fully [open-source and is publicly available on GitHub](https://github.com/OrchardCMS/Orchard2). Orchard 2 (as a framework) is being built from scratch: it's still in development and does not share any of its code base (at least directly) with the current versions of Orchard.
|
||||
As the underlying frameworks (.NET, ASP.NET and ASP.NET MVC) are constantly evolving, Orchard of course keeps track of the changes and improvements of these: Orchard Core is the next generation of Orchard releases that is based on [ASP.NET Core](https://www.asp.net/core). Just like the current Orchard project, it's fully [open-source and is publicly available on GitHub](https://github.com/OrchardCMS/OrchardCore). Orchard Core (as a framework) is being built from scratch: it's still in development and does not share any of its code base (at least directly) with the current versions (1.x) of Orchard.
|
||||
|
21
SECURITY.md
Normal file
21
SECURITY.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.0 | :x: |
|
||||
| 1.1 | :x: |
|
||||
| 1.2 | :x: |
|
||||
| 1.3 | :x: |
|
||||
| 1.4 | :x: |
|
||||
| 1.5 | :x: |
|
||||
| 1.6 | :x: |
|
||||
| 1.7 | :x: |
|
||||
| 1.8 | :x: |
|
||||
| 1.9 | :x: |
|
||||
| 1.10 | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Send an email to sebros@microsoft.com
|
@ -72,7 +72,7 @@ call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\src\Orchard.sln"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
|
||||
:: 2. Build to the temporary path
|
||||
call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\Orchard.proj" /t:Precompiled /v:m
|
||||
call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\Orchard.proj" /t:Precompiled /v:m /m
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
|
||||
:: 3. KuduSync
|
||||
|
119
deploy.ps1
Normal file
119
deploy.ps1
Normal file
@ -0,0 +1,119 @@
|
||||
# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7#erroractionpreference
|
||||
$ErrorActionPreference = "Continue" # Just explicit set it
|
||||
|
||||
Import-Module -Name ./DeploymentUtility -Force
|
||||
|
||||
"Verify if Node.js installed"
|
||||
if (-not (Get-Command -Name node -ErrorAction Ignore)) {
|
||||
throw (
|
||||
"Missing Node.js executable, please install Node.js." +
|
||||
"If already installed, make sure it can be reached from the current environment."
|
||||
)
|
||||
}
|
||||
|
||||
$ARTIFACTS = "$PSScriptRoot/../artifacts"
|
||||
# Set deployment source folder
|
||||
if (-not $Env:DEPLOYMENT_SOURCE) {
|
||||
'Set $DEPLOYMENT_SOURCE variable from the current directory'
|
||||
$Env:DEPLOYMENT_SOURCE = $PSScriptRoot
|
||||
}
|
||||
|
||||
if (-not $Env:DEPLOYMENT_TARGET) {
|
||||
'Set $DEPLOYMENT_TARGET variable'
|
||||
$Env:DEPLOYMENT_TARGET = "$ARTIFACTS/wwwroot"
|
||||
}
|
||||
|
||||
if (-not $Env:NEXT_MANIFEST_PATH) {
|
||||
'Set $NEXT_MANIFEST_PATH variable'
|
||||
$Env:NEXT_MANIFEST_PATH = "$ARTIFACTS/manifest"
|
||||
|
||||
if (-not $Env:PREVIOUS_MANIFEST_PATH) {
|
||||
'Set $PREVIOUS_MANIFEST_PATH variable'
|
||||
$Env:PREVIOUS_MANIFEST_PATH = "$ARTIFACTS/manifest"
|
||||
}
|
||||
}
|
||||
|
||||
# Log environment variables
|
||||
$environmentNameToWriteValue = @(
|
||||
"DEPLOYMENT_SOURCE"
|
||||
"DEPLOYMENT_TARGET"
|
||||
"NEXT_MANIFEST_PATH"
|
||||
"PREVIOUS_MANIFEST_PATH"
|
||||
"WEBSITE_NODE_DEFAULT_VERSION"
|
||||
"WEBSITE_NPM_DEFAULT_VERSION"
|
||||
"SCM_REPOSITORY_PATH"
|
||||
"SOLUTION_PATH"
|
||||
"PROJECT_PATH"
|
||||
"MSBUILD_PATH"
|
||||
"Path"
|
||||
)
|
||||
Write-EnviromentValue -EnvironmentName $environmentNameToWriteValue
|
||||
|
||||
################ Build Node.js project with yarn if there is yarn.lock file ################
|
||||
$nodeProjectsDir = Get-ChildItem -Path . -Recurse -Filter "yarn.lock" |
|
||||
Select-Object -ExpandProperty DirectoryName -Unique |
|
||||
Where-Object { $_ -NotMatch "node_modules" }
|
||||
|
||||
"Node projects directory:"
|
||||
$nodeProjectsDir
|
||||
|
||||
Install-Yarn
|
||||
|
||||
$nodeProjectsDir | Foreach-Object {
|
||||
$projectDir = $_
|
||||
Push-Location -Path $projectDir
|
||||
|
||||
"Current Node project directory is $(Get-Location)"
|
||||
"Installing npm packages with yarn"
|
||||
Invoke-ExternalCommand -ScriptBlock { yarn install }
|
||||
|
||||
"Building Node.js project with yarn"
|
||||
Invoke-ExternalCommand -ScriptBlock { yarn build }
|
||||
Pop-Location
|
||||
}
|
||||
###########################################################################################
|
||||
|
||||
# Build .NET project
|
||||
"Restore NuGet packages"
|
||||
# REF https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-restore#options
|
||||
$msBuildDir = Split-Path -Path $Env:MSBUILD_PATH -Parent
|
||||
Invoke-ExternalCommand -ScriptBlock { ./lib/nuget/nuget.exe restore "$Env:SOLUTION_PATH" -MSBuildPath "$msBuildDir" }
|
||||
|
||||
"Build .NET project to the pre-compiled directory"
|
||||
$preCompiledDir = "$Env:DEPLOYMENT_SOURCE/build/Precompiled"
|
||||
|
||||
"Build .NET project to the temp directory"
|
||||
"Building the project with MSBuild to '$preCompiledDir'"
|
||||
Invoke-ExternalCommand -ScriptBlock {
|
||||
cmd /c "$Env:MSBUILD_PATH" `
|
||||
"$Env:PROJECT_PATH" `
|
||||
/t:Precompiled `
|
||||
/p:PreCompiledDir=$preCompiledDir `
|
||||
/verbosity:minimal `
|
||||
/maxcpucount `
|
||||
/nologo `
|
||||
$Env:SCM_BUILD_ARGS
|
||||
# Set SCM_BUILD_ARGS as App Service Configuration to any string you want to append to the MSBuild command line.
|
||||
}
|
||||
|
||||
Install-KuduSync
|
||||
|
||||
"Syncing a build output to a deployment folder"
|
||||
Invoke-ExternalCommand -ScriptBlock {
|
||||
cmd /c kudusync `
|
||||
-f "$preCompiledDir" `
|
||||
-t "$Env:DEPLOYMENT_TARGET" `
|
||||
-n "$Env:NEXT_MANIFEST_PATH" `
|
||||
-p "$Env:PREVIOUS_MANIFEST_PATH" `
|
||||
-i ".git;.hg;.deployment;deploy.cmd;deploy.ps1;node_modules;"
|
||||
}
|
||||
|
||||
if ($Env:POST_DEPLOYMENT_ACTION) {
|
||||
"Post deployment stub"
|
||||
Invoke-ExternalCommand -ScriptBlock { $Env:POST_DEPLOYMENT_ACTION }
|
||||
}
|
||||
|
||||
"Deployment successfully"
|
Binary file not shown.
@ -1,4 +0,0 @@
|
||||
This library has been modified to be compatible with NH 3.3.
|
||||
The file DetachedCriteriaAdapter.cs in this folder is used instead of the original onw from soure code.
|
||||
|
||||
Source code can be found at http://sourceforge.net/projects/nhcontrib/files/NHibernate.Linq/1.0/NHibernate.Linq-1.0.0.GA-src.zip
|
Binary file not shown.
BIN
lib/vswhere/vswhere.exe
Normal file
BIN
lib/vswhere/vswhere.exe
Normal file
Binary file not shown.
11
src/.editorconfig
Normal file
11
src/.editorconfig
Normal file
@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = crlf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.cs]
|
||||
csharp_new_line_before_open_brace = none
|
||||
dotnet_sort_system_directives_first = true
|
133
src/Gulpfile.js
133
src/Gulpfile.js
@ -10,8 +10,10 @@ var fs = require("fs"),
|
||||
plumber = require("gulp-plumber"),
|
||||
sourcemaps = require("gulp-sourcemaps"),
|
||||
less = require("gulp-less"),
|
||||
cssnano = require("gulp-cssnano"),
|
||||
sass = require("gulp-sass"),
|
||||
postcss = require("gulp-postcss"),
|
||||
autoprefixer = require("autoprefixer"),
|
||||
cssnano = require("cssnano"),
|
||||
typescript = require("gulp-typescript"),
|
||||
uglify = require("gulp-uglify"),
|
||||
rename = require("gulp-rename"),
|
||||
@ -95,10 +97,16 @@ function resolveAssetGroupPaths(assetGroup, assetManifestPath) {
|
||||
assetGroup.manifestPath = assetManifestPath;
|
||||
assetGroup.basePath = path.dirname(assetManifestPath);
|
||||
assetGroup.inputPaths = assetGroup.inputs.map(function (inputPath) {
|
||||
return path.resolve(path.join(assetGroup.basePath, inputPath));
|
||||
var excludeFile = false;
|
||||
if (inputPath.startsWith('!')) {
|
||||
inputPath = inputPath.slice(1);
|
||||
excludeFile = true;
|
||||
}
|
||||
var newPath = path.resolve(path.join(assetGroup.basePath, inputPath));
|
||||
return (excludeFile ? '!' : '') + newPath;
|
||||
});
|
||||
assetGroup.watchPaths = [];
|
||||
if (!!assetGroup.watch) {
|
||||
if (assetGroup.watch) {
|
||||
assetGroup.watchPaths = assetGroup.watch.map(function (watchPath) {
|
||||
return path.resolve(path.join(assetGroup.basePath, watchPath));
|
||||
});
|
||||
@ -111,12 +119,6 @@ function resolveAssetGroupPaths(assetGroup, assetManifestPath) {
|
||||
function createAssetGroupTask(assetGroup, doRebuild) {
|
||||
var outputExt = path.extname(assetGroup.output).toLowerCase();
|
||||
var doConcat = path.basename(assetGroup.outputFileName, outputExt) !== "@";
|
||||
if (doConcat && !doRebuild) {
|
||||
// Force a rebuild of this asset group is the asset manifest file itself is newer than the output.
|
||||
var assetManifestStats = fs.statSync(assetGroup.manifestPath);
|
||||
var outputStats = fs.existsSync(assetGroup.outputPath) ? fs.statSync(assetGroup.outputPath) : null;
|
||||
doRebuild = !outputStats || assetManifestStats.mtime > outputStats.mtime;
|
||||
}
|
||||
switch (outputExt) {
|
||||
case ".css":
|
||||
return buildCssPipeline(assetGroup, doConcat, doRebuild);
|
||||
@ -136,51 +138,65 @@ function buildCssPipeline(assetGroup, doConcat, doRebuild) {
|
||||
throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
|
||||
});
|
||||
var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
|
||||
var containsLessOrScss = assetGroup.inputPaths.some(function (inputPath) {
|
||||
var ext = path.extname(inputPath).toLowerCase();
|
||||
return ext === ".less" || ext === ".scss";
|
||||
});
|
||||
// Source maps are useless if neither concatenating nor transforming.
|
||||
if ((!doConcat || assetGroup.inputPaths.length < 2) && !assetGroup.inputPaths.some(function (inputPath) { return path.extname(inputPath).toLowerCase() === ".less"; }))
|
||||
if ((!doConcat || assetGroup.inputPaths.length < 2) && !containsLessOrScss)
|
||||
generateSourceMaps = false;
|
||||
var minifiedStream = gulp.src(assetGroup.inputPaths) // Minified output, source mapping completely disabled.
|
||||
.pipe(gulpif(!doRebuild,
|
||||
gulpif(doConcat,
|
||||
newer(assetGroup.outputPath),
|
||||
newer({
|
||||
dest: assetGroup.outputDir,
|
||||
ext: ".css"
|
||||
}))))
|
||||
newer({
|
||||
dest: doConcat ? assetGroup.outputPath : assetGroup.outputDir,
|
||||
ext: doConcat ? null : ".css",
|
||||
extra: assetGroup.manifestPath // Force a rebuild of this asset group is the asset manifest file itself is newer than the output(s).
|
||||
})
|
||||
))
|
||||
.pipe(plumber())
|
||||
.pipe(gulpif("*.less", less()))
|
||||
.pipe(gulpif("*.scss", sass({
|
||||
precision: 10
|
||||
precision: 10
|
||||
})))
|
||||
.pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
|
||||
.pipe(cssnano({
|
||||
autoprefixer: { browsers: ["last 2 versions"] },
|
||||
discardComments: { removeAll: true },
|
||||
discardUnused: false,
|
||||
mergeIdents: false,
|
||||
reduceIdents: false,
|
||||
zindex: false
|
||||
}))
|
||||
.pipe(rename({
|
||||
suffix: ".min"
|
||||
}))
|
||||
.pipe(postcss([
|
||||
autoprefixer({ browsers: ["last 2 versions"] }),
|
||||
cssnano({
|
||||
discardComments: { removeAll: true },
|
||||
discardUnused: false,
|
||||
mergeIdents: false,
|
||||
reduceIdents: false,
|
||||
zindex: false
|
||||
})
|
||||
]))
|
||||
.pipe(eol())
|
||||
.pipe(rename(function (path) {
|
||||
if (assetGroup.flatten)
|
||||
path.dirname = "";
|
||||
if (assetGroup.separateMinified)
|
||||
path.dirname += "/min";
|
||||
else
|
||||
path.basename += ".min";
|
||||
}))
|
||||
.pipe(gulp.dest(assetGroup.outputDir));
|
||||
var devStream = gulp.src(assetGroup.inputPaths) // Non-minified output, with source mapping
|
||||
var devStream = gulp.src(assetGroup.inputPaths) // Non-minified output, with source mapping.
|
||||
.pipe(gulpif(!doRebuild,
|
||||
gulpif(doConcat,
|
||||
newer(assetGroup.outputPath),
|
||||
newer({
|
||||
dest: assetGroup.outputDir,
|
||||
ext: ".css"
|
||||
}))))
|
||||
newer({
|
||||
dest: doConcat ? assetGroup.outputPath : assetGroup.outputDir,
|
||||
ext: doConcat ? null : ".css",
|
||||
extra: assetGroup.manifestPath // Force a rebuild of this asset group is the asset manifest file itself is newer than the output(s).
|
||||
})
|
||||
))
|
||||
.pipe(plumber())
|
||||
.pipe(gulpif(generateSourceMaps, sourcemaps.init()))
|
||||
.pipe(gulpif("*.less", less()))
|
||||
.pipe(gulpif("*.scss", sass({
|
||||
precision: 10
|
||||
precision: 10
|
||||
})))
|
||||
.pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
|
||||
.pipe(postcss([
|
||||
autoprefixer({ browsers: ["last 2 versions"] })
|
||||
]))
|
||||
.pipe(header(
|
||||
"/*\n" +
|
||||
"** NOTE: This file is generated by Gulp and should not be edited directly!\n" +
|
||||
@ -188,6 +204,10 @@ function buildCssPipeline(assetGroup, doConcat, doRebuild) {
|
||||
"*/\n\n"))
|
||||
.pipe(gulpif(generateSourceMaps, sourcemaps.write()))
|
||||
.pipe(eol())
|
||||
.pipe(rename(function (path) {
|
||||
if (assetGroup.flatten)
|
||||
path.dirname = "";
|
||||
}))
|
||||
.pipe(gulp.dest(assetGroup.outputDir));
|
||||
return merge([minifiedStream, devStream]);
|
||||
}
|
||||
@ -199,37 +219,44 @@ function buildJsPipeline(assetGroup, doConcat, doRebuild) {
|
||||
throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
|
||||
});
|
||||
var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
|
||||
// Source maps are useless if neither concatenating nor transforming.
|
||||
// Source maps are useless if neither concatenating nor transpiling.
|
||||
if ((!doConcat || assetGroup.inputPaths.length < 2) && !assetGroup.inputPaths.some(function (inputPath) { return path.extname(inputPath).toLowerCase() === ".ts"; }))
|
||||
generateSourceMaps = false;
|
||||
var typeScriptOptions = { allowJs: true, noImplicitAny: true, noEmitOnError: true, module: 'amd' };
|
||||
if (assetGroup.typeScriptOptions)
|
||||
typeScriptOptions = Object.assign(typeScriptOptions, assetGroup.typeScriptOptions); // Merge override options from asset group if any.
|
||||
if (doConcat)
|
||||
typeScriptOptions.outFile = assetGroup.outputFileName;
|
||||
return gulp.src(assetGroup.inputPaths)
|
||||
.pipe(gulpif(!doRebuild,
|
||||
gulpif(doConcat,
|
||||
newer(assetGroup.outputPath),
|
||||
newer({
|
||||
dest: assetGroup.outputDir,
|
||||
ext: ".js"
|
||||
}))))
|
||||
newer({
|
||||
dest: doConcat ? assetGroup.outputPath : assetGroup.outputDir,
|
||||
ext: doConcat ? null : ".js",
|
||||
extra: assetGroup.manifestPath // Force a rebuild of this asset group is the asset manifest file itself is newer than the output(s).
|
||||
})
|
||||
))
|
||||
.pipe(plumber())
|
||||
.pipe(gulpif(generateSourceMaps, sourcemaps.init()))
|
||||
.pipe(gulpif("*.ts", typescript({
|
||||
declaration: false,
|
||||
noImplicitAny: true,
|
||||
noEmitOnError: true,
|
||||
sortOutput: true,
|
||||
}).js))
|
||||
.pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
|
||||
.pipe(typescript(typeScriptOptions))
|
||||
.pipe(header(
|
||||
"/*\n" +
|
||||
"** NOTE: This file is generated by Gulp and should not be edited directly!\n" +
|
||||
"** Any changes made directly to this file will be overwritten next time its asset group is processed by Gulp.\n" +
|
||||
"*/\n\n"))
|
||||
.pipe(gulpif(generateSourceMaps, sourcemaps.write()))
|
||||
.pipe(eol())
|
||||
.pipe(rename(function (path) {
|
||||
if (assetGroup.flatten)
|
||||
path.dirname = "";
|
||||
}))
|
||||
.pipe(gulp.dest(assetGroup.outputDir))
|
||||
.pipe(uglify())
|
||||
.pipe(rename({
|
||||
suffix: ".min"
|
||||
}))
|
||||
.pipe(eol())
|
||||
.pipe(rename(function (path) {
|
||||
if (assetGroup.separateMinified)
|
||||
path.dirname += "/min";
|
||||
else
|
||||
path.basename += ".min";
|
||||
}))
|
||||
.pipe(gulp.dest(assetGroup.outputDir));
|
||||
}
|
||||
|
27
src/Libraries/NHibernate/NHibernate.Linq/AssemblyInfo.cs
Normal file
27
src/Libraries/NHibernate/NHibernate.Linq/AssemblyInfo.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:2.0.50727.4016
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[assembly: CLSCompliantAttribute(true)]
|
||||
[assembly: AssemblyTitleAttribute("NHibernate.Linq")]
|
||||
[assembly: AssemblyDescriptionAttribute("A linq provider for NHibernate")]
|
||||
[assembly: AssemblyCompanyAttribute("NHForge.org")]
|
||||
[assembly: AssemblyProductAttribute("NHibernate.Linq")]
|
||||
[assembly: AssemblyCopyrightAttribute("Licensed under LGPL.")]
|
||||
[assembly: AssemblyVersionAttribute("1.0.0.4000")]
|
||||
[assembly: AssemblyInformationalVersionAttribute("1.0.0.4000")]
|
||||
[assembly: AssemblyFileVersionAttribute("1.0.0.4000")]
|
||||
[assembly: AssemblyDelaySignAttribute(false)]
|
||||
[assembly: AllowPartiallyTrustedCallersAttribute()]
|
||||
|
@ -0,0 +1,35 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps an ICriteria object providing results when necessary.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class CriteriaResultReader<T> : IEnumerable<T>, IEnumerable
|
||||
{
|
||||
private readonly ICriteria _criteria;
|
||||
|
||||
public CriteriaResultReader(ICriteria criteria)
|
||||
{
|
||||
_criteria = criteria;
|
||||
}
|
||||
|
||||
private IList List()
|
||||
{
|
||||
return _criteria.List();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
foreach (var item in List())
|
||||
yield return (T)item;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return List().GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class CollectionAccessExpression : PropertyAccessExpression
|
||||
{
|
||||
private readonly EntityExpression _elementExpression;
|
||||
|
||||
public EntityExpression ElementExpression
|
||||
{
|
||||
get { return _elementExpression; }
|
||||
}
|
||||
|
||||
public CollectionAccessExpression(string name, System.Type type, IType nhibernateType,
|
||||
EntityExpression expression, EntityExpression elementExpression)
|
||||
: base(name, type, nhibernateType, expression, NHibernateExpressionType.CollectionAccess)
|
||||
{
|
||||
_elementExpression = elementExpression;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Metadata;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class EntityExpression : NHibernateExpression
|
||||
{
|
||||
private readonly string _alias;
|
||||
private readonly string _associationPath;
|
||||
private readonly IClassMetadata _metaData;
|
||||
private readonly Expression _expression;
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
}
|
||||
|
||||
public string AssociationPath
|
||||
{
|
||||
get { return _associationPath; }
|
||||
}
|
||||
|
||||
public IClassMetadata MetaData
|
||||
{
|
||||
get { return _metaData; }
|
||||
}
|
||||
|
||||
public Expression Expression
|
||||
{
|
||||
get { return _expression; }
|
||||
}
|
||||
|
||||
public EntityExpression(string associationPath, string alias, System.Type type, IClassMetadata metaData, Expression expression)
|
||||
: base(IsRoot(expression) ? NHibernateExpressionType.RootEntity : NHibernateExpressionType.Entity, type)
|
||||
{
|
||||
_associationPath = associationPath;
|
||||
_alias = alias;
|
||||
_metaData = metaData;
|
||||
_expression = expression;
|
||||
}
|
||||
|
||||
private static bool IsRoot(Expression expr)
|
||||
{
|
||||
if (expr == null) return true;
|
||||
if (!(expr is EntityExpression)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Alias;
|
||||
}
|
||||
|
||||
public virtual string GetAliasedIdentifierPropertyName()
|
||||
{
|
||||
if ((NHibernateExpressionType)this.NodeType == NHibernateExpressionType.RootEntity)
|
||||
{
|
||||
return this.MetaData.IdentifierPropertyName;
|
||||
}
|
||||
return string.Format("{0}.{1}", this.Alias, this.MetaData.IdentifierPropertyName);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public abstract class NHibernateExpression : Expression
|
||||
{
|
||||
|
||||
public NHibernateExpression(NHibernateExpressionType nodeType, System.Type type)
|
||||
: base() {
|
||||
|
||||
_nodeType = nodeType;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
private readonly NHibernateExpressionType _nodeType;
|
||||
public override ExpressionType NodeType { get { return (ExpressionType)_nodeType; } }
|
||||
private readonly System.Type _type;
|
||||
public override System.Type Type { get { return _type; } }
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extended node types for custom expressions
|
||||
/// </summary>
|
||||
public enum NHibernateExpressionType
|
||||
{
|
||||
QuerySource = 1000, //make sure these don't overlap with ExpressionType
|
||||
RootEntity,
|
||||
Entity,
|
||||
PropertyAccess,
|
||||
CollectionAccess
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class PropertyAccessExpression : NHibernateExpression
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly EntityExpression _expression;
|
||||
private readonly IType _nhibernateType;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public EntityExpression Expression
|
||||
{
|
||||
get { return _expression; }
|
||||
}
|
||||
|
||||
public IType NHibernateType
|
||||
{
|
||||
get { return _nhibernateType; }
|
||||
}
|
||||
|
||||
public PropertyAccessExpression(string name, System.Type type, IType nhibernateType, EntityExpression expression)
|
||||
: this(name, type, nhibernateType, expression, NHibernateExpressionType.PropertyAccess) { }
|
||||
|
||||
protected PropertyAccessExpression(string name, System.Type type, IType nhibernateType, EntityExpression expression, NHibernateExpressionType nodeType)
|
||||
: base(nodeType, type)
|
||||
{
|
||||
if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
|
||||
if (type == null) throw new ArgumentNullException("type");
|
||||
if (nhibernateType == null) throw new ArgumentNullException("nhibernateType");
|
||||
if (expression == null) throw new ArgumentNullException("expression");
|
||||
|
||||
_name = name;
|
||||
_expression = expression;
|
||||
_nhibernateType = nhibernateType;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Expression.ToString() + "." + this.Name;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class QuerySourceExpression : NHibernateExpression
|
||||
{
|
||||
private readonly string _alias;
|
||||
private readonly IQueryable _query;
|
||||
private readonly System.Type _elementType;
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
}
|
||||
|
||||
public IQueryable Query
|
||||
{
|
||||
get { return _query; }
|
||||
}
|
||||
|
||||
public System.Type ElementType
|
||||
{
|
||||
get { return _elementType ?? Query.ElementType; }
|
||||
}
|
||||
|
||||
public QuerySourceExpression(string alias, IQueryable query)
|
||||
: this(alias, query, null) { }
|
||||
|
||||
public QuerySourceExpression(string alias, IQueryable query, System.Type elementType)
|
||||
: base(NHibernateExpressionType.QuerySource, query.GetType())
|
||||
{
|
||||
_alias = alias;
|
||||
_query = query;
|
||||
_elementType = elementType;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Alias))
|
||||
return Alias;
|
||||
|
||||
return base.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class SqlAggregateFunctionProjection : AggregateProjection
|
||||
{
|
||||
public SqlAggregateFunctionProjection(string functionName, string propertyName)
|
||||
: this(functionName, propertyName, null)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlAggregateFunctionProjection(string functionName, string propertyName, System.Type returnType)
|
||||
: this(functionName, propertyName, returnType, null)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlAggregateFunctionProjection(string functionName, string propertyName, System.Type returnType, object[] paramValues)
|
||||
: this(functionName, propertyName, 0, returnType, paramValues)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlAggregateFunctionProjection(string functionName, string propertyName, int propertyPosition, System.Type returnType,
|
||||
object[] paramValues)
|
||||
: base(functionName, propertyName)
|
||||
{
|
||||
ReturnType = returnType;
|
||||
ParameterValues = paramValues;
|
||||
PropertyPosition = propertyPosition;
|
||||
}
|
||||
|
||||
public System.Type ReturnType { get; private set; }
|
||||
public Object[] ParameterValues { get; private set; }
|
||||
public int PropertyPosition { get; private set; }
|
||||
|
||||
public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
|
||||
{
|
||||
if (ReturnType != null)
|
||||
{
|
||||
return new[] { TypeFactory.HeuristicType(ReturnType.Name) };
|
||||
}
|
||||
|
||||
return base.GetTypes(criteria, criteriaQuery);
|
||||
}
|
||||
|
||||
public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery)
|
||||
{
|
||||
if (ParameterValues != null && ParameterValues.Length > 0)
|
||||
{
|
||||
var sql = new SqlStringBuilder();
|
||||
sql.Add(aggregate).Add("(");
|
||||
bool hasProperty = false;
|
||||
bool hasParameter = false;
|
||||
|
||||
for (int i = 0; i < ParameterValues.Length; i++)
|
||||
{
|
||||
if (PropertyPosition == i)
|
||||
{
|
||||
if (i > 0) sql.Add(", ");
|
||||
sql.Add(criteriaQuery.GetColumn(criteria, propertyName)).Add(", ");
|
||||
hasProperty = true;
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
sql.Add(", ");
|
||||
}
|
||||
|
||||
sql.Add(LinqUtil.SqlEncode(ParameterValues[i]));
|
||||
hasParameter = true;
|
||||
}
|
||||
if (!hasProperty)
|
||||
{
|
||||
if (hasParameter) sql.Add(", ");
|
||||
sql.Add(criteriaQuery.GetColumn(criteria, propertyName));
|
||||
}
|
||||
|
||||
return sql.Add(") as y").Add(loc.ToString()).Add("_").ToSqlString();
|
||||
}
|
||||
|
||||
// if ParameterValues were not specified, we defer to the base functionality
|
||||
return base.ToSqlString(criteria, loc, criteriaQuery);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
/// <summary>
|
||||
/// Associates a method with a corresponding SQL function.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public class SqlFunctionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.Expressions.SqlFunctionAttribute"/> class.
|
||||
/// </summary>
|
||||
public SqlFunctionAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.Expressions.SqlFunctionAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="owner">The name of the schema that owns the SQL function.</param>
|
||||
public SqlFunctionAttribute(string owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the schema that owns the SQL function.
|
||||
/// </summary>
|
||||
public string Owner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position of the function parameter that accepts the property name.
|
||||
/// </summary>
|
||||
public int PropertyPosition { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace NHibernate.Linq.Expressions
|
||||
{
|
||||
public class SqlFunctionExpression : ICriterion
|
||||
{
|
||||
private String op;
|
||||
|
||||
public SqlFunctionExpression(String functionName, System.Type returnType, ICriterion innerCriterion)
|
||||
: this(functionName, returnType, null, null, innerCriterion, 0, null)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues,
|
||||
System.Type[] paramTypes, ICriterion innerCriterion)
|
||||
: this(functionName, returnType, paramValues, paramTypes, innerCriterion, 0, null)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues,
|
||||
System.Type[] paramTypes, ICriterion innerCriterion, int propertyPosition)
|
||||
: this(functionName, returnType, paramValues, paramTypes, innerCriterion, propertyPosition, null)
|
||||
{
|
||||
}
|
||||
|
||||
public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues,
|
||||
System.Type[] paramTypes, ICriterion innerCriterion, int propertyPosition,
|
||||
SqlFunctionExpression rightFunction)
|
||||
{
|
||||
FunctionName = functionName;
|
||||
ReturnType = returnType;
|
||||
ParameterValues = paramValues;
|
||||
ParameterTypes = paramTypes;
|
||||
InnerCriterion = innerCriterion;
|
||||
PropertyPosition = propertyPosition;
|
||||
RightFunction = rightFunction;
|
||||
}
|
||||
|
||||
private SqlFunctionExpression RightFunction { get; set; }
|
||||
public ICriterion InnerCriterion { get; set; }
|
||||
public String FunctionName { get; private set; }
|
||||
public System.Type ReturnType { get; private set; }
|
||||
public Object[] ParameterValues { get; private set; }
|
||||
public System.Type[] ParameterTypes { get; private set; }
|
||||
public int PropertyPosition { get; private set; }
|
||||
|
||||
protected virtual string Op
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(op))
|
||||
{
|
||||
op = InnerCriterion.GetType().GetProperty("Op", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.GetValue(InnerCriterion, null) as String;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
}
|
||||
|
||||
#region ICriterion Members
|
||||
|
||||
public virtual TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
|
||||
{
|
||||
var values = new List<TypedValue>();
|
||||
if (ParameterValues != null)
|
||||
{
|
||||
for (int i = 0; i < ParameterValues.Length; i++)
|
||||
{
|
||||
values.Add(new TypedValue(TypeFactory.HeuristicType(ParameterTypes[i].Name), ParameterValues[i]));
|
||||
}
|
||||
}
|
||||
if (ReturnType != null && InnerCriterion is SimpleExpression)
|
||||
{
|
||||
var simple = InnerCriterion as SimpleExpression;
|
||||
values.Add(new TypedValue(TypeFactory.HeuristicType(ReturnType.Name), simple.Value));
|
||||
}
|
||||
if (RightFunction != null)
|
||||
{
|
||||
values.AddRange(RightFunction.GetTypedValues(criteria, criteriaQuery));
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
}
|
||||
|
||||
public virtual SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
|
||||
{
|
||||
var sql = new SqlStringBuilder();
|
||||
string leftPropertyName = null;
|
||||
string rightPropertyName = null;
|
||||
|
||||
if (InnerCriterion is SimpleExpression)
|
||||
{
|
||||
leftPropertyName = ((SimpleExpression)InnerCriterion).PropertyName;
|
||||
}
|
||||
else if (InnerCriterion is PropertyExpression)
|
||||
{
|
||||
System.Type type = typeof(PropertyExpression);
|
||||
leftPropertyName =
|
||||
type.GetField("_lhsPropertyName", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(InnerCriterion) as
|
||||
String;
|
||||
rightPropertyName =
|
||||
type.GetField("_rhsPropertyName", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(InnerCriterion) as
|
||||
String;
|
||||
}
|
||||
|
||||
AddParameters(leftPropertyName, sql, criteria, criteriaQuery);
|
||||
sql.Add(" ").Add(Op).Add(" ");
|
||||
|
||||
if (RightFunction != null)
|
||||
{
|
||||
RightFunction.AddParameters(rightPropertyName, sql, criteria, criteriaQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.AddParameter();
|
||||
}
|
||||
|
||||
return sql.ToSqlString();
|
||||
}
|
||||
|
||||
public IProjection[] GetProjections()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void AddParameters(String propertyName, SqlStringBuilder sql, ICriteria criteria, ICriteriaQuery criteriaQuery)
|
||||
{
|
||||
bool hasProperty = false;
|
||||
bool hasParameter = false;
|
||||
|
||||
sql.Add(FunctionName).Add("(");
|
||||
|
||||
if (ParameterValues != null && ParameterValues.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < ParameterValues.Length; i++)
|
||||
{
|
||||
if (PropertyPosition == i)
|
||||
{
|
||||
if (i > 0) sql.Add(", ");
|
||||
sql.Add(criteriaQuery.GetColumn(criteria, propertyName)).Add(", ");
|
||||
hasProperty = true;
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
sql.Add(", ");
|
||||
}
|
||||
|
||||
sql.AddParameter();
|
||||
hasParameter = true;
|
||||
}
|
||||
}
|
||||
if (!hasProperty)
|
||||
{
|
||||
if (hasParameter) sql.Add(", ");
|
||||
sql.Add(criteriaQuery.GetColumn(criteria, propertyName));
|
||||
}
|
||||
|
||||
sql.Add(")");
|
||||
}
|
||||
}
|
||||
}
|
9
src/Libraries/NHibernate/NHibernate.Linq/IDbMethods.cs
Normal file
9
src/Libraries/NHibernate/NHibernate.Linq/IDbMethods.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface used to conditionally include database provider specific methods.
|
||||
/// </summary>
|
||||
public interface IDbMethods
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
public interface INHibernateQueryable
|
||||
{
|
||||
QueryOptions QueryOptions { get; }
|
||||
}
|
||||
|
||||
public interface INHibernateQueryable<T> : INHibernateQueryable, IOrderedQueryable<T>
|
||||
{
|
||||
IQueryable<T> Expand(string path);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<project
|
||||
name="NHibernate.Linq"
|
||||
default="build"
|
||||
xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd"
|
||||
>
|
||||
|
||||
<property name="root.dir" value="../.." />
|
||||
<include buildfile="${root.dir}/common-project.xml" />
|
||||
|
||||
<target name="init" depends="common.init">
|
||||
<property name="assembly.description" value="A linq provider for NHibernate" />
|
||||
<property name="assembly.allow-partially-trusted-callers" value="true" />
|
||||
|
||||
<assemblyfileset id="project.references" basedir="${bin.dir}" defaultexcludes="false">
|
||||
<include name="System.dll" />
|
||||
<include name="System.Core.dll" />
|
||||
<include name="System.Linq.Dynamic.dll"/>
|
||||
<include name="System.Xml.dll" />
|
||||
<include name="Iesi.Collections.dll" />
|
||||
<include name="NHibernate.dll" />
|
||||
<include name="log4net.dll" />
|
||||
<include name="System.Data.Services.dll" />
|
||||
<include name="Antlr3.Runtime.dll" />
|
||||
|
||||
</assemblyfileset>
|
||||
|
||||
<resourcefileset id="project.resources" prefix="NHibernate.Linq" dynamicprefix="true">
|
||||
<include name="*.xsd" />
|
||||
<include name="**/*.xml" />
|
||||
<exclude name="bin/**/*.xml" />
|
||||
</resourcefileset>
|
||||
|
||||
<fileset id="project.sources">
|
||||
<include name="**/*.cs" />
|
||||
</fileset>
|
||||
</target>
|
||||
|
||||
<target name="generate-assemblyinfo" depends="init common.generate-assemblyinfo" />
|
||||
|
||||
<target name="build" description="Build NHibernate.Linq"
|
||||
depends="generate-assemblyinfo common.compile-dll">
|
||||
</target>
|
||||
|
||||
</project>
|
139
src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj
Normal file
139
src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj
Normal file
@ -0,0 +1,139 @@
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{2CF9A83A-BC40-4485-A763-BFF59B2EBDAD}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NHibernate.Linq</RootNamespace>
|
||||
<AssemblyName>NHibernate.Linq</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\NH.Linq.snk</AssemblyOriginatorKeyFile>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;USING_NET_35_SP1</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="NHibernate, Version=5.3.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Remotion.Linq.EagerFetching, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.Services">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Expressions\CollectionAccessExpression.cs" />
|
||||
<Compile Include="Expressions\NHibernateExpression.cs" />
|
||||
<Compile Include="Expressions\QuerySourceExpression.cs" />
|
||||
<Compile Include="INHibernateQueryable.cs" />
|
||||
<Compile Include="QueryOptions.cs" />
|
||||
<Compile Include="Transform\TypeSafeConstructorMemberInitResultTransformer.cs" />
|
||||
<Compile Include="Util\SessionFactoryUtil.cs" />
|
||||
<Compile Include="Visitors\BinaryBooleanReducer.cs" />
|
||||
<Compile Include="Visitors\BinaryCriterionType.cs" />
|
||||
<Compile Include="Visitors\BinaryCriterionVisitor.cs" />
|
||||
<Compile Include="Visitors\BinaryCriterionDelegates.cs" />
|
||||
<Compile Include="Visitors\AssociationVisitor.cs" />
|
||||
<Compile Include="CriteriaResultReader.cs" />
|
||||
<Compile Include="Visitors\BinaryExpressionOrderer.cs" />
|
||||
<Compile Include="Visitors\CollectionAliasVisitor.cs" />
|
||||
<Compile Include="Visitors\RootVisitor.cs" />
|
||||
<Compile Include="Visitors\EntityExpressionVisitor.cs" />
|
||||
<Compile Include="Visitors\Evaluator.cs" />
|
||||
<Compile Include="Expressions\EntityExpression.cs" />
|
||||
<Compile Include="Expressions\NHibernateExpressionType.cs" />
|
||||
<Compile Include="Expressions\PropertyAccessExpression.cs" />
|
||||
<Compile Include="Visitors\InheritanceVisitor.cs" />
|
||||
<Compile Include="Visitors\MemberNameVisitor.cs" />
|
||||
<Compile Include="Visitors\ImmediateResultsVisitor.cs" />
|
||||
<Compile Include="Visitors\NHibernateExpressionVisitor.cs" />
|
||||
<Compile Include="NHibernateQueryProvider.cs" />
|
||||
<Compile Include="Query.cs" />
|
||||
<Compile Include="QueryProvider.cs" />
|
||||
<Compile Include="Visitors\PropertyToMethodVisitor.cs" />
|
||||
<Compile Include="Visitors\SelectManyVisitor.cs" />
|
||||
<Compile Include="Transform\LinqJoinResultsTransformer.cs" />
|
||||
<Compile Include="Util\DetachedCriteriaAdapter.cs" />
|
||||
<Compile Include="Util\CriteriaUtil.cs" />
|
||||
<Compile Include="Expressions\SqlFunctionAttribute.cs" />
|
||||
<Compile Include="Expressions\SqlFunctionExpression.cs" />
|
||||
<Compile Include="Expressions\SqlAggregateFunctionProjection.cs" />
|
||||
<Compile Include="Visitors\GroupingArgumentsVisitor.cs" />
|
||||
<Compile Include="Transform\LinqGroupingResultTransformer.cs" />
|
||||
<Compile Include="NHibernateExtensions.cs" />
|
||||
<Compile Include="IDbMethods.cs" />
|
||||
<Compile Include="Visitors\ExpressionVisitor.cs" />
|
||||
<Compile Include="Util\LinqUtil.cs" />
|
||||
<Compile Include="NHibernateContext.cs" />
|
||||
<Compile Include="Visitors\NHibernateQueryTranslator.cs" />
|
||||
<Compile Include="Util\QueryUtil.cs" />
|
||||
<Compile Include="Visitors\SelectArgumentsVisitor.cs" />
|
||||
<Compile Include="SqlClient\SqlClientExtensions.cs" />
|
||||
<Compile Include="Util\TypeSystem.cs" />
|
||||
<Compile Include="Visitors\WhereArgumentsVisitor.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\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>
|
432
src/Libraries/NHibernate/NHibernate.Linq/NHibernateContext.cs
Normal file
432
src/Libraries/NHibernate/NHibernate.Linq/NHibernateContext.cs
Normal file
@ -0,0 +1,432 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NHibernate.Metadata;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="T:NHibernate.ISession"/> object to provide base functionality
|
||||
/// for custom, database-specific context classes.
|
||||
/// </summary>
|
||||
public abstract class NHibernateContext : IDisposable, ICloneable, IUpdatable, IExpandProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to database provider specific methods.
|
||||
/// </summary>
|
||||
public readonly IDbMethods Methods;
|
||||
|
||||
private ISession session;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NHibernateContext"/> class.
|
||||
/// </summary>
|
||||
public NHibernateContext()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.NHibernateContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="session">An initialized <see cref="T:NHibernate.ISession"/> object.</param>
|
||||
public NHibernateContext(ISession session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the <see cref="T:NHibernate.ISession"/> associated with this object.
|
||||
/// </summary>
|
||||
public virtual ISession Session
|
||||
{
|
||||
get
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
// Attempt to get the Session
|
||||
session = ProvideSession();
|
||||
}
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Allows for empty construction but provides an interface for an interface to have the derived
|
||||
/// classes provide a session object late in the cycle.
|
||||
/// </summary>
|
||||
/// <returns>The Required <see cref="T:NHibernate.ISession"/> object.</returns>
|
||||
protected virtual ISession ProvideSession()
|
||||
{
|
||||
// Should not be called as supplying the session in the constructor
|
||||
throw new NotImplementedException("If NHibernateContext is constructed with the empty constructor, inheritor is required to override ProvideSession to supply Session.");
|
||||
}
|
||||
|
||||
#region ICloneable Members
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new object that is a copy of the current instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual object Clone()
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
throw new ArgumentNullException("session");
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(GetType(), session);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the wrapped <see cref="T:NHibernate.ISession"/> object.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
session.Dispose();
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IUpdatable Members
|
||||
|
||||
List<object> _updateCache = null;
|
||||
/// <summary>
|
||||
/// Gets the update cache.
|
||||
/// </summary>
|
||||
/// <value>The update cache.</value>
|
||||
List<object> UpdateCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_updateCache == null)
|
||||
{
|
||||
_updateCache = new List<object>();
|
||||
}
|
||||
return _updateCache;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the reference to collection.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="resourceToBeAdded">The resource to be added.</param>
|
||||
void IUpdatable.AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
|
||||
{
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName);
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new DataServiceException("Type not recognized as a valid type for this Context");
|
||||
}
|
||||
|
||||
// Get the property to use to add the resource to
|
||||
object collection = metadata.GetPropertyValue(targetResource, propertyName);
|
||||
|
||||
// Try with IList implementation first (its faster)
|
||||
if (collection is IList)
|
||||
{
|
||||
((IList)collection).Add(resourceToBeAdded);
|
||||
}
|
||||
else // Try with Reflection's Add()
|
||||
{
|
||||
MethodInfo addMethod = collection.GetType().GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (addMethod == null)
|
||||
{
|
||||
throw new DataServiceException(string.Concat("Could not determine the collection type of the ", propertyName, " property."));
|
||||
}
|
||||
addMethod.Invoke(collection, new object[] { resourceToBeAdded });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the changes.
|
||||
/// </summary>
|
||||
void IUpdatable.ClearChanges()
|
||||
{
|
||||
UpdateCache.Clear();
|
||||
session.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the resource.
|
||||
/// </summary>
|
||||
/// <param name="containerName">Name of the container.</param>
|
||||
/// <param name="fullTypeName">Full name of the type.</param>
|
||||
/// <returns>Newly created Resource</returns>
|
||||
object IUpdatable.CreateResource(string containerName, string fullTypeName)
|
||||
{
|
||||
// Get the metadata
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(fullTypeName);
|
||||
object newResource = metadata.Instantiate(null);
|
||||
|
||||
// We can't save it to the session as it may not be valid yet
|
||||
// This happens if the key is a non-initancable key (e.g. Northwind.Customers)
|
||||
// So we save them to a local cache. Only when SaveAll happens will be push them to the Session
|
||||
UpdateCache.Add(newResource);
|
||||
|
||||
// Returns the new resource
|
||||
return newResource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the resource.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
void IUpdatable.DeleteResource(object targetResource)
|
||||
{
|
||||
// Push it to the Session to support deletion
|
||||
if (UpdateCache.Contains(targetResource))
|
||||
{
|
||||
UpdateCache.Remove(targetResource);
|
||||
session.Save(targetResource);
|
||||
}
|
||||
|
||||
// Mark it as deleted
|
||||
if (session.Contains(targetResource)) session.Delete(targetResource);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resource.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="fullTypeName">Full name of the type.</param>
|
||||
/// <returns></returns>
|
||||
object IUpdatable.GetResource(System.Linq.IQueryable query, string fullTypeName)
|
||||
{
|
||||
// Get the first result
|
||||
IEnumerable results = (IEnumerable)query;
|
||||
object returnValue = null;
|
||||
foreach (object result in results)
|
||||
{
|
||||
if (returnValue != null) break;
|
||||
returnValue = result;
|
||||
}
|
||||
|
||||
// Check the Typename if needed
|
||||
if (fullTypeName != null)
|
||||
{
|
||||
if (fullTypeName != returnValue.GetType().FullName)
|
||||
{
|
||||
throw new DataServiceException("Incorrect Type Returned");
|
||||
}
|
||||
}
|
||||
|
||||
// Return the resource
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <returns></returns>
|
||||
object IUpdatable.GetValue(object targetResource, string propertyName)
|
||||
{
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName);
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new DataServiceException("Type not recognized as a valid type for this Context");
|
||||
}
|
||||
|
||||
// If
|
||||
if (metadata.IdentifierPropertyName == propertyName)
|
||||
{
|
||||
return metadata.GetIdentifier(targetResource);
|
||||
}
|
||||
else
|
||||
{
|
||||
return metadata.GetPropertyValue(targetResource, propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the reference from collection.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="resourceToBeRemoved">The resource to be removed.</param>
|
||||
void IUpdatable.RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
|
||||
{
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName);
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new DataServiceException("Type not recognized as a valid type for this Context");
|
||||
}
|
||||
|
||||
// Get the property to use to remove the resource to
|
||||
object collection = metadata.GetPropertyValue(targetResource, propertyName);
|
||||
|
||||
// Try with IList implementation first (its faster)
|
||||
if (collection is IList)
|
||||
{
|
||||
((IList)collection).Remove(resourceToBeRemoved);
|
||||
}
|
||||
else // Try with Reflection's Add()
|
||||
{
|
||||
MethodInfo removeMethod = collection.GetType().GetMethod("Remove", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (removeMethod == null)
|
||||
{
|
||||
throw new DataServiceException(string.Concat("Could not determine the collection type of the ", propertyName, " property."));
|
||||
}
|
||||
removeMethod.Invoke(collection, new object[] { resourceToBeRemoved });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the resource.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource to reset.</param>
|
||||
/// <returns></returns>
|
||||
object IUpdatable.ResetResource(object resource)
|
||||
{
|
||||
IUpdatable update = this;
|
||||
|
||||
// Create a new resource of the same type
|
||||
// but only make a local copy as we're only using it to set the default fields
|
||||
// Get the metadata
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(resource.GetType().ToString());
|
||||
object tempCopy = metadata.Instantiate(null);
|
||||
|
||||
// Copy the default non-keys
|
||||
foreach (string propName in metadata.PropertyNames)
|
||||
{
|
||||
object value = metadata.GetPropertyValue(tempCopy, propName);
|
||||
update.SetValue(resource, propName, value);
|
||||
}
|
||||
|
||||
//Return the new resource
|
||||
return resource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the resource.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource.</param>
|
||||
/// <returns></returns>
|
||||
object IUpdatable.ResolveResource(object resource)
|
||||
{
|
||||
// Resolve Resource always just returns the resource
|
||||
// since we not using tokens or cookies to the actual objects
|
||||
// the resources are always the actual CLR objects
|
||||
return resource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes.
|
||||
/// </summary>
|
||||
void IUpdatable.SaveChanges()
|
||||
{
|
||||
// All saves must be all or nothing.
|
||||
using (ITransaction tx = Session.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
// If we have anything in the object cache,
|
||||
// add it to session.
|
||||
if (_updateCache != null)
|
||||
{
|
||||
_updateCache.ForEach(o => session.SaveOrUpdate(o));
|
||||
_updateCache.Clear();
|
||||
}
|
||||
|
||||
// Push the changes to the database
|
||||
session.Flush();
|
||||
|
||||
// Commit the Transaction
|
||||
tx.Commit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// If anythign goes wrong, it all gets rolled back
|
||||
tx.Rollback();
|
||||
|
||||
// Send the error back to the user
|
||||
throw new DataServiceException("Failed to save changes. See inner exception for details", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the reference.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="propertyValue">The property value.</param>
|
||||
void IUpdatable.SetReference(object targetResource, string propertyName, object propertyValue)
|
||||
{
|
||||
((IUpdatable)this).SetValue(targetResource, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value.
|
||||
/// </summary>
|
||||
/// <param name="targetResource">The target resource.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="propertyValue">The property value.</param>
|
||||
void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue)
|
||||
{
|
||||
IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName);
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new DataServiceException("Type not recognized as a valid type for this Context");
|
||||
}
|
||||
|
||||
// See if its the Key property first
|
||||
if (metadata.IdentifierPropertyName == propertyName)
|
||||
{
|
||||
metadata.SetIdentifier(targetResource, propertyValue);
|
||||
}
|
||||
else // Else set the property
|
||||
{
|
||||
metadata.SetPropertyValue(targetResource, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IExpandProvider Members
|
||||
|
||||
IEnumerable IExpandProvider.ApplyExpansions(IQueryable queryable, ICollection<ExpandSegmentCollection> expandPaths)
|
||||
{
|
||||
if (queryable == null) throw new DataServiceException("Query cannot be null");
|
||||
|
||||
INHibernateQueryable nHibQuery = queryable as INHibernateQueryable;
|
||||
if (nHibQuery == null) throw new DataServiceException("Expansion only supported on INHibernateQueryable queries");
|
||||
|
||||
if (expandPaths.Count == 0) throw new DataServiceException("Expansion Paths cannot be null");
|
||||
foreach (ExpandSegmentCollection coll in expandPaths)
|
||||
{
|
||||
foreach (ExpandSegment seg in coll)
|
||||
{
|
||||
if (seg.HasFilter)
|
||||
{
|
||||
throw new DataServiceException("NHibernate does not support Expansions with Filters");
|
||||
}
|
||||
else
|
||||
{
|
||||
nHibQuery.QueryOptions.AddExpansion(seg.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nHibQuery as IEnumerable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a static method that enables LINQ syntax for NHibernate Criteria Queries.
|
||||
/// </summary>
|
||||
public static class NHibernateExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="T:NHibernate.Linq.NHibernateQueryProvider"/> object used to evaluate an expression tree.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An NHibernate entity type.</typeparam>
|
||||
/// <param name="session">An initialized <see cref="T:NHibernate.ISession"/> object.</param>
|
||||
/// <returns>An <see cref="T:NHibernate.Linq.NHibernateQueryProvider"/> used to evaluate an expression tree.</returns>
|
||||
public static INHibernateQueryable<T> Linq<T>(this ISession session)
|
||||
{
|
||||
QueryOptions options = new QueryOptions();
|
||||
return new Query<T>(new NHibernateQueryProvider(session, options), options);
|
||||
}
|
||||
|
||||
public static INHibernateQueryable<T> Linq<T>(this ISession session,string entityName)
|
||||
{
|
||||
QueryOptions options = new QueryOptions();
|
||||
return new Query<T>(new NHibernateQueryProvider(session, options,entityName), options);
|
||||
}
|
||||
|
||||
public static void List<T>(this ISession session, Expression expr, IList list)
|
||||
{
|
||||
var options = new QueryOptions();
|
||||
var queryProvider = new NHibernateQueryProvider(session, options);
|
||||
IQueryable<T> queryable = new Query<T>(queryProvider, options);
|
||||
queryable = queryable.Where((Expression<Func<T, bool>>)expr);
|
||||
|
||||
var result = queryProvider.TranslateExpression(queryable.Expression);
|
||||
var criteria = result as ICriteria;
|
||||
if (criteria != null)
|
||||
{
|
||||
criteria.List(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
var items = result as IEnumerable;
|
||||
if (items != null)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.Linq.Visitors;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
public class NHibernateQueryProvider : QueryProvider
|
||||
{
|
||||
private readonly ISession _session;
|
||||
private readonly string entityName;
|
||||
|
||||
public NHibernateQueryProvider(ISession session, QueryOptions queryOptions)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException("session");
|
||||
_session = session;
|
||||
this.queryOptions = queryOptions;
|
||||
}
|
||||
|
||||
public NHibernateQueryProvider(ISession session, QueryOptions queryOptions,string entityName)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException("session");
|
||||
_session = session;
|
||||
this.entityName = entityName;
|
||||
this.queryOptions = queryOptions;
|
||||
}
|
||||
|
||||
|
||||
private static object ResultsFromCriteria(ICriteria criteria, Expression expression)
|
||||
{
|
||||
System.Type elementType = TypeSystem.GetElementType(expression.Type);
|
||||
|
||||
return Activator.CreateInstance(typeof(CriteriaResultReader<>)
|
||||
.MakeGenericType(elementType), criteria);
|
||||
}
|
||||
|
||||
public object TranslateExpression(Expression expression)
|
||||
{
|
||||
expression = Evaluator.PartialEval(expression);
|
||||
expression = new BinaryBooleanReducer().Visit(expression);
|
||||
expression = new AssociationVisitor((ISessionFactoryImplementor)_session.SessionFactory).Visit(expression);
|
||||
expression = new InheritanceVisitor().Visit(expression);
|
||||
expression = CollectionAliasVisitor.AssignCollectionAccessAliases(expression);
|
||||
expression = new PropertyToMethodVisitor().Visit(expression);
|
||||
expression = new BinaryExpressionOrderer().Visit(expression);
|
||||
|
||||
NHibernateQueryTranslator translator = new NHibernateQueryTranslator(_session,entityName);
|
||||
return translator.Translate(expression, this.queryOptions);
|
||||
}
|
||||
|
||||
public override object Execute(Expression expression)
|
||||
{
|
||||
var results = TranslateExpression(expression);
|
||||
var criteria = results as ICriteria;
|
||||
|
||||
if (criteria != null)
|
||||
return ResultsFromCriteria(criteria, expression);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
77
src/Libraries/NHibernate/NHibernate.Linq/Query.cs
Normal file
77
src/Libraries/NHibernate/NHibernate.Linq/Query.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
///<summary>
|
||||
/// Generic IQueryable base class. See http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
|
||||
/// </summary>
|
||||
public class Query<T> : INHibernateQueryable<T>
|
||||
{
|
||||
private readonly QueryProvider provider;
|
||||
private readonly Expression expression;
|
||||
private readonly QueryOptions queryOptions;
|
||||
|
||||
public Query(QueryProvider provider, QueryOptions queryOptions)
|
||||
{
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
|
||||
this.provider = provider;
|
||||
this.queryOptions = queryOptions;
|
||||
this.expression = Expression.Constant(this);
|
||||
}
|
||||
|
||||
public Query(QueryProvider provider, Expression expression, QueryOptions queryOptions)
|
||||
{
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
if (expression == null) throw new ArgumentNullException("expression");
|
||||
|
||||
if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type))
|
||||
throw new ArgumentOutOfRangeException("expression");
|
||||
|
||||
this.provider = provider;
|
||||
this.queryOptions = queryOptions;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
Expression IQueryable.Expression
|
||||
{
|
||||
get { return this.expression; }
|
||||
}
|
||||
|
||||
System.Type IQueryable.ElementType
|
||||
{
|
||||
get { return typeof(T); }
|
||||
}
|
||||
|
||||
IQueryProvider IQueryable.Provider
|
||||
{
|
||||
get { return this.provider; }
|
||||
}
|
||||
|
||||
public QueryOptions QueryOptions
|
||||
{
|
||||
get { return queryOptions; }
|
||||
}
|
||||
|
||||
public IQueryable<T> Expand(string path)
|
||||
{
|
||||
queryOptions.AddExpansion(path);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
56
src/Libraries/NHibernate/NHibernate.Linq/QueryOptions.cs
Normal file
56
src/Libraries/NHibernate/NHibernate.Linq/QueryOptions.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// It provides methods for caching the results, and some extension methods for them.
|
||||
/// </summary>
|
||||
public class QueryOptions
|
||||
{
|
||||
private Action<ICriteria> action;
|
||||
|
||||
public QueryOptions()
|
||||
{
|
||||
this.action = delegate { };
|
||||
}
|
||||
|
||||
public QueryOptions SetCachable(bool cachable)
|
||||
{
|
||||
action += criteria => criteria.SetCacheable(cachable);
|
||||
return this;
|
||||
}
|
||||
public QueryOptions SetCacheMode(CacheMode mode)
|
||||
{
|
||||
action += criteria => criteria.SetCacheMode(mode);
|
||||
return this;
|
||||
}
|
||||
public QueryOptions SetCacheRegion(string cacheRegion)
|
||||
{
|
||||
action += criteria => criteria.SetCacheRegion(cacheRegion);
|
||||
return this;
|
||||
}
|
||||
public QueryOptions SetComment(string comment)
|
||||
{
|
||||
action += criteria => criteria.SetComment(comment);
|
||||
return this;
|
||||
}
|
||||
public QueryOptions RegisterCustomAction(Action<ICriteria> customAction)
|
||||
{
|
||||
action += customAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
internal void Execute(ICriteria criteria)
|
||||
{
|
||||
action(criteria);
|
||||
}
|
||||
|
||||
public void AddExpansion(string path)
|
||||
{
|
||||
action += criteria =>
|
||||
{
|
||||
criteria.Fetch(SelectMode.Fetch, path);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
39
src/Libraries/NHibernate/NHibernate.Linq/QueryProvider.cs
Normal file
39
src/Libraries/NHibernate/NHibernate.Linq/QueryProvider.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
|
||||
namespace NHibernate.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic IQueryProvider base class. See http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
|
||||
/// </summary>
|
||||
public abstract class QueryProvider : IQueryProvider
|
||||
{
|
||||
protected QueryOptions queryOptions;
|
||||
|
||||
IQueryable<T> IQueryProvider.CreateQuery<T>(Expression expression)
|
||||
{
|
||||
return new Query<T>(this, expression, queryOptions);
|
||||
}
|
||||
|
||||
IQueryable IQueryProvider.CreateQuery(Expression expression)
|
||||
{
|
||||
QueryOptions options = new QueryOptions();
|
||||
System.Type elementType = TypeSystem.GetElementType(expression.Type);
|
||||
return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression, options });
|
||||
}
|
||||
|
||||
T IQueryProvider.Execute<T>(Expression expression)
|
||||
{
|
||||
return (T)this.Execute(expression);
|
||||
}
|
||||
|
||||
object IQueryProvider.Execute(Expression expression)
|
||||
{
|
||||
return this.Execute(expression);
|
||||
}
|
||||
|
||||
public abstract object Execute(Expression expression);
|
||||
}
|
||||
}
|
@ -0,0 +1,321 @@
|
||||
using System;
|
||||
|
||||
namespace NHibernate.Linq.SqlClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides static methods that represent functionality provided by MS SQL Server.
|
||||
/// </summary>
|
||||
public static class SqlClientExtensions
|
||||
{
|
||||
#region DateTime Functions
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer representing the day datepart of the specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Day(this IDbMethods methods, DateTime value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer representing the day datepart of the specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Day(this IDbMethods methods, DateTime? value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer that represents the month part of a specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Month(this IDbMethods methods, DateTime value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer that represents the month part of a specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Month(this IDbMethods methods, DateTime? value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer that represents the year part of a specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Year(this IDbMethods methods, DateTime value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an integer that represents the year part of a specified date.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Year(this IDbMethods methods, DateTime? value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion DateTime Functions
|
||||
|
||||
#region Math Functions
|
||||
|
||||
#endregion Math Functions
|
||||
|
||||
#region String Functions
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ASCII code value of the leftmost character of a character expression.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Ascii(this IDbMethods methods, string value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ASCII code value of the leftmost character of a character expression.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Ascii(this IDbMethods methods, char value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ASCII code value of the leftmost character of a character expression.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Ascii(this IDbMethods methods, char? value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an int ASCII code to a character.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static char Char(this IDbMethods methods, int value)
|
||||
{
|
||||
return char.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an int ASCII code to a character.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static char Char(this IDbMethods methods, int? value)
|
||||
{
|
||||
return char.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the starting position of the specified expression in a character string.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="search"></param>
|
||||
/// <returns></returns>
|
||||
public static int CharIndex(this IDbMethods methods, string value, char search)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the starting position of the specified expression in a character string.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="search"></param>
|
||||
/// <param name="start"></param>
|
||||
/// <returns></returns>
|
||||
public static int CharIndex(this IDbMethods methods, string value, char search, int start)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the starting position of the specified expression in a character string.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="search"></param>
|
||||
/// <returns></returns>
|
||||
public static int CharIndex(this IDbMethods methods, string value, string search)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the starting position of the specified expression in a character string.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="search"></param>
|
||||
/// <param name="start"></param>
|
||||
/// <returns></returns>
|
||||
public static int CharIndex(this IDbMethods methods, string value, string search, int start)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the left part of a character string with the specified number of characters.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public static string Left(this IDbMethods methods, string value, int length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of characters of the specified string expression, excluding trailing blanks.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static int Len(this IDbMethods methods, string value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a character expression after converting uppercase character data to lowercase.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string Lower(this IDbMethods methods, string value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a character expression after it removes leading blanks.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string LTrim(this IDbMethods methods, string value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all occurrences of a specified string value with another string value.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="search"></param>
|
||||
/// <param name="replace"></param>
|
||||
/// <returns></returns>
|
||||
public static string Replace(this IDbMethods methods, string value, string search, string replace)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeats a string value a specified number of times.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public static string Replicate(this IDbMethods methods, string value, int count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the reverse of a character expression.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string Reverse(this IDbMethods methods, string value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the right part of a character string with the specified number of characters.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public static string Right(this IDbMethods methods, string value, int length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a character string after truncating all trailing blanks.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string RTrim(this IDbMethods methods, string value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns part of a character, binary, text, or image expression.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public static string Substring(this IDbMethods methods, string value, int start, int length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a character expression with lowercase character data converted to uppercase.
|
||||
/// </summary>
|
||||
/// <param name="methods"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string Upper(this IDbMethods methods, string value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion String Functions
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NHibernate.Transform;
|
||||
|
||||
namespace NHibernate.Linq.Transform
|
||||
{
|
||||
/// <summary>
|
||||
/// Transforms critieria query results into a collection of grouped objects.
|
||||
/// </summary>
|
||||
public class LinqGroupingResultTransformer : IResultTransformer
|
||||
{
|
||||
private readonly System.Type groupingType;
|
||||
private readonly IDictionary<Object, IGrouping> groups;
|
||||
private readonly String propertyName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.LinqGroupingResultTransformer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">A <see cref="T:System.Type"/> representing the type of collection to transform.</param>
|
||||
/// <param name="propertyName">The name of the property to be used as a key for the purpose of grouping.</param>
|
||||
public LinqGroupingResultTransformer(System.Type type, String propertyName)
|
||||
{
|
||||
System.Type[] args = type.GetGenericArguments();
|
||||
groupingType = typeof(Grouping<,>).MakeGenericType(args[0], args[1]);
|
||||
groups = new Dictionary<Object, IGrouping>();
|
||||
this.propertyName = propertyName;
|
||||
|
||||
int index = propertyName.IndexOf('.');
|
||||
if (index > -1)
|
||||
{
|
||||
this.propertyName = propertyName.Substring(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#region IResultTransformer Members
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the query result collection.
|
||||
/// </summary>
|
||||
/// <param name="collection">An <see cref="T:System.Collections.IList"/> of objects.</param>
|
||||
/// <returns>A transformed <see cref="T:System.Collections.IList"/> object.</returns>
|
||||
public IList TransformList(IList collection)
|
||||
{
|
||||
while (collection.Contains(null))
|
||||
{
|
||||
collection.Remove(null);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms each query result.
|
||||
/// </summary>
|
||||
/// <param name="tuple">An <see cref="T:System.Object"/> array of query result values.</param>
|
||||
/// <param name="aliases">A <see cref="T:System.String"/> array of column aliases.</param>
|
||||
/// <returns>An <see cref="T:System.Object"/> initialized with the values from the specified tuple.</returns>
|
||||
public object TransformTuple(object[] tuple, string[] aliases)
|
||||
{
|
||||
object value = tuple[0].GetType().GetProperty(propertyName).GetValue(tuple[0], null);
|
||||
String key = String.Format("{0}", value);
|
||||
|
||||
if (groups.ContainsKey(key))
|
||||
{
|
||||
groups[key].Add(tuple[1]);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var group = (IGrouping)Activator.CreateInstance(groupingType, value);
|
||||
group.Add(tuple[1]);
|
||||
groups[key] = group;
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a method for adding individual objects to a collection of grouped objects.
|
||||
/// </summary>
|
||||
internal interface IGrouping
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an object to the current group.
|
||||
/// </summary>
|
||||
/// <param name="item">The <see cref="T:System.Object"/> to add.</param>
|
||||
void Add(object item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a collection of objects that have a common key.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TElement"></typeparam>
|
||||
internal class Grouping<TKey, TElement> : IGrouping<TKey, TElement>, IGrouping
|
||||
{
|
||||
private readonly TKey key;
|
||||
private readonly IList<TElement> list = new List<TElement>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.Grouping"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public Grouping(TKey key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
#region IGrouping Members
|
||||
|
||||
/// <summary>
|
||||
/// Adds an object to the current group.
|
||||
/// </summary>
|
||||
/// <param name="item">The <see cref="T:System.Object"/> to add.</param>
|
||||
public void Add(object item)
|
||||
{
|
||||
list.Add((TElement)item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IGrouping<TKey,TElement> Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key of the <see cref="T:System.Linq.IGrouping`2"/>.
|
||||
/// </summary>
|
||||
public TKey Key
|
||||
{
|
||||
get { return key; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.</returns>
|
||||
public IEnumerator<TElement> GetEnumerator()
|
||||
{
|
||||
return list.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="T:System.Collections.IEnumerator"/> that can be used to iterate through the collection.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("Key = {0}", Key);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace NHibernate.Linq.Transform
|
||||
{
|
||||
public class LinqJoinResultsTransformer : NHibernate.Transform.IResultTransformer
|
||||
{
|
||||
private readonly System.Type _entityType;
|
||||
|
||||
public LinqJoinResultsTransformer(System.Type entityType)
|
||||
{
|
||||
_entityType = entityType;
|
||||
}
|
||||
|
||||
public IList TransformList(IList collection)
|
||||
{
|
||||
return collection;
|
||||
}
|
||||
|
||||
public object TransformTuple(object[] tuple, string[] aliases)
|
||||
{
|
||||
foreach (object obj in tuple)
|
||||
{
|
||||
if (obj != null && obj.GetType() == _entityType)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using NHibernate.Linq.Util;
|
||||
|
||||
namespace NHibernate.Transform
|
||||
{
|
||||
[Serializable]
|
||||
public class TypeSafeConstructorMemberInitResultTransformer : IResultTransformer
|
||||
{
|
||||
private readonly Expression expression;
|
||||
|
||||
public TypeSafeConstructorMemberInitResultTransformer(NewExpression expression)
|
||||
{
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public TypeSafeConstructorMemberInitResultTransformer(MemberInitExpression expression)
|
||||
{
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public object TransformTuple(object[] tuple, string[] aliases)
|
||||
{
|
||||
try
|
||||
{
|
||||
int argumentCount;
|
||||
switch (expression.NodeType)
|
||||
{
|
||||
case ExpressionType.New:
|
||||
return InvokeConstructor((NewExpression)expression, tuple, out argumentCount);
|
||||
|
||||
case ExpressionType.MemberInit:
|
||||
return InvokeMemberInitExpression((MemberInitExpression)expression, tuple, out argumentCount);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new QueryException(
|
||||
"could not instantiate: " +
|
||||
expression.Type.FullName,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
private object InvokeConstructor(NewExpression expression, object[] args, out int argumentCount)
|
||||
{
|
||||
object valueToSet;
|
||||
int nestedArgumentCount;
|
||||
|
||||
argumentCount = 0;
|
||||
ArrayList argList = new ArrayList();
|
||||
|
||||
int i = 0;
|
||||
foreach (var arg in expression.Arguments)
|
||||
{
|
||||
switch (arg.NodeType)
|
||||
{
|
||||
case ExpressionType.New:
|
||||
valueToSet = InvokeConstructor((NewExpression)arg, args.Skip(i).ToArray(), out nestedArgumentCount);
|
||||
i += nestedArgumentCount;
|
||||
break;
|
||||
|
||||
case ExpressionType.MemberInit:
|
||||
valueToSet = InvokeMemberInitExpression((MemberInitExpression)arg,
|
||||
args.Skip(i).ToArray(), out nestedArgumentCount);
|
||||
i += nestedArgumentCount;
|
||||
break;
|
||||
|
||||
default:
|
||||
valueToSet = LinqUtil.ChangeType(args[i], arg.Type);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
argList.Add(valueToSet);
|
||||
}
|
||||
|
||||
argumentCount = i;
|
||||
return expression.Constructor.Invoke(argList.ToArray());
|
||||
}
|
||||
|
||||
private object InvokeMemberInitExpression(MemberInitExpression expression, object[] args, out int argumentCount)
|
||||
{
|
||||
object valueToSet;
|
||||
int nestedArgumentCount, constructorArgumentCount;
|
||||
|
||||
argumentCount = 0;
|
||||
object instance = InvokeConstructor(expression.NewExpression, args, out constructorArgumentCount);
|
||||
|
||||
int i = constructorArgumentCount;
|
||||
foreach (MemberAssignment binding in expression.Bindings)
|
||||
{
|
||||
switch (binding.Expression.NodeType)
|
||||
{
|
||||
case ExpressionType.New:
|
||||
valueToSet = InvokeConstructor((NewExpression)binding.Expression,
|
||||
args.Skip(i).ToArray(), out nestedArgumentCount);
|
||||
i += nestedArgumentCount;
|
||||
break;
|
||||
|
||||
case ExpressionType.MemberInit:
|
||||
valueToSet = InvokeMemberInitExpression((MemberInitExpression)binding.Expression,
|
||||
args.Skip(i).ToArray(), out nestedArgumentCount);
|
||||
i += nestedArgumentCount;
|
||||
break;
|
||||
|
||||
default:
|
||||
valueToSet = args[i];
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
SetValue(binding.Member, instance, valueToSet);
|
||||
}
|
||||
|
||||
argumentCount = i;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the field or property represented by the specified
|
||||
/// <see cref="T:System.Reflection.MemberInfo"/> for the supplied object instance.
|
||||
/// </summary>
|
||||
/// <param name="memberInfo">A <see cref="T:System.Reflection.MemberInfo"/> object.</param>
|
||||
/// <param name="instance">An instance of an object.</param>
|
||||
/// <param name="valueToSet">The value to set on the specified object.</param>
|
||||
private void SetValue(MemberInfo memberInfo, object instance, object valueToSet)
|
||||
{
|
||||
var field = memberInfo as FieldInfo;
|
||||
if (field != null)
|
||||
{
|
||||
field.SetValue(instance, LinqUtil.ChangeType(valueToSet, field.FieldType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prop = memberInfo as PropertyInfo;
|
||||
prop.SetValue(instance, LinqUtil.ChangeType(valueToSet, prop.PropertyType), null);
|
||||
}
|
||||
}
|
||||
|
||||
public IList TransformList(IList collection)
|
||||
{
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
}
|
122
src/Libraries/NHibernate/NHibernate.Linq/Util/CriteriaUtil.cs
Normal file
122
src/Libraries/NHibernate/NHibernate.Linq/Util/CriteriaUtil.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.Impl;
|
||||
using NHibernate.Loader.Criteria;
|
||||
using NHibernate.Persister.Entity;
|
||||
using NHibernate.Transform;
|
||||
|
||||
namespace NHibernate.Linq.Util
|
||||
{
|
||||
public static class CriteriaUtil
|
||||
{
|
||||
#region Extension Methods
|
||||
|
||||
public static ICriteriaQuery GenerateCriteriaQuery(this ICriteria criteria, ISessionFactory sessionFactory, string rootEntityName)
|
||||
{
|
||||
return new CriteriaQueryTranslator(
|
||||
(ISessionFactoryImplementor)sessionFactory,
|
||||
(CriteriaImpl)criteria,
|
||||
rootEntityName, "this");
|
||||
}
|
||||
|
||||
public static void SetProjectionIfNotNull(this ICriteria criteria, IProjection projection)
|
||||
{
|
||||
if (projection != null)
|
||||
criteria.SetProjection(projection);
|
||||
}
|
||||
|
||||
public static void SetResultTransformerIfNotNull(this ICriteria criteria, IResultTransformer transformer)
|
||||
{
|
||||
if (transformer != null)
|
||||
criteria.SetResultTransformer(transformer);
|
||||
else
|
||||
criteria.SetResultTransformer(new RootEntityResultTransformer());
|
||||
}
|
||||
|
||||
public static void Add(this ICriteria criteria, IEnumerable<ICriterion> criterion)
|
||||
{
|
||||
foreach (ICriterion c in criterion)
|
||||
{
|
||||
criteria.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetEntityOrClassName(this ICriteria criteria)
|
||||
{
|
||||
if (criteria is CriteriaImpl)
|
||||
{
|
||||
return ((CriteriaImpl)criteria).EntityOrClassName;
|
||||
}
|
||||
|
||||
if (criteria is DetachedCriteriaAdapter)
|
||||
{
|
||||
var adapter = (DetachedCriteriaAdapter)criteria;
|
||||
return adapter.DetachedCriteria.EntityOrClassName;
|
||||
}
|
||||
throw new NotSupportedException("criteria must be of type CriteriaImpl or DetachedCriteriaAdapter.");
|
||||
}
|
||||
|
||||
public static IProjection GetProjection(this ICriteria criteria)
|
||||
{
|
||||
var impl = criteria as CriteriaImpl;
|
||||
if (impl != null)
|
||||
{
|
||||
return impl.Projection;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static System.Type GetRootType(this ICriteria criteria)
|
||||
{
|
||||
if (criteria is DetachedCriteriaAdapter)
|
||||
{
|
||||
var adapter = (DetachedCriteriaAdapter)criteria;
|
||||
return GetRootType(adapter.DetachedCriteria, adapter.Session);
|
||||
}
|
||||
return GetRootType(GetRootCriteria(criteria));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static ISessionImplementor GetSession(ICriteria criteria)
|
||||
{
|
||||
return GetRootCriteria(criteria).Session;
|
||||
}
|
||||
|
||||
private static CriteriaImpl GetRootCriteria(ICriteria criteria)
|
||||
{
|
||||
var impl = criteria as CriteriaImpl;
|
||||
if (impl != null)
|
||||
return impl;
|
||||
return GetRootCriteria(((CriteriaImpl.Subcriteria)criteria).Parent);
|
||||
}
|
||||
|
||||
private static System.Type GetRootType(CriteriaImpl criteria)
|
||||
{
|
||||
if (criteria.Session == null)
|
||||
throw new InvalidOperationException("Could not get root type on criteria that is not attached to a session");
|
||||
|
||||
ISessionFactoryImplementor factory = criteria.Session.Factory;
|
||||
|
||||
//TODO: need to cache the entityName meta data
|
||||
var entityNames = factory.GetEntityNameMetaData();
|
||||
|
||||
if (!entityNames.ContainsKey(criteria.EntityOrClassName))
|
||||
throw new InvalidOperationException("Could not find entity named: " + criteria.EntityOrClassName);
|
||||
|
||||
return entityNames[criteria.EntityOrClassName];
|
||||
}
|
||||
|
||||
private static System.Type GetRootType(DetachedCriteria criteria, ISession session)
|
||||
{
|
||||
ISessionFactoryImplementor factory = (ISessionFactoryImplementor)session.SessionFactory;
|
||||
IEntityPersister persister = factory.GetEntityPersister(criteria.EntityOrClassName);
|
||||
if (persister == null)
|
||||
throw new InvalidOperationException("Could not find entity named: " + criteria.EntityOrClassName);
|
||||
|
||||
return persister.MappedClass;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Transform;
|
||||
@ -151,7 +153,8 @@ namespace NHibernate.Linq.Util
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ICriteria SetFetchMode(string associationPath, FetchMode mode)
|
||||
[Obsolete("Use Fetch instead")]
|
||||
public ICriteria SetFetchMode(string associationPath, FetchMode mode)
|
||||
{
|
||||
return detachedCriteria.SetFetchMode(associationPath, mode).Adapt(session);
|
||||
}
|
||||
@ -240,11 +243,34 @@ namespace NHibernate.Linq.Util
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
public Task<IList> ListAsync(CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#region ICloneable Members
|
||||
public Task<object> UniqueResultAsync(CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
public Task ListAsync(IList results, CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Task<IList<T>> ListAsync<T>(CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Task<T> UniqueResultAsync<T>(CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IFutureEnumerable<T> ICriteria.Future<T>() {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ICloneable Members
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@ -277,5 +303,6 @@ namespace NHibernate.Linq.Util
|
||||
_readOnlyInitialized = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
153
src/Libraries/NHibernate/NHibernate.Linq/Util/LinqUtil.cs
Normal file
153
src/Libraries/NHibernate/NHibernate.Linq/Util/LinqUtil.cs
Normal file
@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides static utility methods that aid in evaluating expression trees.
|
||||
/// </summary>
|
||||
public static class LinqUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a collection of type T by invoking a delegate method during
|
||||
/// enumeration that return each item, begining with an initialValue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of collection being created.</typeparam>
|
||||
/// <param name="func">A delegate method to invoke.</param>
|
||||
/// <param name="initialValue">The first item in the collection.</param>
|
||||
/// <returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> collection of type T.</returns>
|
||||
public static IEnumerable<T> Iterate<T>(Func<T, T> func, T initialValue)
|
||||
{
|
||||
T value = initialValue;
|
||||
while (true)
|
||||
{
|
||||
yield return value;
|
||||
value = func(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an <see cref="T:System.Object"/> with the specified <see cref="T:System.Type"/>
|
||||
/// and whose value is equivalent to the specified object.
|
||||
/// </summary>
|
||||
/// <param name="value">An <see cref="T:System.Object"/> that implements the <see cref="T:System.IConvertible"/> interface.</param>
|
||||
/// <param name="conversionType">A <see cref="T:System.Type"/>.</param>
|
||||
/// <returns>An object whose <see cref="T:System.Type"/> is conversionType and whose value is equivalent
|
||||
/// to value, or null, if value is null and conversionType is not a value type.</returns>
|
||||
public static object ChangeType(object value, System.Type conversionType)
|
||||
{
|
||||
// have to use IsAssignableFrom() due to proxy classes
|
||||
if (value != null && !conversionType.IsAssignableFrom(value.GetType()))
|
||||
{
|
||||
if (IsNullableType(conversionType))
|
||||
{
|
||||
System.Type arg = conversionType.GetGenericArguments()[0];
|
||||
if (arg.IsEnum)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
value = Activator.CreateInstance(conversionType, Enum.Parse(arg, value as string));
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Activator.CreateInstance(conversionType, Enum.ToObject(arg, value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Activator.CreateInstance(conversionType, Convert.ChangeType(value, arg));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (conversionType.IsEnum)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
value = Enum.Parse(conversionType, value as string);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Enum.ToObject(conversionType, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Convert.ChangeType(value, conversionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specified type is a <see cref="T:System.Nullable`1"/> type.
|
||||
/// </summary>
|
||||
/// <param name="type">A <see cref="T:System.Type"/> to check.</param>
|
||||
/// <returns>True if the type is a <see cref="T:System.Nullable`1"/> type, otherwise false.</returns>
|
||||
public static bool IsNullableType(System.Type type)
|
||||
{
|
||||
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specified type is an anonymous type.
|
||||
/// </summary>
|
||||
/// <param name="type">A <see cref="T:System.Type"/> to check.</param>
|
||||
/// <returns>True if the type is an anonymous type, otherwise false.</returns>
|
||||
public static bool IsAnonymousType(System.Type type)
|
||||
{
|
||||
return type != null && type.Name.StartsWith("<");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes an <see cref="T:System.Object"/> for use in SQL statements.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to encode.</param>
|
||||
/// <returns>A SQL encoded value.</returns>
|
||||
public static string SqlEncode(object value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
System.Type type = value.GetType();
|
||||
|
||||
if (IsNullableType(type))
|
||||
{
|
||||
value = type.GetProperty("Value").GetValue(value, null);
|
||||
return SqlEncode(value);
|
||||
}
|
||||
|
||||
switch (System.Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
return ((bool)value) ? "1" : "0";
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.Decimal:
|
||||
case TypeCode.Double:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Single:
|
||||
return value.ToString();
|
||||
case TypeCode.DBNull:
|
||||
case TypeCode.Empty:
|
||||
return "null";
|
||||
default:
|
||||
return String.Format("'{0}'", value.ToString().Replace("'", "''"));
|
||||
}
|
||||
}
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
public static Expression StripQuotes(Expression e)
|
||||
{
|
||||
while (e.NodeType == ExpressionType.Quote)
|
||||
e = ((UnaryExpression)e).Operand;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
140
src/Libraries/NHibernate/NHibernate.Linq/Util/QueryUtil.cs
Normal file
140
src/Libraries/NHibernate/NHibernate.Linq/Util/QueryUtil.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using Expression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Util
|
||||
{
|
||||
public class QueryUtil
|
||||
{
|
||||
public static object GetExpressionValue(Expression expression)
|
||||
{
|
||||
var constExpr = expression as ConstantExpression;
|
||||
if (constExpr != null)
|
||||
return constExpr.Value;
|
||||
|
||||
return Expression.Lambda(typeof(Func<>).MakeGenericType(expression.Type), expression)
|
||||
.Compile().DynamicInvoke();
|
||||
}
|
||||
|
||||
public static List<ParameterExpression> GetParameters(Expression expr)
|
||||
{
|
||||
var list = new List<ParameterExpression>();
|
||||
GetParameters(expr, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static object[] GetMethodParameterValues(MethodCallExpression call)
|
||||
{
|
||||
System.Type[] paramTypes = null;
|
||||
return GetMethodParameterValues(call, out paramTypes);
|
||||
}
|
||||
|
||||
public static object[] GetMethodParameterValues(MethodCallExpression call, out System.Type[] types)
|
||||
{
|
||||
ConstantExpression ce;
|
||||
object[] values = null;
|
||||
types = null;
|
||||
|
||||
if (call != null)
|
||||
{
|
||||
var valueList = new List<Object>();
|
||||
var typeList = new List<System.Type>();
|
||||
|
||||
for (int i = 0; i < call.Arguments.Count; i++)
|
||||
{
|
||||
ce = call.Arguments[i] as ConstantExpression;
|
||||
if (ce != null)
|
||||
{
|
||||
valueList.Add(ce.Value);
|
||||
typeList.Add(ce.Type);
|
||||
}
|
||||
}
|
||||
if (valueList.Count > 0)
|
||||
{
|
||||
values = valueList.ToArray();
|
||||
types = typeList.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static SqlFunctionExpression GetFunctionCriteria(MethodCallExpression call, ICriterion criterion,
|
||||
SqlFunctionExpression rightFunction)
|
||||
{
|
||||
System.Type[] paramTypes = null;
|
||||
object[] paramValues = GetMethodParameterValues(call, out paramTypes);
|
||||
|
||||
int propertyPosition = 0;
|
||||
string methodName = QueryUtil.GetMethodName(call, out propertyPosition);
|
||||
|
||||
return new SqlFunctionExpression(methodName, call.Method.ReturnType, paramValues, paramTypes, criterion,
|
||||
propertyPosition, rightFunction);
|
||||
}
|
||||
|
||||
public static void GetParameters(Expression expr, List<ParameterExpression> list)
|
||||
{
|
||||
if (expr is ParameterExpression)
|
||||
{
|
||||
var pe = expr as ParameterExpression;
|
||||
if (!list.Contains(pe))
|
||||
{
|
||||
list.Add(pe);
|
||||
}
|
||||
}
|
||||
else if (expr is MemberExpression)
|
||||
{
|
||||
GetParameters(((MemberExpression)expr).Expression, list);
|
||||
}
|
||||
else if (expr is UnaryExpression)
|
||||
{
|
||||
GetParameters(((UnaryExpression)expr).Operand, list);
|
||||
}
|
||||
else if (expr is BinaryExpression)
|
||||
{
|
||||
var be = expr as BinaryExpression;
|
||||
GetParameters(be.Left, list);
|
||||
GetParameters(be.Right, list);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetMethodName(MethodCallExpression call, out int propertyPosition)
|
||||
{
|
||||
object[] attribs = call.Method.GetCustomAttributes(typeof(SqlFunctionAttribute), false);
|
||||
var attrib = attribs.FirstOrDefault() as SqlFunctionAttribute;
|
||||
string methodName = call.Method.Name;
|
||||
propertyPosition = 0;
|
||||
|
||||
if (attrib != null)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(attrib.Owner))
|
||||
methodName = String.Format("{0}.{1}", attrib.Owner, methodName);
|
||||
propertyPosition = attrib.PropertyPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
// provide mapping of System methods to SQL functions
|
||||
switch (methodName.ToLower())
|
||||
{
|
||||
case "tolower":
|
||||
methodName = "lower";
|
||||
break;
|
||||
case "toupper":
|
||||
methodName = "upper";
|
||||
break;
|
||||
case "indexof":
|
||||
case "charindex":
|
||||
methodName = "charindex";
|
||||
propertyPosition = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.Metadata;
|
||||
|
||||
namespace NHibernate.Linq.Util
|
||||
{
|
||||
public static class SessionFactoryUtil
|
||||
{
|
||||
public static IDictionary<System.Type, string> GetProxyMetaData(this ISessionFactoryImplementor factory, IDictionary<string, IClassMetadata> metaData)
|
||||
{
|
||||
var dict = new Dictionary<System.Type, string>();
|
||||
foreach (var item in metaData)
|
||||
{
|
||||
if (item.Value.HasProxy)
|
||||
{
|
||||
var proxyType = factory.GetEntityPersister(item.Key).ConcreteProxyClass;
|
||||
if (proxyType != item.Value.MappedClass && !dict.ContainsKey(proxyType))
|
||||
{
|
||||
dict.Add(proxyType, item.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
public static IDictionary<string, System.Type> GetEntityNameMetaData(this ISessionFactoryImplementor factory)
|
||||
{
|
||||
var metaData = factory.GetAllClassMetadata();
|
||||
|
||||
var dict = new Dictionary<string, System.Type>();
|
||||
foreach (var item in metaData)
|
||||
{
|
||||
var type = item.Value.MappedClass;
|
||||
|
||||
dict.Add(item.Key, type);
|
||||
if (item.Value.HasProxy)
|
||||
{
|
||||
var proxyType = factory.GetEntityPersister(item.Key).ConcreteProxyClass;
|
||||
if (proxyType != type && !dict.ContainsKey(proxyType.FullName))
|
||||
{
|
||||
dict.Add(proxyType.FullName, proxyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
54
src/Libraries/NHibernate/NHibernate.Linq/Util/TypeSystem.cs
Normal file
54
src/Libraries/NHibernate/NHibernate.Linq/Util/TypeSystem.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NHibernate.Linq.Util
|
||||
{
|
||||
/// <remarks>
|
||||
/// http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
|
||||
/// </remarks>
|
||||
public static class TypeSystem
|
||||
{
|
||||
public static System.Type GetElementType(System.Type seqType)
|
||||
{
|
||||
System.Type ienum = FindIEnumerable(seqType);
|
||||
if (ienum == null) return seqType;
|
||||
return ienum.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
private static System.Type FindIEnumerable(System.Type seqType)
|
||||
{
|
||||
if (seqType == null || seqType == typeof(string))
|
||||
return null;
|
||||
|
||||
if (seqType.IsArray)
|
||||
return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
|
||||
|
||||
if (seqType.IsGenericType)
|
||||
{
|
||||
foreach (System.Type arg in seqType.GetGenericArguments())
|
||||
{
|
||||
System.Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
|
||||
if (ienum.IsAssignableFrom(seqType))
|
||||
{
|
||||
return ienum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.Type[] ifaces = seqType.GetInterfaces();
|
||||
if (ifaces != null && ifaces.Length > 0)
|
||||
{
|
||||
foreach (System.Type iface in ifaces)
|
||||
{
|
||||
System.Type ienum = FindIEnumerable(iface);
|
||||
if (ienum != null) return ienum;
|
||||
}
|
||||
}
|
||||
|
||||
if (seqType.BaseType != null && seqType.BaseType != typeof(object))
|
||||
{
|
||||
return FindIEnumerable(seqType.BaseType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.Metadata;
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Preprocesses an expression tree replacing MemberAccessExpressions and ParameterExpressions with
|
||||
/// NHibernate-specific PropertyAccessExpressions and EntityExpressions respectively.
|
||||
/// </summary>
|
||||
public class AssociationVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly ISessionFactoryImplementor _sessionFactory;
|
||||
private readonly IDictionary<string, IClassMetadata> _metaData;
|
||||
private readonly IDictionary<System.Type, string> _proxyTypes;
|
||||
|
||||
public AssociationVisitor(ISessionFactoryImplementor sessionFactory)
|
||||
{
|
||||
_sessionFactory = sessionFactory;
|
||||
_metaData = _sessionFactory.GetAllClassMetadata();
|
||||
_proxyTypes = _sessionFactory.GetProxyMetaData(_metaData);
|
||||
}
|
||||
|
||||
private IClassMetadata GetMetaData(System.Type type)
|
||||
{
|
||||
if (LinqUtil.IsAnonymousType(type))
|
||||
return null;
|
||||
|
||||
string entityName = _sessionFactory.TryGetGuessEntityName(type);
|
||||
|
||||
if (!String.IsNullOrEmpty(entityName) && _metaData.ContainsKey(entityName))
|
||||
return _metaData[entityName];
|
||||
|
||||
if (_proxyTypes.ContainsKey(type))
|
||||
return _metaData[_proxyTypes[type]];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private EntityExpression GetParentExpression(MemberExpression expr, out string memberName, out IType nhibernateType)
|
||||
{
|
||||
memberName = null;
|
||||
nhibernateType = null;
|
||||
|
||||
CollectionAccessExpression collectionExpr = expr.Expression as CollectionAccessExpression;
|
||||
if (collectionExpr != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
PropertyAccessExpression propExpr = expr.Expression as PropertyAccessExpression;
|
||||
if (propExpr != null)
|
||||
{
|
||||
memberName = propExpr.Name + "." + expr.Member.Name;
|
||||
nhibernateType = propExpr.Expression.MetaData.GetPropertyType(memberName);
|
||||
return propExpr.Expression;
|
||||
}
|
||||
|
||||
EntityExpression entityExpr = expr.Expression as EntityExpression;
|
||||
if (entityExpr != null)
|
||||
{
|
||||
memberName = expr.Member.Name;
|
||||
nhibernateType = entityExpr.MetaData.GetPropertyType(memberName);
|
||||
return entityExpr;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string AssociationPathForEntity(MemberExpression expr)
|
||||
{
|
||||
PropertyAccessExpression propExpr = expr.Expression as PropertyAccessExpression;
|
||||
if (propExpr != null)
|
||||
return propExpr.Name + "." + expr.Member.Name;
|
||||
|
||||
EntityExpression entityExpr = expr.Expression as EntityExpression;
|
||||
if (entityExpr != null && entityExpr.Expression != null)
|
||||
return entityExpr.Alias + "." + expr.Member.Name;
|
||||
|
||||
return expr.Member.Name;
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression expr)
|
||||
{
|
||||
expr = (MemberExpression)base.VisitMemberAccess(expr);
|
||||
|
||||
IClassMetadata metaData = GetMetaData(expr.Type);
|
||||
if (metaData != null)
|
||||
{
|
||||
string associationPath = AssociationPathForEntity(expr);
|
||||
return new EntityExpression(associationPath, expr.Member.Name, expr.Type, metaData, expr.Expression);
|
||||
}
|
||||
|
||||
string memberName;
|
||||
IType nhibernateType;
|
||||
EntityExpression parentExpression = GetParentExpression(expr, out memberName, out nhibernateType);
|
||||
|
||||
if (parentExpression != null)
|
||||
{
|
||||
if (nhibernateType.IsCollectionType)
|
||||
{
|
||||
CollectionType collectionType = (CollectionType)nhibernateType;
|
||||
IType nhElementType = collectionType.GetElementType((ISessionFactoryImplementor)_sessionFactory);
|
||||
|
||||
System.Type elementType = nhElementType.ReturnedClass;
|
||||
IClassMetadata elementMetaData = GetMetaData(elementType);
|
||||
|
||||
EntityExpression elementExpression = null;
|
||||
if (elementMetaData != null)
|
||||
elementExpression = new EntityExpression(null, memberName, elementType, elementMetaData, null);
|
||||
|
||||
return new CollectionAccessExpression(memberName, expr.Type, nhibernateType, parentExpression, elementExpression);
|
||||
}
|
||||
|
||||
return new PropertyAccessExpression(memberName, expr.Type, nhibernateType, parentExpression);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression expr)
|
||||
{
|
||||
IClassMetadata metaData = GetMetaData(expr.Type);
|
||||
if (metaData != null)
|
||||
return new EntityExpression(null, expr.Name, expr.Type, metaData, null);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expr)
|
||||
{
|
||||
IQueryable query = expr.Value as IQueryable;
|
||||
if (query != null)
|
||||
{
|
||||
return new QuerySourceExpression("this", query);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Preprocesses an expression tree replacing binary boolean expressions with unary expressions.
|
||||
/// </summary>
|
||||
public class BinaryBooleanReducer : ExpressionVisitor
|
||||
{
|
||||
//this class simplifies this:
|
||||
// timesheet.Entries.Any() == true
|
||||
//to this:
|
||||
// timesheet.Entries.Any()
|
||||
|
||||
private Expression ProcessBinaryExpression(Expression exprToCompare, Expression exprToReturn, ExpressionType nodeType, Expression original)
|
||||
{
|
||||
BooleanConstantFinder visitor = new BooleanConstantFinder();
|
||||
visitor.Visit(exprToCompare);
|
||||
|
||||
if (visitor.Constant.HasValue)
|
||||
{
|
||||
switch (nodeType)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
return visitor.Constant.Value ? exprToReturn : Expression.Not(exprToReturn);
|
||||
case ExpressionType.NotEqual:
|
||||
return visitor.Constant.Value ? Expression.Not(exprToReturn) : exprToReturn;
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
return visitor.Constant.Value ? Expression.Constant(true) : exprToReturn;
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
return visitor.Constant.Value ? exprToReturn : Expression.Constant(false);
|
||||
default:
|
||||
return original;
|
||||
}
|
||||
}
|
||||
else
|
||||
return original;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression expr)
|
||||
{
|
||||
Expression e = ProcessBinaryExpression(expr.Left, expr.Right, expr.NodeType, expr);
|
||||
if (e != expr)
|
||||
return e;
|
||||
e = ProcessBinaryExpression(expr.Right, expr.Left, expr.NodeType, expr);
|
||||
if (e != expr)
|
||||
return e;
|
||||
return base.VisitBinary(expr);
|
||||
|
||||
}
|
||||
|
||||
class BooleanConstantFinder : ExpressionVisitor
|
||||
{
|
||||
private bool _isNestedBinaryExpression;
|
||||
|
||||
public bool? Constant { get; private set; }
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c.Type == typeof(bool) && !_isNestedBinaryExpression)
|
||||
Constant = (bool)c.Value;
|
||||
return c;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression b)
|
||||
{
|
||||
_isNestedBinaryExpression = true;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using NHibernate.Criterion;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a method that returns an <see cref="T:NHibernate.Criterion.ICriterion"/>
|
||||
/// object that compares one property to another property using a binary expression.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to compare on the left hand side of the expression.</param>
|
||||
/// <param name="otherPropertyName">The name of the property to compare on the right hand side of the expression.</param>
|
||||
/// <returns>An initialized <see cref="T:NHibernate.Criterion.ICriterion"/> object.</returns>
|
||||
public delegate ICriterion ComparePropToProp(string propertyName, string otherPropertyName);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a method that returns an <see cref="T:NHibernate.Criterion.ICriterion"/>
|
||||
/// object that compares a property to a constant value using a binary expression.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to compare on the left hand side of the expression.</param>
|
||||
/// <param name="value">The constant value used for the right hand side of the expression.</param>
|
||||
/// <returns>An initialized <see cref="T:NHibernate.Criterion.ICriterion"/> object.</returns>
|
||||
public delegate ICriterion ComparePropToValue(string propertyName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a method that returns an <see cref="T:NHibernate.Criterion.ICriterion"/>
|
||||
/// object that compares a value to a criteria using a binary expression.
|
||||
/// </summary>
|
||||
/// <param name="value">The value on the left hand side of the expression.</param>
|
||||
/// <param name="criteria">The <see cref="T:NHibernate.Criterion.DetachedCriteria"/> used for the right hand side of the expression.</param>
|
||||
/// <returns>An initialized <see cref="T:NHibernate.Criterion.ICriterion"/> object.</returns>
|
||||
public delegate ICriterion CompareValueToCriteria(object value, DetachedCriteria criteria);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a method that returns an <see cref="T:NHibernate.Criterion.ICriterion"/>
|
||||
/// object that compares a property to a criteria using a binary expression.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to compare on the left hand side of the expression.</param>
|
||||
/// <param name="criteria">The <see cref="T:NHibernate.Criterion.DetachedCriteria"/> used for the right hand side of the expression.</param>
|
||||
/// <returns>An initialized <see cref="T:NHibernate.Criterion.ICriterion"/> object.</returns>
|
||||
public delegate ICriterion ComparePropToCriteria(string propertyName, DetachedCriteria criteria);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
public enum BinaryCriterionType
|
||||
{
|
||||
None,
|
||||
Value,
|
||||
Property,
|
||||
Criteria
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using Expression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Visits a BinaryExpression providing the appropriate NHibernate ICriterion.
|
||||
/// </summary>
|
||||
public class BinaryCriterionVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ICriteria rootCriteria;
|
||||
private readonly ISession session;
|
||||
|
||||
public BinaryCriterionVisitor(ICriteria rootCriteria, ISession session)
|
||||
{
|
||||
this.rootCriteria = rootCriteria;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public System.Type ConvertTo { get; private set; }
|
||||
|
||||
public BinaryCriterionType Type { get; private set; }
|
||||
|
||||
public object Value { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public DetachedCriteria Criteria { get; private set; }
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Criteria;
|
||||
|
||||
//TODO: don't hardcode this alias 'sub'
|
||||
Criteria = DetachedCriteria.ForEntityName(rootCriteria.GetEntityOrClassName(), "sub");
|
||||
|
||||
EntityExpression rootEntity = EntityExpressionVisitor.RootEntity(expr);
|
||||
if (rootEntity != null)
|
||||
{
|
||||
string identifierName = rootEntity.MetaData.IdentifierPropertyName;
|
||||
Criteria.Add(Restrictions.EqProperty(rootCriteria.Alias + "." + identifierName, "sub." + identifierName));
|
||||
}
|
||||
|
||||
if (SelectArgumentsVisitor.SupportsMethod(expr.Method.Name))
|
||||
{
|
||||
var projectionVisitor = new SelectArgumentsVisitor(Criteria.Adapt(session), session);
|
||||
projectionVisitor.Visit(expr);
|
||||
Criteria.SetProjection(projectionVisitor.Projection);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
Name = expr.Member.Name;
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Value;
|
||||
Value = QueryUtil.GetExpressionValue(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
Name = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
Name = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
return VisitPropertyAccess(expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitUnary(UnaryExpression expr)
|
||||
{
|
||||
if (expr.NodeType == ExpressionType.Convert)
|
||||
{
|
||||
//convert to the type of the operand, not the type of the conversion
|
||||
ConvertTo = expr.Operand.Type;
|
||||
Visit(expr.Operand);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
public static ICriterion GetBinaryCriteria(
|
||||
ICriteria rootCriteria,
|
||||
ISession session,
|
||||
BinaryExpression expr,
|
||||
ComparePropToValue comparePropToValue,
|
||||
ComparePropToProp comparePropToProp,
|
||||
CompareValueToCriteria compareValueToCriteria,
|
||||
ComparePropToCriteria comparePropToCriteria)
|
||||
{
|
||||
var left = new BinaryCriterionVisitor(rootCriteria, session);
|
||||
var right = new BinaryCriterionVisitor(rootCriteria, session);
|
||||
|
||||
left.Visit(expr.Left);
|
||||
right.Visit(expr.Right);
|
||||
|
||||
//the query should have been preprocessed so that
|
||||
//only the following combinations are possible:
|
||||
// LEFT RIGHT
|
||||
// ========================
|
||||
// property value
|
||||
// property property
|
||||
// property criteria
|
||||
// value criteria
|
||||
// criteria criteria <== not supported yet
|
||||
|
||||
switch (left.Type)
|
||||
{
|
||||
case BinaryCriterionType.Property:
|
||||
switch (right.Type)
|
||||
{
|
||||
case BinaryCriterionType.Value:
|
||||
object val = right.Value;
|
||||
if (left.ConvertTo != null)
|
||||
val = LinqUtil.ChangeType(val, left.ConvertTo);
|
||||
return comparePropToValue(left.Name, val);
|
||||
|
||||
case BinaryCriterionType.Property:
|
||||
return comparePropToProp(left.Name, right.Name);
|
||||
|
||||
case BinaryCriterionType.Criteria:
|
||||
return comparePropToCriteria(left.Name, right.Criteria);
|
||||
}
|
||||
break;
|
||||
|
||||
case BinaryCriterionType.Value:
|
||||
return compareValueToCriteria(left.Value, right.Criteria);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Could not understand: " + expr);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Preprocesses an expression tree ordering binary expressions in accordance with the <see cref="T:NHibernate.Linq.Visitors.BinaryCriterionVisitor"/>.
|
||||
/// </summary>
|
||||
public class BinaryExpressionOrderer : NHibernateExpressionVisitor
|
||||
{
|
||||
// This class makes sure binary expressions are in one of these configurations
|
||||
// so that the BinaryCriterionVisitor can correctly process it.
|
||||
// LEFT RIGHT
|
||||
// ========================
|
||||
// property value
|
||||
// property property
|
||||
// property criteria
|
||||
// value criteria
|
||||
// criteria criteria
|
||||
|
||||
private ExpressionType ReflectExpressionType(ExpressionType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ExpressionType.LessThan:
|
||||
return ExpressionType.GreaterThan;
|
||||
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
return ExpressionType.GreaterThanOrEqual;
|
||||
|
||||
case ExpressionType.GreaterThan:
|
||||
return ExpressionType.LessThan;
|
||||
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
return ExpressionType.LessThanOrEqual;
|
||||
|
||||
case ExpressionType.Equal:
|
||||
return ExpressionType.Equal;
|
||||
|
||||
case ExpressionType.NotEqual:
|
||||
return ExpressionType.NotEqual;
|
||||
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression Swap(BinaryExpression expr)
|
||||
{
|
||||
ExpressionType nodeType = ReflectExpressionType(expr.NodeType);
|
||||
return Expression.MakeBinary(nodeType, expr.Right, expr.Left, expr.IsLiftedToNull, expr.Method, expr.Conversion);
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression expr)
|
||||
{
|
||||
BinaryExpressionTypeFinder left = new BinaryExpressionTypeFinder();
|
||||
left.Visit(expr.Left);
|
||||
|
||||
if (left.Type == BinaryCriterionType.None)
|
||||
return base.VisitBinary(expr);
|
||||
|
||||
BinaryExpressionTypeFinder right = new BinaryExpressionTypeFinder();
|
||||
right.Visit(expr.Right);
|
||||
|
||||
if (right.Type == BinaryCriterionType.None)
|
||||
return base.VisitBinary(expr);
|
||||
|
||||
|
||||
if (right.Type == BinaryCriterionType.Property)
|
||||
{
|
||||
if (left.Type == BinaryCriterionType.Criteria
|
||||
|| left.Type == BinaryCriterionType.Value)
|
||||
{
|
||||
return Swap(expr);
|
||||
}
|
||||
}
|
||||
else if (right.Type == BinaryCriterionType.Value)
|
||||
{
|
||||
if (left.Type == BinaryCriterionType.Criteria)
|
||||
{
|
||||
return Swap(expr);
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
class BinaryExpressionTypeFinder : NHibernateExpressionVisitor
|
||||
{
|
||||
private bool _isNestedBinaryExpression;
|
||||
private BinaryCriterionType _type;
|
||||
|
||||
public BinaryCriterionType Type
|
||||
{
|
||||
get { return _type; }
|
||||
private set
|
||||
{
|
||||
if (!_isNestedBinaryExpression)
|
||||
_type = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression b)
|
||||
{
|
||||
_isNestedBinaryExpression = true;
|
||||
return b;
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Criteria;
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Value;
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
Type = BinaryCriterionType.Property;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Assigns the appropriate aliases to a collection access.
|
||||
/// </summary>
|
||||
public class CollectionAliasVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private IEnumerable<ParameterExpression> _currentCollectionAliases;
|
||||
|
||||
private string FindCollectionAlias(System.Type elementType)
|
||||
{
|
||||
if (_currentCollectionAliases == null) return null;
|
||||
|
||||
foreach (ParameterExpression p in _currentCollectionAliases)
|
||||
{
|
||||
if (p.Type == elementType)
|
||||
{
|
||||
return p.Name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
EntityExpression elementExpression = expr.ElementExpression;
|
||||
if (elementExpression == null)
|
||||
return expr;
|
||||
|
||||
string alias = FindCollectionAlias(elementExpression.Type);
|
||||
|
||||
if (String.IsNullOrEmpty(alias))
|
||||
return expr;
|
||||
|
||||
elementExpression = new EntityExpression(elementExpression.AssociationPath, alias, elementExpression.Type, elementExpression.MetaData, elementExpression.Expression);
|
||||
return new CollectionAccessExpression(expr.Name, expr.Type, expr.NHibernateType, expr.Expression, elementExpression);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
if (expr.Arguments.Count > 1)
|
||||
{
|
||||
LambdaExpression lambda = LinqUtil.StripQuotes(expr.Arguments[1]) as LambdaExpression;
|
||||
if (lambda != null)
|
||||
{
|
||||
_currentCollectionAliases = lambda.Parameters;
|
||||
}
|
||||
}
|
||||
|
||||
return base.VisitMethodCall(expr);
|
||||
}
|
||||
|
||||
public static Expression AssignCollectionAccessAliases(Expression expr)
|
||||
{
|
||||
CollectionAliasVisitor visitor = new CollectionAliasVisitor();
|
||||
return visitor.Visit(expr);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the first (or root) instance of EntityExpression found in the given Expression.
|
||||
/// </summary>
|
||||
public class EntityExpressionVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly bool _findFirstEntity;
|
||||
|
||||
public EntityExpression Expression { get; private set; }
|
||||
|
||||
public EntityExpressionVisitor(bool findFirstEntity)
|
||||
{
|
||||
_findFirstEntity = findFirstEntity;
|
||||
}
|
||||
|
||||
protected override Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
this.Expression = expr;
|
||||
if (_findFirstEntity) return expr;
|
||||
return base.VisitEntity(expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Visit(expr.Arguments[0]);
|
||||
return expr;
|
||||
}
|
||||
|
||||
private static EntityExpression FindEntity(Expression expr, bool findFirst)
|
||||
{
|
||||
EntityExpressionVisitor visitor = new EntityExpressionVisitor(findFirst);
|
||||
visitor.Visit(expr);
|
||||
return visitor.Expression;
|
||||
}
|
||||
|
||||
public static EntityExpression FirstEntity(Expression expr)
|
||||
{
|
||||
return FindEntity(expr, true);
|
||||
}
|
||||
|
||||
public static EntityExpression RootEntity(Expression expr)
|
||||
{
|
||||
return FindEntity(expr, false);
|
||||
}
|
||||
}
|
||||
}
|
131
src/Libraries/NHibernate/NHibernate.Linq/Visitors/Evaluator.cs
Normal file
131
src/Libraries/NHibernate/NHibernate.Linq/Visitors/Evaluator.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
public static class Evaluator
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs evaluation & replacement of independent sub-trees
|
||||
/// </summary>
|
||||
/// <param name="expression">The root of the expression tree.</param>
|
||||
/// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
|
||||
/// <returns>A new tree with sub-trees evaluated and replaced.</returns>
|
||||
public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
|
||||
{
|
||||
return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs evaluation & replacement of independent sub-trees
|
||||
/// </summary>
|
||||
/// <param name="expression">The root of the expression tree.</param>
|
||||
/// <returns>A new tree with sub-trees evaluated and replaced.</returns>
|
||||
public static Expression PartialEval(Expression expression)
|
||||
{
|
||||
return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
|
||||
}
|
||||
|
||||
private static bool CanBeEvaluatedLocally(Expression expression)
|
||||
{
|
||||
if (expression.NodeType == ExpressionType.Constant)
|
||||
{
|
||||
return !(((ConstantExpression)expression).Value is IQueryable);
|
||||
}
|
||||
|
||||
return expression.NodeType != ExpressionType.Parameter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates & replaces sub-trees when first candidate is reached (top-down)
|
||||
/// </summary>
|
||||
class SubtreeEvaluator : ExpressionVisitor
|
||||
{
|
||||
HashSet<Expression> candidates;
|
||||
|
||||
internal SubtreeEvaluator(HashSet<Expression> candidates)
|
||||
{
|
||||
this.candidates = candidates;
|
||||
}
|
||||
|
||||
internal Expression Eval(Expression exp)
|
||||
{
|
||||
return this.Visit(exp);
|
||||
}
|
||||
|
||||
public override Expression Visit(Expression exp)
|
||||
{
|
||||
if (exp == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (this.candidates.Contains(exp))
|
||||
{
|
||||
return this.Evaluate(exp);
|
||||
}
|
||||
return base.Visit(exp);
|
||||
}
|
||||
|
||||
private Expression Evaluate(Expression e)
|
||||
{
|
||||
if (e.NodeType == ExpressionType.Constant)
|
||||
return e;
|
||||
|
||||
if (e.NodeType == ExpressionType.Lambda)
|
||||
return e;
|
||||
|
||||
LambdaExpression lambda = Expression.Lambda(e);
|
||||
Delegate fn = lambda.Compile();
|
||||
return Expression.Constant(fn.DynamicInvoke(null), e.Type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs bottom-up analysis to determine which nodes can possibly
|
||||
/// be part of an evaluated sub-tree.
|
||||
/// </summary>
|
||||
class Nominator : ExpressionVisitor
|
||||
{
|
||||
Func<Expression, bool> fnCanBeEvaluated;
|
||||
HashSet<Expression> candidates;
|
||||
bool cannotBeEvaluated;
|
||||
|
||||
internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
|
||||
{
|
||||
this.fnCanBeEvaluated = fnCanBeEvaluated;
|
||||
}
|
||||
|
||||
internal HashSet<Expression> Nominate(Expression expression)
|
||||
{
|
||||
this.candidates = new HashSet<Expression>();
|
||||
this.Visit(expression);
|
||||
return this.candidates;
|
||||
}
|
||||
|
||||
public override Expression Visit(Expression expression)
|
||||
{
|
||||
if (expression != null)
|
||||
{
|
||||
bool saveCannotBeEvaluated = this.cannotBeEvaluated;
|
||||
this.cannotBeEvaluated = false;
|
||||
base.Visit(expression);
|
||||
if (!this.cannotBeEvaluated)
|
||||
{
|
||||
if (this.fnCanBeEvaluated(expression))
|
||||
{
|
||||
this.candidates.Add(expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.cannotBeEvaluated = true;
|
||||
}
|
||||
}
|
||||
this.cannotBeEvaluated |= saveCannotBeEvaluated;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,394 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides virtual methods that can be used by subclasses to parse an expression tree.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class actually already exists in the System.Core assembly...as an internal class.
|
||||
/// I can only speculate as to why it is internal, but it is obviously much too dangerous
|
||||
/// for anyone outside of Microsoft to be using...
|
||||
/// </remarks>
|
||||
[DebuggerStepThrough, DebuggerNonUserCode]
|
||||
public abstract class ExpressionVisitor
|
||||
{
|
||||
public virtual Expression Visit(Expression exp)
|
||||
{
|
||||
if (exp == null) return exp;
|
||||
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary((UnaryExpression)exp);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return VisitBinary((BinaryExpression)exp);
|
||||
case ExpressionType.TypeIs:
|
||||
return VisitTypeIs((TypeBinaryExpression)exp);
|
||||
case ExpressionType.Conditional:
|
||||
return VisitConditional((ConditionalExpression)exp);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant((ConstantExpression)exp);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter((ParameterExpression)exp);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess((MemberExpression)exp);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall((MethodCallExpression)exp);
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLambda((LambdaExpression)exp);
|
||||
case ExpressionType.New:
|
||||
return VisitNew((NewExpression)exp);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return VisitNewArray((NewArrayExpression)exp);
|
||||
case ExpressionType.Invoke:
|
||||
return VisitInvocation((InvocationExpression)exp);
|
||||
case ExpressionType.MemberInit:
|
||||
return VisitMemberInit((MemberInitExpression)exp);
|
||||
case ExpressionType.ListInit:
|
||||
return VisitListInit((ListInitExpression)exp);
|
||||
default:
|
||||
throw new NotSupportedException(String.Format("Unhandled expression type: '{0}'", exp.NodeType));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual MemberBinding VisitBinding(MemberBinding binding)
|
||||
{
|
||||
switch (binding.BindingType)
|
||||
{
|
||||
case MemberBindingType.Assignment:
|
||||
return VisitMemberAssignment((MemberAssignment)binding);
|
||||
case MemberBindingType.MemberBinding:
|
||||
return VisitMemberMemberBinding((MemberMemberBinding)binding);
|
||||
case MemberBindingType.ListBinding:
|
||||
return VisitMemberListBinding((MemberListBinding)binding);
|
||||
default:
|
||||
throw new NotSupportedException(string.Format("Unhandled binding type '{0}'", binding.BindingType));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
|
||||
{
|
||||
ReadOnlyCollection<Expression> arguments = VisitList(initializer.Arguments);
|
||||
if (arguments != initializer.Arguments)
|
||||
{
|
||||
return Expression.ElementInit(initializer.AddMethod, arguments);
|
||||
}
|
||||
return initializer;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitUnary(UnaryExpression u)
|
||||
{
|
||||
Expression operand = Visit(u.Operand);
|
||||
if (operand != u.Operand)
|
||||
{
|
||||
return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitBinary(BinaryExpression b)
|
||||
{
|
||||
Expression left = Visit(b.Left);
|
||||
Expression right = Visit(b.Right);
|
||||
Expression conversion = Visit(b.Conversion);
|
||||
|
||||
if (left != b.Left || right != b.Right || conversion != b.Conversion)
|
||||
{
|
||||
if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
|
||||
return Expression.Coalesce(left, right, conversion as LambdaExpression);
|
||||
else
|
||||
return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitTypeIs(TypeBinaryExpression b)
|
||||
{
|
||||
Expression expr = Visit(b.Expression);
|
||||
if (expr != b.Expression)
|
||||
{
|
||||
return Expression.TypeIs(expr, b.TypeOperand);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitConstant(ConstantExpression c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitConditional(ConditionalExpression c)
|
||||
{
|
||||
Expression test = Visit(c.Test);
|
||||
Expression ifTrue = Visit(c.IfTrue);
|
||||
Expression ifFalse = Visit(c.IfFalse);
|
||||
|
||||
if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse)
|
||||
{
|
||||
return Expression.Condition(test, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
Expression exp = Visit(m.Expression);
|
||||
if (exp != m.Expression)
|
||||
{
|
||||
return Expression.MakeMemberAccess(exp, m.Member);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
Expression obj = Visit(m.Object);
|
||||
IEnumerable<Expression> args = VisitList(m.Arguments);
|
||||
|
||||
if (obj != m.Object || args != m.Arguments)
|
||||
{
|
||||
return Expression.Call(obj, m.Method, args);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
protected virtual ReadOnlyCollection<Expression> VisitList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
List<Expression> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
Expression p = Visit(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(p);
|
||||
}
|
||||
else if (p != original[i])
|
||||
{
|
||||
list = new List<Expression>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (list != null)
|
||||
return list.AsReadOnly();
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
|
||||
{
|
||||
Expression e = Visit(assignment.Expression);
|
||||
|
||||
if (e != assignment.Expression)
|
||||
{
|
||||
return Expression.Bind(assignment.Member, e);
|
||||
}
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
|
||||
{
|
||||
IEnumerable<MemberBinding> bindings = VisitBindingList(binding.Bindings);
|
||||
|
||||
if (bindings != binding.Bindings)
|
||||
{
|
||||
return Expression.MemberBind(binding.Member, bindings);
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
|
||||
{
|
||||
IEnumerable<ElementInit> initializers = VisitElementInitializerList(binding.Initializers);
|
||||
|
||||
if (initializers != binding.Initializers)
|
||||
{
|
||||
return Expression.ListBind(binding.Member, initializers);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original)
|
||||
{
|
||||
List<MemberBinding> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
MemberBinding b = VisitBinding(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(b);
|
||||
}
|
||||
else if (b != original[i])
|
||||
{
|
||||
list = new List<MemberBinding>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(b);
|
||||
}
|
||||
}
|
||||
|
||||
if (list != null)
|
||||
return list;
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original)
|
||||
{
|
||||
List<ElementInit> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
ElementInit init = VisitElementInitializer(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(init);
|
||||
}
|
||||
else if (init != original[i])
|
||||
{
|
||||
list = new List<ElementInit>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(init);
|
||||
}
|
||||
}
|
||||
|
||||
if (list != null)
|
||||
return list;
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
Expression body = Visit(lambda.Body);
|
||||
if (body != lambda.Body)
|
||||
{
|
||||
return Expression.Lambda(lambda.Type, body, lambda.Parameters);
|
||||
}
|
||||
return lambda;
|
||||
}
|
||||
|
||||
protected virtual NewExpression VisitNew(NewExpression nex)
|
||||
{
|
||||
IEnumerable<Expression> args = VisitList(nex.Arguments);
|
||||
if (args != nex.Arguments)
|
||||
{
|
||||
if (nex.Members != null)
|
||||
return Expression.New(nex.Constructor, args, nex.Members);
|
||||
else
|
||||
return Expression.New(nex.Constructor, args);
|
||||
}
|
||||
|
||||
return nex;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMemberInit(MemberInitExpression init)
|
||||
{
|
||||
NewExpression n = VisitNew(init.NewExpression);
|
||||
IEnumerable<MemberBinding> bindings = VisitBindingList(init.Bindings);
|
||||
|
||||
if (n != init.NewExpression || bindings != init.Bindings)
|
||||
{
|
||||
return Expression.MemberInit(n, bindings);
|
||||
}
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitListInit(ListInitExpression init)
|
||||
{
|
||||
NewExpression n = VisitNew(init.NewExpression);
|
||||
IEnumerable<ElementInit> initializers = VisitElementInitializerList(init.Initializers);
|
||||
|
||||
if (n != init.NewExpression || initializers != init.Initializers)
|
||||
{
|
||||
return Expression.ListInit(n, initializers);
|
||||
}
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
IEnumerable<Expression> exprs = VisitList(na.Expressions);
|
||||
if (exprs != na.Expressions)
|
||||
{
|
||||
if (na.NodeType == ExpressionType.NewArrayInit)
|
||||
{
|
||||
return Expression.NewArrayInit(na.Type.GetElementType(), exprs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Expression.NewArrayBounds(na.Type.GetElementType(), exprs);
|
||||
}
|
||||
}
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitInvocation(InvocationExpression iv)
|
||||
{
|
||||
IEnumerable<Expression> args = VisitList(iv.Arguments);
|
||||
Expression expr = Visit(iv.Expression);
|
||||
|
||||
if (args != iv.Arguments || expr != iv.Expression)
|
||||
{
|
||||
return Expression.Invoke(expr, args);
|
||||
}
|
||||
|
||||
return iv;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using Expression = System.Linq.Expressions.Expression;
|
||||
using NHProjections = NHibernate.Criterion.Projections;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Visits an expression tree providing the appropriate projections for grouping arguments.
|
||||
/// </summary>
|
||||
public class GroupingArgumentsVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ICriteria _rootCriteria;
|
||||
private readonly List<IProjection> _projections = new List<IProjection>();
|
||||
|
||||
public IProjection Projection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_projections.Count == 0)
|
||||
return null;
|
||||
|
||||
if (_projections.Count == 1)
|
||||
return _projections[0];
|
||||
|
||||
ProjectionList list = NHProjections.ProjectionList();
|
||||
foreach (var projection in _projections)
|
||||
list.Add(projection);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public GroupingArgumentsVisitor(ICriteria rootCriteria)
|
||||
{
|
||||
_rootCriteria = rootCriteria;
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
string name = MemberNameVisitor.GetMemberName(_rootCriteria, expr);
|
||||
_projections.Add(NHProjections.GroupProperty(name));
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
return VisitPropertyAccess(expr);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Util;
|
||||
using LinqExpression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
public interface IImmediateResultsVisitor
|
||||
{
|
||||
object GetResults(MethodCallExpression expr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits any expression calls that require immediate results.
|
||||
/// </summary>
|
||||
public class ImmediateResultsVisitor<T> : NHibernateExpressionVisitor, IImmediateResultsVisitor
|
||||
{
|
||||
private readonly ISession session;
|
||||
private readonly ICriteria rootCriteria;
|
||||
private T results;
|
||||
|
||||
public ImmediateResultsVisitor(ISession session, ICriteria rootCriteria)
|
||||
{
|
||||
this.session = session;
|
||||
this.rootCriteria = rootCriteria;
|
||||
}
|
||||
|
||||
public object GetResults(MethodCallExpression expr)
|
||||
{
|
||||
Visit(expr);
|
||||
return results;
|
||||
}
|
||||
|
||||
protected override LinqExpression VisitMethodCall(MethodCallExpression call)
|
||||
{
|
||||
switch (call.Method.Name)
|
||||
{
|
||||
case "First":
|
||||
results = HandleFirstCall(call);
|
||||
break;
|
||||
case "FirstOrDefault":
|
||||
results = HandleFirstOrDefaultCall(call);
|
||||
break;
|
||||
case "Single":
|
||||
results = HandleSingleCall(call);
|
||||
break;
|
||||
case "SingleOrDefault":
|
||||
results = HandleSingleOrDefaultCall(call);
|
||||
break;
|
||||
case "Aggregate":
|
||||
results = HandleAggregateCallback(call);
|
||||
break;
|
||||
case "Average":
|
||||
case "Count":
|
||||
case "LongCount":
|
||||
case "Max":
|
||||
case "Min":
|
||||
case "Sum":
|
||||
rootCriteria.ClearOrders();
|
||||
results = HandleAggregateCall(call);
|
||||
break;
|
||||
case "Any":
|
||||
results = HandleAnyCall(call);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("The method " + call.Method.Name + " is not implemented.");
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
private T HandleFirstCall(MethodCallExpression call)
|
||||
{
|
||||
return GetElementList(call, 1).First();
|
||||
}
|
||||
|
||||
private T HandleFirstOrDefaultCall(MethodCallExpression call)
|
||||
{
|
||||
return GetElementList(call, 1).FirstOrDefault();
|
||||
}
|
||||
|
||||
private T HandleSingleCall(MethodCallExpression call)
|
||||
{
|
||||
return GetElementList(call, 2).Single();
|
||||
}
|
||||
|
||||
private T HandleSingleOrDefaultCall(MethodCallExpression call)
|
||||
{
|
||||
return GetElementList(call, 2).SingleOrDefault();
|
||||
}
|
||||
|
||||
private IList<T> GetElementList(MethodCallExpression call, int count)
|
||||
{
|
||||
if (call.Arguments.Count > 1)
|
||||
rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1]));
|
||||
|
||||
return rootCriteria.SetFirstResult(0).SetMaxResults(count).List<T>();
|
||||
}
|
||||
|
||||
private T HandleAggregateCallback(MethodCallExpression call)
|
||||
{
|
||||
LambdaExpression lambda = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[call.Arguments.Count - 1]);
|
||||
System.Type resultType = lambda.Parameters[1].Type;
|
||||
|
||||
IList list = rootCriteria.List();
|
||||
MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(resultType);
|
||||
IEnumerable enumerable = (IEnumerable)castMethod.Invoke(null, new object[] { list });
|
||||
|
||||
if (call.Arguments.Count == 2)
|
||||
{
|
||||
return (T)call.Method.Invoke(null, new object[]
|
||||
{
|
||||
enumerable.AsQueryable(),
|
||||
lambda
|
||||
});
|
||||
}
|
||||
else if (call.Arguments.Count == 3)
|
||||
{
|
||||
return (T)call.Method.Invoke(null, new[]
|
||||
{
|
||||
enumerable.AsQueryable(),
|
||||
((ConstantExpression)call.Arguments[1]).Value,
|
||||
lambda
|
||||
});
|
||||
}
|
||||
else if (call.Arguments.Count == 4)
|
||||
{
|
||||
return (T)call.Method.Invoke(null, new[]
|
||||
{
|
||||
enumerable.AsQueryable(),
|
||||
((ConstantExpression)call.Arguments[1]).Value,
|
||||
LinqUtil.StripQuotes(call.Arguments[2]),
|
||||
lambda
|
||||
});
|
||||
}
|
||||
|
||||
throw new ArgumentException("Invalid number of arguments passed to the Aggregate method.");
|
||||
}
|
||||
|
||||
private T HandleAggregateCall(MethodCallExpression call)
|
||||
{
|
||||
var visitor = new SelectArgumentsVisitor(rootCriteria, session);
|
||||
visitor.Visit(call);
|
||||
|
||||
T value = default(T);
|
||||
if (visitor.Projection != null)
|
||||
{
|
||||
object result = rootCriteria.SetProjection(visitor.Projection).UniqueResult();
|
||||
if (result != null)
|
||||
{
|
||||
value = (T)LinqUtil.ChangeType(result, typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private T HandleAnyCall(MethodCallExpression call)
|
||||
{
|
||||
rootCriteria.SetProjection(Projections.RowCount());
|
||||
|
||||
if (call.Arguments.Count > 1)
|
||||
rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1]));
|
||||
|
||||
int count = (int)rootCriteria.UniqueResult();
|
||||
|
||||
//HACK: the Any method always returns bool - maybe need to make this class non-generic
|
||||
return (T)(object)(count > 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
public class InheritanceVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private System.Type castedType;
|
||||
|
||||
protected override Expression VisitQuerySource(QuerySourceExpression expr)
|
||||
{
|
||||
if (castedType != null)
|
||||
return new QuerySourceExpression(expr.Alias, expr.Query, castedType);
|
||||
return base.VisitQuerySource(expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
//this is a naive implementation and will not work for any OfType calls not called on root entity
|
||||
if (m.Method.Name == "OfType")
|
||||
this.castedType = m.Method.GetGenericArguments()[0];
|
||||
|
||||
return base.VisitMethodCall(m);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.SqlCommand;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Visits an expression providing the member name being accessed based on the EntityExpressions and
|
||||
/// PropertyAccessExpressions in the expression tree. Any entity associations encountered are added
|
||||
/// as subcriteria to the query.
|
||||
/// </summary>
|
||||
public class MemberNameVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ICriteria rootCriteria;
|
||||
private readonly bool createCriteriaForCollections;
|
||||
private ICriteria currentCriteria;
|
||||
private Expression currentExpression;
|
||||
private StringBuilder memberNameBuilder;
|
||||
private string currentAssociationPath;
|
||||
private bool isQueringEntity;
|
||||
|
||||
public string MemberName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isQueringEntity || memberNameBuilder.Length < 1)
|
||||
return currentAssociationPath;
|
||||
string memberName = memberNameBuilder.ToString();
|
||||
return memberName.Substring(0, memberName.Length - 1); //remove the last "."
|
||||
}
|
||||
}
|
||||
|
||||
public ICriteria CurrentCriteria
|
||||
{
|
||||
get { return currentCriteria; }
|
||||
}
|
||||
|
||||
public Expression CurrentExpression
|
||||
{
|
||||
get { return currentExpression; }
|
||||
}
|
||||
|
||||
public MemberNameVisitor(ICriteria criteria)
|
||||
: this(criteria, false) { }
|
||||
|
||||
public MemberNameVisitor(ICriteria criteria, bool createCriteriaForCollections)
|
||||
{
|
||||
this.rootCriteria = this.currentCriteria = criteria;
|
||||
this.createCriteriaForCollections = createCriteriaForCollections;
|
||||
this.memberNameBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
private void ResetMemberName(string name)
|
||||
{
|
||||
memberNameBuilder = new StringBuilder();
|
||||
memberNameBuilder.Append(name);
|
||||
}
|
||||
|
||||
private ICriteria EnsureCriteria(string associationPath, string alias)
|
||||
{
|
||||
ICriteria criteria;
|
||||
if ((criteria = currentCriteria.GetCriteriaByAlias(alias)) == null)
|
||||
{
|
||||
criteria = currentCriteria.CreateCriteria(associationPath, alias, JoinType.LeftOuterJoin);
|
||||
}
|
||||
return criteria;
|
||||
}
|
||||
|
||||
private bool IsRootEntity(EntityExpression expr)
|
||||
{
|
||||
var nhExpression = expr.Expression as NHibernateExpression;
|
||||
|
||||
if (nhExpression != null)
|
||||
return false;
|
||||
|
||||
if (expr.Type != rootCriteria.GetRootType())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
expr = (EntityExpression)base.VisitEntity(expr);
|
||||
|
||||
if (currentCriteria.GetCriteriaByAlias(expr.Alias) != null || !IsRootEntity(expr))
|
||||
{
|
||||
if (!String.IsNullOrEmpty(expr.AssociationPath))
|
||||
currentCriteria = EnsureCriteria(expr.AssociationPath, expr.Alias);
|
||||
|
||||
ResetMemberName(expr.Alias + ".");
|
||||
}
|
||||
currentAssociationPath = expr.AssociationPath;
|
||||
currentExpression = expr;
|
||||
isQueringEntity = true;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
expr = (PropertyAccessExpression)base.VisitPropertyAccess(expr);
|
||||
memberNameBuilder.Append(expr.Name + ".");
|
||||
|
||||
currentExpression = expr;
|
||||
isQueringEntity = false;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
expr = (CollectionAccessExpression)base.VisitCollectionAccess(expr);
|
||||
//memberNameBuilder.Append(expr.Name + ".");
|
||||
ResetMemberName(expr.Name + ".");
|
||||
currentExpression = expr;
|
||||
|
||||
if (createCriteriaForCollections)
|
||||
{
|
||||
if (expr.ElementExpression != null)
|
||||
{
|
||||
currentCriteria = EnsureCriteria(expr.Name, expr.ElementExpression.Alias);
|
||||
}
|
||||
}
|
||||
|
||||
isQueringEntity = false;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Visit(expr.Arguments[0]);
|
||||
return expr;
|
||||
}
|
||||
|
||||
public static string GetMemberName(ICriteria rootCriteria, Expression expr)
|
||||
{
|
||||
MemberNameVisitor visitor = new MemberNameVisitor(rootCriteria);
|
||||
visitor.Visit(expr);
|
||||
return visitor.MemberName;
|
||||
}
|
||||
|
||||
public static string GetLastMemberName(ICriteria rootCriteria, Expression expr)
|
||||
{
|
||||
return GetMemberName(rootCriteria, expr).Split('.').Last();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// NHibernate-specific base expression visitor.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough, DebuggerNonUserCode]
|
||||
public class NHibernateExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
public override Expression Visit(Expression exp)
|
||||
{
|
||||
if (exp == null) return null;
|
||||
|
||||
switch ((NHibernateExpressionType)exp.NodeType)
|
||||
{
|
||||
case NHibernateExpressionType.QuerySource:
|
||||
return VisitQuerySource((QuerySourceExpression)exp);
|
||||
case NHibernateExpressionType.RootEntity:
|
||||
case NHibernateExpressionType.Entity:
|
||||
return VisitEntity((EntityExpression)exp);
|
||||
case NHibernateExpressionType.PropertyAccess:
|
||||
return VisitPropertyAccess((PropertyAccessExpression)exp);
|
||||
case NHibernateExpressionType.CollectionAccess:
|
||||
return VisitCollectionAccess((CollectionAccessExpression)exp);
|
||||
default:
|
||||
return base.Visit(exp);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Expression VisitQuerySource(QuerySourceExpression expr)
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
Expression e = Visit(expr.Expression);
|
||||
if (e != expr.Expression)
|
||||
{
|
||||
return new EntityExpression(expr.AssociationPath, expr.Alias, expr.Type, expr.MetaData, e);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
EntityExpression e = (EntityExpression)Visit(expr.Expression);
|
||||
if (e != expr.Expression)
|
||||
{
|
||||
return new PropertyAccessExpression(expr.Name, expr.Type, expr.NHibernateType, e);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
EntityExpression e = (EntityExpression)Visit(expr.Expression);
|
||||
if (e != expr.Expression)
|
||||
{
|
||||
return new CollectionAccessExpression(expr.Name, expr.Type, expr.NHibernateType, e, expr.ElementExpression);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using LinqExpression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Translates a Linq Expression into an NHibernate ICriteria object.
|
||||
/// </summary>
|
||||
public class NHibernateQueryTranslator : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ISession session;
|
||||
private readonly string entityName;
|
||||
private ICriteria rootCriteria;
|
||||
private QueryOptions options;
|
||||
|
||||
public NHibernateQueryTranslator(ISession session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
public NHibernateQueryTranslator(ISession session,string entityName)
|
||||
{
|
||||
this.session = session;
|
||||
this.entityName = entityName;
|
||||
}
|
||||
|
||||
public virtual object Translate(LinqExpression expression, QueryOptions queryOptions)
|
||||
{
|
||||
this.rootCriteria = null;
|
||||
this.options = queryOptions;
|
||||
|
||||
Visit(expression); //ensure criteria
|
||||
|
||||
var visitor = new RootVisitor(rootCriteria, session, true);
|
||||
visitor.Visit(expression);
|
||||
return visitor.Results;
|
||||
}
|
||||
|
||||
protected override LinqExpression VisitQuerySource(QuerySourceExpression expr)
|
||||
{
|
||||
if (rootCriteria == null)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(this.entityName))
|
||||
rootCriteria = session.CreateCriteria(entityName, expr.Alias);
|
||||
else
|
||||
rootCriteria = session.CreateCriteria(expr.ElementType, expr.Alias);
|
||||
options.Execute(rootCriteria);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using NHibernate.Linq.Expressions;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts calls to an IEnumerable.Count property to IEnumerable.Count() extension method.
|
||||
/// </summary>
|
||||
public class PropertyToMethodVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private MethodInfo GetCountMethod(System.Type elementType)
|
||||
{
|
||||
//this should work, but it doesn't...
|
||||
//System.Type genericEnumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
|
||||
//return typeof(Enumerable).GetMethod("Count", new System.Type[] { genericEnumerableType });
|
||||
|
||||
var method = typeof(Enumerable).GetMethods()
|
||||
.Where(m => m.Name == "Count" && m.GetParameters().Count() == 1).First();
|
||||
return method.MakeGenericMethod(elementType);
|
||||
}
|
||||
|
||||
private Expression CastIfNecessary(CollectionAccessExpression expr)
|
||||
{
|
||||
if (expr.Type.IsGenericType)
|
||||
return expr;
|
||||
|
||||
MethodInfo method = typeof(Enumerable).GetMethod("Cast")
|
||||
.MakeGenericMethod(expr.ElementExpression.Type);
|
||||
|
||||
return Expression.Call(method, expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
CollectionAccessExpression parent = m.Expression as CollectionAccessExpression;
|
||||
if (parent != null && m.Member.Name == "Count")
|
||||
{
|
||||
MethodInfo method = GetCountMethod(parent.ElementExpression.Type);
|
||||
return Expression.Call(method, CastIfNecessary(parent));
|
||||
}
|
||||
return base.VisitMemberAccess(m);
|
||||
}
|
||||
}
|
||||
}
|
210
src/Libraries/NHibernate/NHibernate.Linq/Visitors/RootVisitor.cs
Normal file
210
src/Libraries/NHibernate/NHibernate.Linq/Visitors/RootVisitor.cs
Normal file
@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using LinqExpression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Translates a Linq Expression into an NHibernate ICriteria object.
|
||||
/// </summary>
|
||||
public class RootVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ICriteria rootCriteria;
|
||||
private readonly ISession session;
|
||||
private readonly bool isAtRoot;
|
||||
private object results;
|
||||
private bool hasResults;
|
||||
|
||||
public object Results
|
||||
{
|
||||
get
|
||||
{
|
||||
if (hasResults)
|
||||
return results;
|
||||
return rootCriteria;
|
||||
}
|
||||
}
|
||||
|
||||
public RootVisitor(ICriteria rootCriteria, ISession session, bool isAtRoot)
|
||||
{
|
||||
this.rootCriteria = rootCriteria;
|
||||
this.session = session;
|
||||
this.isAtRoot = isAtRoot;
|
||||
}
|
||||
|
||||
protected override LinqExpression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Visit(expr.Arguments[0]);
|
||||
|
||||
switch (expr.Method.Name)
|
||||
{
|
||||
case "Where":
|
||||
HandleWhereCall(expr);
|
||||
break;
|
||||
case "Select":
|
||||
HandleSelectCall(expr);
|
||||
break;
|
||||
case "OrderBy":
|
||||
case "ThenBy":
|
||||
HandleOrderByCall(expr);
|
||||
break;
|
||||
case "OrderByDescending":
|
||||
case "ThenByDescending":
|
||||
HandleOrderByDescendingCall(expr);
|
||||
break;
|
||||
case "Take":
|
||||
HandleTakeCall(expr);
|
||||
break;
|
||||
case "Skip":
|
||||
HandleSkipCall(expr);
|
||||
break;
|
||||
case "Distinct":
|
||||
HandleDistinctCall(expr);
|
||||
break;
|
||||
case "GroupBy":
|
||||
HandleGroupByCall(expr);
|
||||
break;
|
||||
case "SelectMany":
|
||||
HandleSelectManyCall(expr);
|
||||
break;
|
||||
case "OfType":
|
||||
case "Cast":
|
||||
//ignore OfType calls -- handled by InheritanceVisitor
|
||||
break;
|
||||
case "First":
|
||||
case "FirstOrDefault":
|
||||
case "Single":
|
||||
case "SingleOrDefault":
|
||||
case "Aggregate":
|
||||
case "Average":
|
||||
case "Count":
|
||||
case "LongCount":
|
||||
case "Max":
|
||||
case "Min":
|
||||
case "Sum":
|
||||
case "Any":
|
||||
if (isAtRoot)
|
||||
HandleImmediateResultsCall(expr);
|
||||
else
|
||||
HandleSelectMethodCall(expr);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("The method " + expr.Method.Name + " is not implemented.");
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private void HandleWhereCall(MethodCallExpression call)
|
||||
{
|
||||
IEnumerable<ICriterion> criterion = WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1]);
|
||||
rootCriteria.Add(criterion);
|
||||
}
|
||||
|
||||
private void HandleSelectCall(MethodCallExpression call)
|
||||
{
|
||||
var lambda = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[1]);
|
||||
|
||||
var visitor = new SelectArgumentsVisitor(rootCriteria, session);
|
||||
visitor.Visit(lambda.Body);
|
||||
|
||||
rootCriteria.SetProjectionIfNotNull(visitor.Projection);
|
||||
rootCriteria.SetResultTransformerIfNotNull(visitor.Transformer);
|
||||
}
|
||||
|
||||
private void HandleOrderByCall(MethodCallExpression call)
|
||||
{
|
||||
LinqExpression expr = ((UnaryExpression)call.Arguments[1]).Operand;
|
||||
|
||||
string name = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
rootCriteria.AddOrder(Order.Asc(name));
|
||||
}
|
||||
|
||||
private void HandleOrderByDescendingCall(MethodCallExpression call)
|
||||
{
|
||||
LinqExpression expr = ((UnaryExpression)call.Arguments[1]).Operand;
|
||||
|
||||
string name = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
rootCriteria.AddOrder(Order.Desc(name));
|
||||
}
|
||||
|
||||
private void HandleTakeCall(MethodCallExpression call)
|
||||
{
|
||||
var count = (int)((ConstantExpression)call.Arguments[1]).Value;
|
||||
rootCriteria.SetMaxResults(count);
|
||||
}
|
||||
|
||||
private void HandleSkipCall(MethodCallExpression call)
|
||||
{
|
||||
var index = (int)((ConstantExpression)call.Arguments[1]).Value;
|
||||
rootCriteria.SetFirstResult(index);
|
||||
}
|
||||
|
||||
private void HandleDistinctCall(MethodCallExpression call)
|
||||
{
|
||||
var projection = rootCriteria.GetProjection() as PropertyProjection;
|
||||
if (projection != null)
|
||||
{
|
||||
rootCriteria.SetProjection(
|
||||
Projections.Distinct(
|
||||
Projections.Property(projection.PropertyName)));
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGroupByCall(MethodCallExpression call)
|
||||
{
|
||||
var visitor = new GroupingArgumentsVisitor(rootCriteria);
|
||||
visitor.Visit(call.Arguments[1]);
|
||||
rootCriteria.SetProjectionIfNotNull(visitor.Projection);
|
||||
}
|
||||
|
||||
private void HandleSelectManyCall(MethodCallExpression call)
|
||||
{
|
||||
//get the association path for the joined entity
|
||||
var collectionSelector = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[1]);
|
||||
|
||||
LambdaExpression resultSelector = null;
|
||||
if (call.Arguments.Count == 3)
|
||||
{
|
||||
resultSelector = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[2]);
|
||||
string alias = resultSelector.Parameters[1].Name;
|
||||
|
||||
var visitor = new SelectManyVisitor(rootCriteria, alias);
|
||||
visitor.Visit(collectionSelector.Body);
|
||||
}
|
||||
|
||||
if (resultSelector != null)
|
||||
{
|
||||
//visit the result selector expression after the alias for the association has been created
|
||||
var resultSelectorVisitor = new SelectArgumentsVisitor(rootCriteria, session);
|
||||
resultSelectorVisitor.Visit(resultSelector.Body);
|
||||
|
||||
rootCriteria.SetProjectionIfNotNull(resultSelectorVisitor.Projection);
|
||||
rootCriteria.SetResultTransformerIfNotNull(resultSelectorVisitor.Transformer);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleImmediateResultsCall(MethodCallExpression call)
|
||||
{
|
||||
System.Type resultType = call.Method.ReturnType;
|
||||
System.Type visitorType = typeof(ImmediateResultsVisitor<>)
|
||||
.MakeGenericType(resultType);
|
||||
|
||||
var visitor = (IImmediateResultsVisitor)Activator
|
||||
.CreateInstance(visitorType, session, rootCriteria);
|
||||
|
||||
hasResults = true;
|
||||
results = visitor.GetResults(call);
|
||||
}
|
||||
|
||||
private void HandleSelectMethodCall(MethodCallExpression call)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,361 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Dialect.Function;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Transform;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.Transform;
|
||||
using NHibernate.Type;
|
||||
using Expression = System.Linq.Expressions.Expression;
|
||||
using NHProjections = NHibernate.Criterion.Projections;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the appropriate NHibernate selection projections and/or IResultTransformers
|
||||
/// based on a given expression tree.
|
||||
/// </summary>
|
||||
public class SelectArgumentsVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
#region Fields & Properties
|
||||
|
||||
private static readonly ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")");
|
||||
private static readonly ISQLFunction arithmaticDivide = new VarArgsSQLFunction("(", "/", ")");
|
||||
private static readonly ISQLFunction arithmaticMultiply = new VarArgsSQLFunction("(", "*", ")");
|
||||
private static readonly ISQLFunction arithmaticSubstract = new VarArgsSQLFunction("(", "-", ")");
|
||||
|
||||
private readonly ICriteria _rootCriteria;
|
||||
private readonly ISession _session;
|
||||
private readonly List<IProjection> _projections;
|
||||
private IResultTransformer _transformer;
|
||||
private ICriteriaQuery _criteriaQuery;
|
||||
|
||||
public IProjection Projection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_projections.Count == 0)
|
||||
return null;
|
||||
|
||||
if (_projections.Count == 1)
|
||||
return _projections[0];
|
||||
|
||||
ProjectionList list = NHProjections.ProjectionList();
|
||||
foreach (var projection in _projections)
|
||||
list.Add(projection);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public IResultTransformer Transformer
|
||||
{
|
||||
get { return _transformer; }
|
||||
}
|
||||
|
||||
private ICriteriaQuery CriteriaQuery
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_criteriaQuery == null)
|
||||
_criteriaQuery = _rootCriteria.GenerateCriteriaQuery(_session.SessionFactory, _rootCriteria.GetEntityOrClassName());
|
||||
return _criteriaQuery;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public SelectArgumentsVisitor(ICriteria rootCriteria, ISession session)
|
||||
{
|
||||
_rootCriteria = rootCriteria;
|
||||
_session = session;
|
||||
_projections = new List<IProjection>();
|
||||
}
|
||||
|
||||
public static bool SupportsMethod(string methodName)
|
||||
{
|
||||
return "Average".Equals(methodName)
|
||||
|| "Count".Equals(methodName)
|
||||
|| "LongCount".Equals(methodName)
|
||||
|| "Max".Equals(methodName)
|
||||
|| "Min".Equals(methodName)
|
||||
|| "Sum".Equals(methodName);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
if (WhereArgumentsVisitor.SupportsMethod(expr.Method.Name))
|
||||
return VisitCriterionExpression(expr);
|
||||
|
||||
//TODO: this needs to be refactored...
|
||||
//create any collection subcriteria and get the collection access expression
|
||||
MemberNameVisitor memberVisitor = new MemberNameVisitor(_rootCriteria, true);
|
||||
memberVisitor.Visit(expr.Arguments[0]);
|
||||
CollectionAccessExpression collectionExpr = (CollectionAccessExpression)memberVisitor.CurrentExpression;
|
||||
|
||||
string propertyName = null;
|
||||
IProjection projection = null;
|
||||
PropertyProjection currentProjection;
|
||||
|
||||
if (expr.Arguments.Count > 1)
|
||||
{
|
||||
propertyName = MemberNameVisitor.GetMemberName(_rootCriteria, expr.Arguments[1]);
|
||||
}
|
||||
else if ((currentProjection = _rootCriteria.GetProjection() as PropertyProjection) != null)
|
||||
{
|
||||
propertyName = currentProjection.PropertyName;
|
||||
}
|
||||
|
||||
switch (expr.Method.Name)
|
||||
{
|
||||
case "Average":
|
||||
projection = NHProjections.Avg(propertyName);
|
||||
break;
|
||||
case "Count":
|
||||
case "LongCount":
|
||||
if (expr.Arguments.Count > 1)
|
||||
_rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(_rootCriteria, _session, expr.Arguments[1]));
|
||||
|
||||
if (collectionExpr != null)
|
||||
{
|
||||
//get count on collection element's identifier property
|
||||
propertyName = memberVisitor.MemberName + "." + collectionExpr.ElementExpression.MetaData.IdentifierPropertyName;
|
||||
projection = NHProjections.Count(propertyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
projection = NHProjections.RowCount();
|
||||
}
|
||||
break;
|
||||
case "Max":
|
||||
projection = NHProjections.Max(propertyName);
|
||||
break;
|
||||
case "Min":
|
||||
projection = NHProjections.Min(propertyName);
|
||||
break;
|
||||
case "Sum":
|
||||
projection = NHProjections.Sum(propertyName);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("The method '" + expr.Method.Name + "' is not implemented.");
|
||||
}
|
||||
|
||||
_projections.Add(projection);
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expr)
|
||||
{
|
||||
_projections.Add(new ConstantProjection(expr.Value));
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override NewExpression VisitNew(NewExpression expr)
|
||||
{
|
||||
NewExpression newExpr = base.VisitNew(expr);
|
||||
_transformer = new TypeSafeConstructorMemberInitResultTransformer(expr);
|
||||
|
||||
var aggregators = expr.Arguments.Where(arg => arg is MethodCallExpression && SupportsMethod(((MethodCallExpression)arg).Method.Name));
|
||||
if (aggregators.Any())
|
||||
{
|
||||
foreach (var exp in expr.Arguments.Except(aggregators))
|
||||
{
|
||||
string propertyName = MemberNameVisitor.GetMemberName(_rootCriteria, exp);
|
||||
if (!String.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
_projections.Add(NHProjections.GroupProperty(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newExpr;
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberInit(MemberInitExpression expr)
|
||||
{
|
||||
Expression newExpr = base.VisitMemberInit(expr);
|
||||
_transformer = new TypeSafeConstructorMemberInitResultTransformer(expr);
|
||||
return newExpr;
|
||||
}
|
||||
|
||||
protected override Expression VisitConditional(ConditionalExpression expr)
|
||||
{
|
||||
var visitorTrue = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
visitorTrue.Visit(expr.IfTrue);
|
||||
|
||||
var visitorFalse = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
visitorFalse.Visit(expr.IfFalse);
|
||||
|
||||
var visitorCondition = new WhereArgumentsVisitor(_rootCriteria, _session);
|
||||
visitorCondition.Visit(expr.Test);
|
||||
Conjunction conjunction = NHibernate.Criterion.Expression.Conjunction();
|
||||
foreach (var criterion in visitorCondition.CurrentCriterions)
|
||||
{
|
||||
conjunction.Add(criterion);
|
||||
}
|
||||
|
||||
_projections.Add(
|
||||
NHibernate.Criterion.Projections
|
||||
.Conditional(conjunction,
|
||||
visitorTrue.Projection,
|
||||
visitorFalse.Projection)
|
||||
);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression expr)
|
||||
{
|
||||
switch (expr.NodeType)
|
||||
{
|
||||
case ExpressionType.Add:
|
||||
VisitAddExpression(expr);
|
||||
break;
|
||||
case ExpressionType.Divide:
|
||||
VisitDivideExpression(expr);
|
||||
break;
|
||||
case ExpressionType.Multiply:
|
||||
VisitMultiplyExpression(expr);
|
||||
break;
|
||||
case ExpressionType.Subtract:
|
||||
VisitSubtractExpression(expr);
|
||||
break;
|
||||
default:
|
||||
return VisitCriterionExpression(expr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private Expression VisitCriterionExpression(Expression expr)
|
||||
{
|
||||
IEnumerable<ICriterion> criterion = WhereArgumentsVisitor.GetCriterion(_rootCriteria, _session, expr);
|
||||
|
||||
if (criterion.Count() > 0)
|
||||
{
|
||||
Conjunction conjunction = new Conjunction();
|
||||
foreach (ICriterion crit in criterion)
|
||||
{
|
||||
conjunction.Add(crit);
|
||||
}
|
||||
|
||||
_projections.Add(Projections.Conditional(
|
||||
conjunction,
|
||||
Projections.Constant(true),
|
||||
Projections.Constant(false))
|
||||
);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
#region Arithmetic
|
||||
|
||||
private void VisitAddExpression(BinaryExpression expr)
|
||||
{
|
||||
var leftVisitor = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
var rightVisitor = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
leftVisitor.Visit(expr.Left);
|
||||
rightVisitor.Visit(expr.Right);
|
||||
|
||||
var joinedProjections = new List<IProjection>();
|
||||
joinedProjections.AddRange(leftVisitor._projections);
|
||||
joinedProjections.AddRange(rightVisitor._projections);
|
||||
|
||||
IType[] types = joinedProjections[0].GetTypes(_rootCriteria, CriteriaQuery);
|
||||
var useConcat = types[0] is AbstractStringType;
|
||||
SqlFunctionProjection projection;
|
||||
if (useConcat)
|
||||
{
|
||||
projection = new SqlFunctionProjection("concat", types[0], joinedProjections.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
projection = new SqlFunctionProjection(arithmaticAddition, types[0], joinedProjections.ToArray());
|
||||
}
|
||||
_projections.Add(projection);
|
||||
}
|
||||
|
||||
private void VisitMultiplyExpression(BinaryExpression expr)
|
||||
{
|
||||
VisitAritmaticOperation(expr, arithmaticMultiply);
|
||||
}
|
||||
|
||||
private void VisitSubtractExpression(BinaryExpression expr)
|
||||
{
|
||||
VisitAritmaticOperation(expr, arithmaticSubstract);
|
||||
}
|
||||
|
||||
private void VisitDivideExpression(BinaryExpression expr)
|
||||
{
|
||||
VisitAritmaticOperation(expr, arithmaticDivide);
|
||||
}
|
||||
|
||||
private void VisitAritmaticOperation(BinaryExpression expr, ISQLFunction arithmaticOperation)
|
||||
{
|
||||
var leftVisitor = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
var rightVisitor = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
leftVisitor.Visit(expr.Left);
|
||||
rightVisitor.Visit(expr.Right);
|
||||
|
||||
var joinedProjections = new List<IProjection>();
|
||||
joinedProjections.AddRange(leftVisitor._projections);
|
||||
joinedProjections.AddRange(rightVisitor._projections);
|
||||
var types = joinedProjections[0].GetTypes(_rootCriteria, CriteriaQuery);
|
||||
var projection = new SqlFunctionProjection(arithmaticOperation, types[0], joinedProjections.ToArray());
|
||||
_projections.Add(projection);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override Expression VisitUnary(UnaryExpression expr)
|
||||
{
|
||||
if (expr.NodeType == ExpressionType.Convert)
|
||||
{
|
||||
var visitor = new SelectArgumentsVisitor(_rootCriteria, _session);
|
||||
visitor.Visit(expr.Operand);
|
||||
|
||||
ProjectionList list = NHProjections.ProjectionList();
|
||||
foreach (IProjection proj in visitor._projections)
|
||||
list.Add(proj);
|
||||
|
||||
var projection = new CastProjection(NHibernateUtil.GuessType(expr.Type), list);
|
||||
_projections.Add(projection);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitEntity(EntityExpression expr)
|
||||
{
|
||||
if (_rootCriteria.GetCriteriaByAlias(expr.Alias) != null)
|
||||
{
|
||||
_transformer = new LinqJoinResultsTransformer(expr.Type);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression expr)
|
||||
{
|
||||
//this must be a grouping parameter member access
|
||||
IProjection projection = _rootCriteria.GetProjection();
|
||||
if (projection != null && projection.IsGrouped)
|
||||
{
|
||||
_projections.Add(NHProjections.Alias(projection, expr.Member.Name));
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
string memberName = MemberNameVisitor.GetMemberName(_rootCriteria, expr);
|
||||
_projections.Add(NHProjections.Property(memberName));
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.SqlCommand;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the appropriate subcriteria to the query based on a SelectMany expression tree.
|
||||
/// </summary>
|
||||
public class SelectManyVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly ICriteria _rootCriteria;
|
||||
private readonly string _alias;
|
||||
|
||||
public SelectManyVisitor(ICriteria criteria, string alias)
|
||||
{
|
||||
_rootCriteria = criteria;
|
||||
_alias = alias;
|
||||
}
|
||||
|
||||
protected override Expression VisitCollectionAccess(CollectionAccessExpression expr)
|
||||
{
|
||||
MemberNameVisitor visitor = new MemberNameVisitor(_rootCriteria, false);
|
||||
visitor.Visit(expr.Expression);
|
||||
|
||||
visitor.CurrentCriteria.CreateCriteria(expr.Name, _alias, JoinType.LeftOuterJoin);
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
Visit(expr.Arguments[0]);
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,370 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Linq.Expressions;
|
||||
using NHibernate.Linq.Util;
|
||||
using NHibernate.Persister.Entity;
|
||||
using Expression = System.Linq.Expressions.Expression;
|
||||
|
||||
namespace NHibernate.Linq.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides ICriterion for a query given a Linq expression tree.
|
||||
/// </summary>
|
||||
public class WhereArgumentsVisitor : NHibernateExpressionVisitor
|
||||
{
|
||||
private readonly Stack<IList<ICriterion>> criterionStack = new Stack<IList<ICriterion>>();
|
||||
private readonly ICriteria rootCriteria;
|
||||
private readonly ISession session;
|
||||
|
||||
public WhereArgumentsVisitor(ICriteria rootCriteria, ISession session)
|
||||
{
|
||||
criterionStack.Push(new List<ICriterion>());
|
||||
this.rootCriteria = rootCriteria;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public static IEnumerable<ICriterion> GetCriterion(ICriteria rootCriteria, ISession session, Expression expression)
|
||||
{
|
||||
var visitor = new WhereArgumentsVisitor(rootCriteria, session);
|
||||
visitor.Visit(expression);
|
||||
return visitor.CurrentCriterions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current collection of <see cref="T:NHibernate.Criterion.ICriterion"/> objects.
|
||||
/// </summary>
|
||||
public IList<ICriterion> CurrentCriterions
|
||||
{
|
||||
get { return criterionStack.Peek(); }
|
||||
}
|
||||
|
||||
public static bool SupportsMethod(string methodName)
|
||||
{
|
||||
return "Any".Equals(methodName)
|
||||
|| "StartsWith".Equals(methodName)
|
||||
|| "EndsWith".Equals(methodName)
|
||||
|| "Contains".Equals(methodName)
|
||||
|| "Equals".Equals(methodName);
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expr)
|
||||
{
|
||||
if (expr.Type == typeof(bool))
|
||||
{
|
||||
bool value = (bool)expr.Value;
|
||||
var falseCriteria = NHibernate.Criterion.Expression.Sql("1=0");
|
||||
var trueCriteria = NHibernate.Criterion.Expression.Sql("1=1");
|
||||
if (value)
|
||||
{
|
||||
this.CurrentCriterions.Add(trueCriteria);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.CurrentCriterions.Add(falseCriteria);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (expr.Type.IsSubclassOf(typeof(Expression)))
|
||||
return Visit(expr.Value as Expression);
|
||||
|
||||
return base.VisitConstant(expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expr)
|
||||
{
|
||||
switch (expr.Method.Name)
|
||||
{
|
||||
case "Any":
|
||||
CurrentCriterions.Add(GetExistsCriteria(expr));
|
||||
break;
|
||||
case "StartsWith":
|
||||
CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.Start));
|
||||
break;
|
||||
case "EndsWith":
|
||||
CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.End));
|
||||
break;
|
||||
case "Contains":
|
||||
if (expr.Object == null)
|
||||
{
|
||||
if (expr.Arguments[0] is ConstantExpression)
|
||||
{
|
||||
CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Arguments[0], expr.Arguments[1]));
|
||||
}
|
||||
else if (expr.Arguments[0] is CollectionAccessExpression)
|
||||
{
|
||||
CurrentCriterions.Add(GetCollectionContainsCriteria((CollectionAccessExpression)expr.Arguments[0], expr.Arguments[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
//myArray.Contains(user.Name)
|
||||
CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Arguments[0], expr.Arguments[1]));
|
||||
}
|
||||
}
|
||||
else if (expr.Object is ConstantExpression)
|
||||
{
|
||||
//myList.Contains(user.Name)
|
||||
CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Object, expr.Arguments[0]));
|
||||
}
|
||||
else if (expr.Object is CollectionAccessExpression)
|
||||
{
|
||||
//timesheet.Entries.Contains(entry)
|
||||
CurrentCriterions.Add(GetCollectionContainsCriteria((CollectionAccessExpression)expr.Object, expr.Arguments[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
//user.Name.Contains(partialName)
|
||||
CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.Anywhere));
|
||||
}
|
||||
break;
|
||||
case "Equals":
|
||||
VisitBinaryCriterionExpression(Expression.Equal(expr.Object, expr.Arguments[0]));
|
||||
break;
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitTypeIs(TypeBinaryExpression expr)
|
||||
{
|
||||
var visitor = new MemberNameVisitor(rootCriteria);
|
||||
visitor.Visit(expr);
|
||||
string memberName = visitor.MemberName + ".class";
|
||||
|
||||
var metaData = session.SessionFactory.GetClassMetadata(expr.TypeOperand);
|
||||
if (metaData.HasSubclasses)
|
||||
{
|
||||
//make sure to include any subtypes
|
||||
var disjunction = new Disjunction();
|
||||
foreach (string entityName in ((IEntityPersister)metaData).EntityMetamodel.SubclassEntityNames)
|
||||
{
|
||||
var metadata = session.SessionFactory.GetClassMetadata(entityName);
|
||||
disjunction.Add(Property.ForName(memberName).Eq(metadata.MappedClass));
|
||||
}
|
||||
visitor.CurrentCriteria.Add(disjunction);
|
||||
}
|
||||
else
|
||||
{
|
||||
visitor.CurrentCriteria.Add(Property.ForName(memberName).Eq(expr.TypeOperand));
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression expr)
|
||||
{
|
||||
switch (expr.NodeType)
|
||||
{
|
||||
case ExpressionType.AndAlso:
|
||||
VisitAndAlsoExpression(expr);
|
||||
break;
|
||||
|
||||
case ExpressionType.OrElse:
|
||||
VisitOrElseExpression(expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
VisitBinaryCriterionExpression(expr);
|
||||
break;
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private void VisitAndAlsoExpression(BinaryExpression expr)
|
||||
{
|
||||
criterionStack.Push(new List<ICriterion>());
|
||||
Visit(expr.Left);
|
||||
Visit(expr.Right);
|
||||
var ands = criterionStack.Pop();
|
||||
|
||||
var conjunction = new Conjunction();
|
||||
foreach (var crit in ands)
|
||||
conjunction.Add(crit);
|
||||
CurrentCriterions.Add(conjunction);
|
||||
}
|
||||
|
||||
private void VisitOrElseExpression(BinaryExpression expr)
|
||||
{
|
||||
criterionStack.Push(new List<ICriterion>());
|
||||
Visit(expr.Left);
|
||||
Visit(expr.Right);
|
||||
IList<ICriterion> ors = criterionStack.Pop();
|
||||
|
||||
var disjunction = new Disjunction();
|
||||
foreach (ICriterion crit in ors)
|
||||
{
|
||||
disjunction.Add(crit);
|
||||
}
|
||||
CurrentCriterions.Add(disjunction);
|
||||
}
|
||||
|
||||
private void VisitBinaryCriterionExpression(BinaryExpression expr)
|
||||
{
|
||||
ComparePropToValue comparePropToValue = null;
|
||||
ComparePropToProp comparePropToProp = null;
|
||||
CompareValueToCriteria compareValueToCriteria = null;
|
||||
ComparePropToCriteria comparePropToCriteria = null;
|
||||
|
||||
switch (expr.NodeType)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
comparePropToValue = (n, v) => (v != null) ? Restrictions.Eq(n, v) : Restrictions.IsNull(n);
|
||||
comparePropToProp = Restrictions.EqProperty;
|
||||
compareValueToCriteria = Subqueries.Eq;
|
||||
comparePropToCriteria = Subqueries.PropertyEq;
|
||||
break;
|
||||
|
||||
case ExpressionType.GreaterThan:
|
||||
comparePropToValue = Restrictions.Gt;
|
||||
comparePropToProp = Restrictions.GtProperty;
|
||||
compareValueToCriteria = Subqueries.Gt;
|
||||
comparePropToCriteria = Subqueries.PropertyGt;
|
||||
break;
|
||||
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
comparePropToValue = Restrictions.Ge;
|
||||
comparePropToProp = Restrictions.GeProperty;
|
||||
compareValueToCriteria = Subqueries.Ge;
|
||||
comparePropToCriteria = Subqueries.PropertyGe;
|
||||
break;
|
||||
|
||||
case ExpressionType.LessThan:
|
||||
comparePropToValue = Restrictions.Lt;
|
||||
comparePropToProp = Restrictions.LtProperty;
|
||||
compareValueToCriteria = Subqueries.Lt;
|
||||
comparePropToCriteria = Subqueries.PropertyLt;
|
||||
break;
|
||||
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
comparePropToValue = Restrictions.Le;
|
||||
comparePropToProp = Restrictions.LeProperty;
|
||||
compareValueToCriteria = Subqueries.Le;
|
||||
comparePropToCriteria = Subqueries.PropertyLe;
|
||||
break;
|
||||
|
||||
case ExpressionType.NotEqual:
|
||||
comparePropToValue = (n, v) => (v != null) ? Restrictions.Not(Restrictions.Eq(n, v)) : Restrictions.IsNotNull(n);
|
||||
comparePropToProp = Restrictions.NotEqProperty;
|
||||
compareValueToCriteria = Subqueries.Ne;
|
||||
comparePropToCriteria = Subqueries.PropertyNe;
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentCriterions.Add(
|
||||
BinaryCriterionVisitor.GetBinaryCriteria(rootCriteria, session,
|
||||
expr, comparePropToValue, comparePropToProp,
|
||||
compareValueToCriteria, comparePropToCriteria));
|
||||
}
|
||||
|
||||
protected override Expression VisitUnary(UnaryExpression expr)
|
||||
{
|
||||
switch (expr.NodeType)
|
||||
{
|
||||
case ExpressionType.Quote:
|
||||
Visit(expr.Operand);
|
||||
break;
|
||||
|
||||
case ExpressionType.Not:
|
||||
VisitNotExpression(expr);
|
||||
break;
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private void VisitNotExpression(UnaryExpression expr)
|
||||
{
|
||||
var criterions = GetCriterion(rootCriteria, session, expr.Operand);
|
||||
|
||||
Conjunction conjunction = Restrictions.Conjunction();
|
||||
foreach (var criterion in criterions)
|
||||
conjunction.Add(criterion);
|
||||
|
||||
CurrentCriterions.Add(Restrictions.Not(conjunction));
|
||||
}
|
||||
|
||||
protected override Expression VisitPropertyAccess(PropertyAccessExpression expr)
|
||||
{
|
||||
if (expr.Type == typeof(bool))
|
||||
{
|
||||
string name = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
CurrentCriterions.Add(Restrictions.Eq(name, true));
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private ICriterion GetExistsCriteria(MethodCallExpression expr)
|
||||
{
|
||||
EntityExpression rootEntity = EntityExpressionVisitor.FirstEntity(expr);
|
||||
string propertyName = MemberNameVisitor.GetMemberName(rootCriteria, expr);
|
||||
|
||||
DetachedCriteria query = DetachedCriteria.For(rootEntity.Type)
|
||||
.SetProjection(Projections.Id())
|
||||
.Add(Restrictions.IsNotEmpty(propertyName));
|
||||
|
||||
if (expr.Arguments.Count > 1)
|
||||
{
|
||||
var arg = (LambdaExpression)LinqUtil.StripQuotes(expr.Arguments[1]);
|
||||
string alias = arg.Parameters[0].Name;
|
||||
|
||||
DetachedCriteria subquery = query.CreateCriteria(propertyName, alias);
|
||||
|
||||
var temp = new WhereArgumentsVisitor(subquery.Adapt(session), session);
|
||||
temp.Visit(arg.Body);
|
||||
|
||||
foreach (ICriterion c in temp.CurrentCriterions)
|
||||
{
|
||||
subquery.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
string identifierName = rootEntity.GetAliasedIdentifierPropertyName();
|
||||
return Subqueries.PropertyIn(identifierName, query);
|
||||
}
|
||||
|
||||
private ICriterion GetLikeCriteria(MethodCallExpression expr, MatchMode matchMode)
|
||||
{
|
||||
return Restrictions.Like(MemberNameVisitor.GetMemberName(rootCriteria, expr.Object),
|
||||
String.Format("{0}", QueryUtil.GetExpressionValue(expr.Arguments[0])),
|
||||
matchMode);
|
||||
}
|
||||
|
||||
private ICriterion GetCollectionContainsCriteria(CollectionAccessExpression arg, Expression containsExpression)
|
||||
{
|
||||
EntityExpression rootEntity = EntityExpressionVisitor.FirstEntity(arg);
|
||||
|
||||
DetachedCriteria query = DetachedCriteria.For(rootEntity.Type)
|
||||
.SetProjection(Projections.Id());
|
||||
|
||||
var visitor = new MemberNameVisitor(query.Adapt(session), true);
|
||||
visitor.Visit(arg);
|
||||
|
||||
//TODO: this won't work for collections of values
|
||||
var containedEntity = QueryUtil.GetExpressionValue(containsExpression);
|
||||
var collectionIdPropertyName = visitor.MemberName + "." + arg.ElementExpression.MetaData.IdentifierPropertyName;
|
||||
var idValue = arg.ElementExpression.MetaData.GetIdentifier(containedEntity);
|
||||
|
||||
query.Add(Restrictions.Eq(collectionIdPropertyName, idValue));
|
||||
|
||||
string identifierName = rootEntity.MetaData.IdentifierPropertyName;
|
||||
return Subqueries.PropertyIn(identifierName, query);
|
||||
}
|
||||
|
||||
private ICriterion GetCollectionContainsCriteria(Expression list, Expression containedExpr)
|
||||
{
|
||||
var values = QueryUtil.GetExpressionValue(list) as ICollection;
|
||||
|
||||
if (values == null)
|
||||
throw new InvalidOperationException("Expression argument must be of type ICollection.");
|
||||
|
||||
return Restrictions.In(MemberNameVisitor.GetMemberName(rootCriteria, containedExpr),
|
||||
values);
|
||||
}
|
||||
}
|
||||
}
|
8
src/Libraries/NHibernate/NHibernate.Linq/packages.config
Normal file
8
src/Libraries/NHibernate/NHibernate.Linq/packages.config
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Antlr3.Runtime" version="3.5.1" targetFramework="net48" />
|
||||
<package id="Iesi.Collections" version="4.0.4" targetFramework="net48" />
|
||||
<package id="NHibernate" version="5.3.10" targetFramework="net48" />
|
||||
<package id="Remotion.Linq" version="2.2.0" targetFramework="net48" />
|
||||
<package id="Remotion.Linq.EagerFetching" version="2.2.0" targetFramework="net48" />
|
||||
</packages>
|
6
src/NuGet.config
Normal file
6
src/NuGet.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<config>
|
||||
<add key="repositoryPath" value="./packages" />
|
||||
</config>
|
||||
</configuration>
|
@ -7,7 +7,7 @@
|
||||
<add key="Orchard.Azure.Media.StorageConnectionString" value="UseDevelopmentStorage=true" />
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
@ -21,15 +21,27 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Iesi.Collections" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.8.4.0" newVersion="5.8.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.8.4.0" newVersion="5.8.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.8.4.0" newVersion="5.8.4.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
@ -10,7 +10,8 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Azure.Tests</RootNamespace>
|
||||
<AssemblyName>Orchard.Azure.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
@ -55,20 +56,23 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=2.0.12.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.12\lib\net45\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Azure.KeyVault.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Edm, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll</HintPath>
|
||||
<Reference Include="Microsoft.Data.Edm, Version=5.8.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.OData, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll</HintPath>
|
||||
<Reference Include="Microsoft.Data.OData, Version=5.8.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Services.Client, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
|
||||
<Reference Include="Microsoft.Data.Services.Client, Version=5.8.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
@ -83,9 +87,8 @@
|
||||
<HintPath>..\packages\Moq.4.2.1510.2205\lib\NET40\Moq.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
|
||||
@ -104,8 +107,8 @@
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Spatial, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll</HintPath>
|
||||
<Reference Include="System.Spatial, Version=5.8.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
@ -128,7 +131,9 @@
|
||||
<None Include="App.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
|
@ -1,12 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net452" />
|
||||
<package id="Microsoft.Data.Edm" version="5.6.4" targetFramework="net452" />
|
||||
<package id="Microsoft.Data.OData" version="5.6.4" targetFramework="net452" />
|
||||
<package id="Microsoft.Data.Services.Client" version="5.6.4" targetFramework="net452" />
|
||||
<package id="Moq" version="4.2.1510.2205" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net452" />
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net452" />
|
||||
<package id="System.Spatial" version="5.6.4" targetFramework="net452" />
|
||||
<package id="WindowsAzure.Storage" version="5.0.2" targetFramework="net452" />
|
||||
<package id="log4net" version="2.0.12" targetFramework="net48" />
|
||||
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Data.Edm" version="5.8.4" targetFramework="net48" />
|
||||
<package id="Microsoft.Data.OData" version="5.8.4" targetFramework="net48" />
|
||||
<package id="Microsoft.Data.Services.Client" version="5.8.4" targetFramework="net48" />
|
||||
<package id="Moq" version="4.2.1510.2205" targetFramework="net48" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net48" />
|
||||
<package id="System.Spatial" version="5.8.4" targetFramework="net48" />
|
||||
<package id="WindowsAzure.Storage" version="5.0.2" targetFramework="net48" />
|
||||
</packages>
|
@ -4,11 +4,11 @@
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Iesi.Collections" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
|
||||
@ -16,8 +16,16 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -177,7 +177,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
contentManager.UpdateEditor(item.ContentItem, updateModel.Object);
|
||||
}
|
||||
|
||||
class UpdatModelStub : IUpdateModel {
|
||||
class UpdateModelStub : IUpdateModel {
|
||||
|
||||
ModelStateDictionary _modelState = new ModelStateDictionary();
|
||||
|
||||
@ -215,11 +215,11 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
|
||||
var user = contentManager.New<IUser>("User");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
_authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true);
|
||||
_authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true);
|
||||
|
||||
item.Owner = user;
|
||||
|
||||
var updater = new UpdatModelStub() { Owner = null };
|
||||
var updater = new UpdateModelStub() { Owner = null };
|
||||
|
||||
contentManager.UpdateEditor(item.ContentItem, updater);
|
||||
}
|
||||
@ -232,11 +232,11 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
|
||||
var user = contentManager.New<IUser>("User");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
_authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true);
|
||||
_authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true);
|
||||
|
||||
item.Owner = user;
|
||||
|
||||
var updater = new UpdatModelStub() { Owner = "" };
|
||||
var updater = new UpdateModelStub() { Owner = "" };
|
||||
|
||||
_container.Resolve<DefaultShapeTableManagerTests.TestShapeProvider>().Discover =
|
||||
b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature())
|
||||
@ -255,11 +255,11 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
|
||||
var user = contentManager.New<IUser>("User");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
_authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true);
|
||||
_authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true);
|
||||
|
||||
item.Owner = user;
|
||||
|
||||
var updater = new UpdatModelStub() { Owner = "" };
|
||||
var updater = new UpdateModelStub() { Owner = "" };
|
||||
|
||||
_container.Resolve<DefaultShapeTableManagerTests.TestShapeProvider>().Discover =
|
||||
b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature())
|
||||
@ -384,7 +384,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
_clock.Advance(TimeSpan.FromMinutes(1));
|
||||
var editUtc = _clock.UtcNow;
|
||||
|
||||
var updater = new UpdatModelStub() { Owner = "" };
|
||||
var updater = new UpdateModelStub() { Owner = "" };
|
||||
contentManager.UpdateEditor(item.ContentItem, updater);
|
||||
|
||||
Assert.That(item.CreatedUtc, Is.EqualTo(createUtc));
|
||||
|
@ -20,6 +20,7 @@ using Orchard.Core.Feeds.StandardBuilders;
|
||||
using Orchard.Tests.Modules;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.Core.Title.Models;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Core.Tests.Feeds.Controllers {
|
||||
[TestFixture]
|
||||
@ -177,6 +178,7 @@ namespace Orchard.Core.Tests.Feeds.Controllers {
|
||||
builder.RegisterInstance(mockContentManager.Object).As<IContentManager>();
|
||||
builder.RegisterType<RssFeedBuilder>().As<IFeedBuilderProvider>();
|
||||
builder.RegisterType<CorePartsFeedItemBuilder>().As<IFeedItemBuilder>();
|
||||
builder.RegisterType<HtmlFilterProcessor>().As<IHtmlFilterProcessor>();
|
||||
builder.RegisterInstance(query).As<IFeedQueryProvider>();
|
||||
var container = builder.Build();
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Core.Tests</RootNamespace>
|
||||
<AssemblyName>Orchard.Core.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
@ -57,43 +58,45 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Autofac, Version=3.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FluentNHibernate, Version=1.4.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FluentNHibernate.1.4.0.0\lib\net35\FluentNHibernate.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="FluentNHibernate, Version=3.1.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FluentNHibernate.3.1.0\lib\net461\FluentNHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Iesi.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.2.1510.2205, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.2.1510.2205\lib\NET40\Moq.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NHibernate, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="NHibernate, Version=5.3.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.mocks, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="pnunit.framework, Version=1.0.4109.34242, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Remotion.Linq.EagerFetching, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
@ -102,36 +105,32 @@
|
||||
<HintPath>..\..\lib\sqlce\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Routing">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
|
@ -30,5 +30,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.10.1")]
|
||||
[assembly: AssemblyFileVersion("1.10.1")]
|
||||
[assembly: AssemblyVersion("1.10.3")]
|
||||
[assembly: AssemblyFileVersion("1.10.3")]
|
||||
|
@ -1,13 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="3.5.2" targetFramework="net452" />
|
||||
<package id="FluentNHibernate" version="1.4.0.0" targetFramework="net452" />
|
||||
<package id="Iesi.Collections" version="4.0.1.4000" targetFramework="net452" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net452" />
|
||||
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net452" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net452" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net452" />
|
||||
<package id="Moq" version="4.2.1510.2205" targetFramework="net452" />
|
||||
<package id="NHibernate" version="4.0.1.4000" targetFramework="net452" />
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net452" />
|
||||
<package id="Antlr3.Runtime" version="3.5.1" targetFramework="net48" />
|
||||
<package id="Autofac" version="3.5.2" targetFramework="net48" />
|
||||
<package id="FluentNHibernate" version="3.1.0" targetFramework="net48" />
|
||||
<package id="Iesi.Collections" version="4.0.4" targetFramework="net48" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net48" />
|
||||
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net48" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net48" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net48" />
|
||||
<package id="Moq" version="4.2.1510.2205" targetFramework="net48" />
|
||||
<package id="NHibernate" version="5.3.10" targetFramework="net48" />
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net48" />
|
||||
<package id="Remotion.Linq" version="2.2.0" targetFramework="net48" />
|
||||
<package id="Remotion.Linq.EagerFetching" version="2.2.0" targetFramework="net48" />
|
||||
</packages>
|
@ -6,4 +6,4 @@
|
||||
<specFlow>
|
||||
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
|
||||
</specFlow>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -10,7 +10,8 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Profile</RootNamespace>
|
||||
<AssemblyName>Orchard.Profile</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
@ -58,15 +59,12 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.mocks, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="pnunit.framework, Version=1.0.4109.34242, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
@ -83,7 +81,6 @@
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="TechTalk.SpecFlow, Version=1.9.0.77, Culture=neutral, PublicKeyToken=0778194805d6db41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SpecFlow.1.9.0\lib\net35\TechTalk.SpecFlow.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -144,4 +141,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -30,5 +30,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.10.1")]
|
||||
[assembly: AssemblyFileVersion("1.10.1")]
|
||||
[assembly: AssemblyVersion("1.10.3")]
|
||||
[assembly: AssemblyFileVersion("1.10.3")]
|
||||
|
6
src/Orchard.Profile/Tests/Profiling.feature.cs
generated
6
src/Orchard.Profile/Tests/Profiling.feature.cs
generated
@ -1,9 +1,9 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.9.0.0
|
||||
// SpecFlow Version:1.9.0.77
|
||||
// SpecFlow Generator Version:1.9.0.0
|
||||
// Runtime Version:4.0.30319.34014
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@ -16,7 +16,7 @@ namespace Orchard.Profile.Tests
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.0")]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.77")]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[NUnit.Framework.TestFixtureAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Profiling")]
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net452" />
|
||||
<package id="SpecFlow" version="1.9.0" targetFramework="net452" />
|
||||
</packages>
|
||||
<package id="NUnit" version="2.5.10.11092" targetFramework="net48" />
|
||||
<package id="SpecFlow" version="1.9.0" targetFramework="net48" />
|
||||
</packages>
|
||||
|
@ -1 +1 @@
|
||||
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.Resources,Orchard.Lists,Orchard.MediaLibrary,Orchard.ContentPicker,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute
|
||||
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.Resources,Orchard.Lists,Orchard.MediaLibrary,Orchard.ContentPicker,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute
|
2
src/Orchard.Specs/Admin.feature.cs
generated
2
src/Orchard.Specs/Admin.feature.cs
generated
@ -3,7 +3,7 @@
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.9.0.77
|
||||
// SpecFlow Generator Version:1.9.0.0
|
||||
// Runtime Version:4.0.30319.34014
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
@ -3,21 +3,20 @@
|
||||
<configSections>
|
||||
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
|
||||
</configSections>
|
||||
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
<specFlow>
|
||||
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
|
||||
</specFlow>
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Iesi.Collections" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
|
||||
@ -25,8 +24,26 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.2.0" newVersion="4.2.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
<specFlow>
|
||||
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
|
||||
</specFlow></configuration>
|
||||
|
@ -9,7 +9,7 @@ Scenario: I can create and publish a new Page with international characters in i
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | Χελλο |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "Χελλο"
|
||||
Then I should see "<h1[^>]*>.*?Χελλο.*?</h1>"
|
||||
|
||||
@ -20,7 +20,7 @@ Scenario: I can create and publish a new Home Page
|
||||
| name | value |
|
||||
| Title.Title | Foo |
|
||||
| AutoroutePart.PromoteToHomePage | True |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "/"
|
||||
Then I should see "<h1[^>]*>.*?Foo.*?</h1>"
|
||||
When I go to "/welcome-to-orchard"
|
||||
|
4
src/Orchard.Specs/Autoroute.feature.cs
generated
4
src/Orchard.Specs/Autoroute.feature.cs
generated
@ -86,7 +86,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 9
|
||||
testRunner.And("I fill in", ((string)(null)), table1, "And ");
|
||||
#line 12
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 13
|
||||
testRunner.And("I go to \"Χελλο\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 14
|
||||
@ -119,7 +119,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 19
|
||||
testRunner.And("I fill in", ((string)(null)), table2, "And ");
|
||||
#line 23
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 24
|
||||
testRunner.And("I go to \"/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 25
|
||||
|
@ -4,8 +4,6 @@ using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Contents;
|
||||
using Orchard.Data;
|
||||
using Orchard.Roles.Models;
|
||||
using Orchard.Roles.Services;
|
||||
using Orchard.Security;
|
||||
using Orchard.Security.Permissions;
|
||||
using Orchard.Specs.Hosting.Orchard.Web;
|
||||
|
@ -11,6 +11,22 @@ using TechTalk.SpecFlow;
|
||||
namespace Orchard.Specs.Bindings {
|
||||
[Binding]
|
||||
public class OrchardSiteFactory : BindingBase {
|
||||
[Given(@"I have a clean site with standard extensions")]
|
||||
public void GivenIHaveACleanSiteWithStandardExtensions() {
|
||||
GivenIHaveACleanSiteWithStandardExtensions("/");
|
||||
}
|
||||
|
||||
[Given(@"I have a clean site with standard extensions at ""(.*)\""")]
|
||||
public void GivenIHaveACleanSiteWithStandardExtensions(string virtualDirectory) {
|
||||
Binding<WebAppHosting>().GivenIHaveACleanSiteWith(
|
||||
virtualDirectory,
|
||||
// This is the list of extensions which will be copied over into the temporary Orchard folder.
|
||||
TableData(
|
||||
new { extension = "Module", names = "Lucene, Markdown, Orchard.Alias, Orchard.AntiSpam, Orchard.ArchiveLater, Orchard.Autoroute, Orchard.Azure, Orchard.Blogs, Orchard.Caching, Orchard.CodeGeneration, Orchard.Comments, Orchard.ContentPermissions, Orchard.ContentPicker, Orchard.ContentTypes, Orchard.DesignerTools, Orchard.Email, Orchard.Fields, Orchard.Forms, Orchard.ImageEditor, Orchard.ImportExport, Orchard.Indexing, Orchard.JobsQueue, Orchard.Resources, Orchard.Layouts, Orchard.Lists, Orchard.Localization, Orchard.MediaLibrary, Orchard.MediaProcessing, Orchard.Migrations, Orchard.Modules, Orchard.MultiTenancy, Orchard.OutputCache, Orchard.Packaging, Orchard.Pages, Orchard.Projections, Orchard.PublishLater, Orchard.Recipes, Orchard.Roles, Orchard.Scripting, Orchard.Scripting.CSharp, Orchard.Scripting.Dlr, Orchard.Search, Orchard.SecureSocketsLayer, Orchard.Setup, Orchard.Tags, Orchard.Taxonomies, Orchard.Templates, Orchard.Themes, Orchard.Tokens, Orchard.Users, Orchard.Warmup, Orchard.Widgets, Orchard.Workflows, Orchard.Conditions, SysCache, TinyMce, Upgrade" },
|
||||
new { extension = "Core", names = "Common, Containers, Contents, Dashboard, Feeds, Navigation, Scheduling, Settings, Shapes, Title, XmlRpc" },
|
||||
new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" }));
|
||||
}
|
||||
|
||||
[Given(@"I have installed Orchard")]
|
||||
public void GivenIHaveInstalledOrchard() {
|
||||
GivenIHaveInstalledOrchard("/");
|
||||
@ -20,13 +36,7 @@ namespace Orchard.Specs.Bindings {
|
||||
public void GivenIHaveInstalledOrchard(string virtualDirectory) {
|
||||
var webApp = Binding<WebAppHosting>();
|
||||
|
||||
// this is the list of module which will be copied over into the temporary Orchard folder
|
||||
webApp.GivenIHaveACleanSiteWith(
|
||||
virtualDirectory,
|
||||
TableData(
|
||||
new { extension = "Module", names = "Lucene, Markdown, Orchard.Alias, Orchard.AntiSpam, Orchard.ArchiveLater, Orchard.Autoroute, Orchard.Azure, Orchard.Blogs, Orchard.Caching, Orchard.CodeGeneration, Orchard.Comments, Orchard.ContentPermissions, Orchard.ContentPicker, Orchard.ContentTypes, Orchard.DesignerTools, Orchard.Email, Orchard.Fields, Orchard.Forms, Orchard.ImageEditor, Orchard.ImportExport, Orchard.Indexing, Orchard.JobsQueue, Orchard.Resources, Orchard.Layouts, Orchard.Lists, Orchard.Localization, Orchard.MediaLibrary, Orchard.MediaProcessing, Orchard.Migrations, Orchard.Modules, Orchard.MultiTenancy, Orchard.OutputCache, Orchard.Packaging, Orchard.Pages, Orchard.Projections, Orchard.PublishLater, Orchard.Recipes, Orchard.Roles, Orchard.Scripting, Orchard.Scripting.CSharp, Orchard.Scripting.Dlr, Orchard.Search, Orchard.SecureSocketsLayer, Orchard.Setup, Orchard.Tags, Orchard.Taxonomies, Orchard.Templates, Orchard.Themes, Orchard.Tokens, Orchard.Users, Orchard.Warmup, Orchard.Widgets, Orchard.Workflows, Orchard.Conditions, SysCache, TinyMce, Upgrade" },
|
||||
new { extension = "Core", names = "Common, Containers, Contents, Dashboard, Feeds, Navigation, Scheduling, Settings, Shapes, Title, XmlRpc" },
|
||||
new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" }));
|
||||
GivenIHaveACleanSiteWithStandardExtensions(virtualDirectory);
|
||||
|
||||
webApp.WhenIGoTo("Setup");
|
||||
|
||||
|
@ -1,17 +1,7 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Contents;
|
||||
using Orchard.Data;
|
||||
using Orchard.Roles.Models;
|
||||
using Orchard.Roles.Services;
|
||||
using Orchard.Security;
|
||||
using Orchard.Security.Permissions;
|
||||
using System.Linq;
|
||||
using Orchard.Localization.Services;
|
||||
using Orchard.Specs.Hosting.Orchard.Web;
|
||||
using TechTalk.SpecFlow;
|
||||
using Orchard.Localization.Services;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.Specs.Bindings {
|
||||
[Binding]
|
||||
@ -22,7 +12,7 @@ namespace Orchard.Specs.Bindings {
|
||||
|
||||
var webApp = Binding<WebAppHosting>();
|
||||
webApp.Host.Execute(() => {
|
||||
using ( var environment = MvcApplication.CreateStandaloneEnvironment("Default") ) {
|
||||
using (var environment = MvcApplication.CreateStandaloneEnvironment("Default")) {
|
||||
var orchardServices = environment.Resolve<IOrchardServices>();
|
||||
var cultureManager = environment.Resolve<ICultureManager>();
|
||||
|
||||
@ -32,6 +22,11 @@ namespace Orchard.Specs.Bindings {
|
||||
}
|
||||
|
||||
orchardServices.WorkContext.CurrentSite.SiteCulture = cultureName;
|
||||
|
||||
// Restarting the shell to reset the cache, because the cache entry storing the list of available
|
||||
// cultures isn't invalidated by the signal in DefaultCultureManager.ListCultures when running
|
||||
// inside the test webhost.
|
||||
MvcApplication.RestartTenant("Default");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace Orchard.Specs.Bindings {
|
||||
var memberShipService = environment.Resolve<IMembershipService>();
|
||||
var roleService = environment.Resolve<IRoleService>();
|
||||
var userRoleRepository = environment.Resolve<IRepository<UserRolesPartRecord>>();
|
||||
var user = memberShipService.CreateUser(new CreateUserParams(username, "qwerty123!", username + "@foo.com", "", "", true));
|
||||
var user = memberShipService.CreateUser(new CreateUserParams(username, "qwerty123!", username + "@foo.com", "", "", true, false));
|
||||
|
||||
foreach (var roleName in roles.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)) {
|
||||
var role = roleService.GetRoleByName(roleName);
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Castle.Core.Logging;
|
||||
using HtmlAgilityPack;
|
||||
@ -318,6 +319,10 @@ namespace Orchard.Specs.Bindings {
|
||||
?? _doc.DocumentNode
|
||||
.SelectSingleNode(string.Format("//a[@title='{0}']", submitText));
|
||||
|
||||
if (submit == null) {
|
||||
throw new ArgumentException("Text not found: " + submitText);
|
||||
}
|
||||
|
||||
urlPath = HttpUtility.HtmlDecode(submit.Attributes["href"].Value);
|
||||
}
|
||||
|
||||
@ -364,6 +369,11 @@ namespace Orchard.Specs.Bindings {
|
||||
}
|
||||
}
|
||||
|
||||
[When(@"I wait ""(.*)""")]
|
||||
public void WhenIWait(int waitMilliseconds) {
|
||||
Thread.Sleep(waitMilliseconds);
|
||||
}
|
||||
|
||||
[Then(@"the status should be (.*) ""(.*)""")]
|
||||
public void ThenTheStatusShouldBe(int statusCode, string statusDescription) {
|
||||
Assert.That(Details.StatusCode, Is.EqualTo(statusCode));
|
||||
|
@ -7,14 +7,14 @@ Scenario: In the admin (menu) there is a link to create a Blog
|
||||
Given I have installed Orchard
|
||||
When I go to "admin"
|
||||
Then I should see "<a[^>]*href="/Admin/Blogs/Create"[^>]*>Blog</a>"
|
||||
|
||||
|
||||
Scenario: I can create a new blog and blog post
|
||||
Given I have installed Orchard
|
||||
When I go to "admin/blogs/create"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -22,7 +22,7 @@ Scenario: I can create a new blog and blog post
|
||||
| name | value |
|
||||
| Title.Title | My Post |
|
||||
| Body.Text | Hi there. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
Then I should see "Your Blog Post has been created."
|
||||
When I go to "my-blog"
|
||||
@ -38,7 +38,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -46,7 +46,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti
|
||||
| name | value |
|
||||
| Title.Title | My Post |
|
||||
| Body.Text | Hi there. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "my-blog/my-post"
|
||||
Then I should see "<h1[^>]*>.*?My Post.*?</h1>"
|
||||
And I should see "Hi there."
|
||||
@ -57,7 +57,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti
|
||||
| name | value |
|
||||
| Title.Title | My Post |
|
||||
| Body.Text | Hi there, again. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "my-blog/my-post-2"
|
||||
Then I should see "<h1[^>]*>.*?My Post.*?</h1>"
|
||||
And I should see "Hi there, again."
|
||||
@ -69,7 +69,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti
|
||||
| Title.Title | My Post |
|
||||
| AutoroutePart.CurrentUrl | my-blog/my-post |
|
||||
| Body.Text | Are you still there? |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "my-blog/my-post-3"
|
||||
Then I should see "<h1[^>]*>.*?My Post.*?</h1>"
|
||||
And I should see "Are you still there?"
|
||||
@ -80,7 +80,7 @@ Scenario: When viewing a blog the user agent is given an RSS feed of the blog's
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -88,11 +88,11 @@ Scenario: When viewing a blog the user agent is given an RSS feed of the blog's
|
||||
| name | value |
|
||||
| Title.Title | My Post |
|
||||
| Body.Text | Hi there. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "my-blog/my-post"
|
||||
Then I should see "<link rel="alternate" type="application/rss\+xml" title="My Blog" href="/rss\?containerid=\d+" />"
|
||||
|
||||
|
||||
Scenario: Enabling remote blog publishing inserts the appropriate metaweblogapi markup into the blog's page
|
||||
Given I have installed Orchard
|
||||
And I have enabled "XmlRpc"
|
||||
@ -101,7 +101,7 @@ Scenario: Enabling remote blog publishing inserts the appropriate metaweblogapi
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "my-blog"
|
||||
Then I should see "<link href="[^"]*/XmlRpc/LiveWriter/Manifest" rel="wlwmanifest" type="application/wlwmanifest\+xml" />"
|
||||
When I go to "/XmlRpc/LiveWriter/Manifest"
|
||||
@ -116,7 +116,7 @@ Scenario: The virtual path of my installation when not at the root is reflected
|
||||
When I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -129,7 +129,7 @@ Scenario: The virtual path of my installation when at the root is reflected in t
|
||||
When I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -142,7 +142,7 @@ Scenario: I set my blog to be the content for the home page and the posts for th
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
| AutoroutePart.PromoteToHomePage | true |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -150,7 +150,7 @@ Scenario: I set my blog to be the content for the home page and the posts for th
|
||||
| name | value |
|
||||
| Title.Title | My Post |
|
||||
| Body.Text | Hi there. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "/"
|
||||
Then I should see "<h1>My Blog</h1>"
|
||||
@ -167,114 +167,126 @@ Scenario: I can create browse blog posts on several pages
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 1 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 2 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 3 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 4 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 5 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 6 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 7 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 8 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 9 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 10 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 11 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
And I wait "1000"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Post 12 |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I am redirected
|
||||
Then I should see "Your Blog Post has been created."
|
||||
When I go to "my-blog"
|
||||
Then I should see "<h1[^>]*>.*?My Blog.*?</h1>"
|
||||
And I should see "<h1[^>]*>.*?My Post 12.*?</h1>"
|
||||
And I should see "<h1[^>]*>.*?My Post 11.*?</h1>"
|
||||
And I should not see "<h1[^>]*>.*?My Post 10.*?</h1>"
|
||||
And I should not see "My Post 2"
|
||||
When I go to "my-blog?page=2"
|
||||
Then I should see "<h1[^>]*>.*?My Blog.*?</h1>"
|
||||
And I should see "<h1[^>]*>.*?My Post 1.*?</h1>"
|
||||
And I should see "<h1[^>]*>.*?My Post 2.*?</h1>"
|
||||
And I should not see "<h1[^>]*>.*?My Post 3.*?</h1>"
|
||||
And I should not see "My Post 3"
|
||||
|
||||
Scenario: I can create a new blog with a percent sign in the title and it gets stripped out of the slug
|
||||
Given I have installed Orchard
|
||||
@ -282,7 +294,7 @@ Scenario: I can create a new blog with a percent sign in the title and it gets s
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | My Blog |
|
||||
And I hit "Save"
|
||||
And I hit "Publish"
|
||||
And I go to "admin/blogs"
|
||||
And I follow "My Blog"
|
||||
And I follow "New Post" where class name has "primaryAction"
|
||||
@ -290,7 +302,7 @@ Scenario: I can create a new blog with a percent sign in the title and it gets s
|
||||
| name | value |
|
||||
| Title.Title | My Post with a % Sign |
|
||||
| Body.Text | Hi there. |
|
||||
And I hit "Publish Now"
|
||||
And I hit "Publish"
|
||||
And I go to "my-blog/my-post-with-a-sign"
|
||||
Then I should see "<h1[^>]*>.*?My Post with a % Sign.*?</h1>"
|
||||
And I should see "Hi there."
|
318
src/Orchard.Specs/Blogs.feature.cs
generated
318
src/Orchard.Specs/Blogs.feature.cs
generated
@ -103,7 +103,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 14
|
||||
testRunner.And("I fill in", ((string)(null)), table1, "And ");
|
||||
#line 17
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 18
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 19
|
||||
@ -123,7 +123,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 21
|
||||
testRunner.And("I fill in", ((string)(null)), table2, "And ");
|
||||
#line 25
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 26
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 27
|
||||
@ -167,7 +167,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 38
|
||||
testRunner.And("I fill in", ((string)(null)), table3, "And ");
|
||||
#line 41
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 42
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 43
|
||||
@ -187,7 +187,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 45
|
||||
testRunner.And("I fill in", ((string)(null)), table4, "And ");
|
||||
#line 49
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 50
|
||||
testRunner.And("I go to \"my-blog/my-post\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 51
|
||||
@ -213,7 +213,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 56
|
||||
testRunner.And("I fill in", ((string)(null)), table5, "And ");
|
||||
#line 60
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 61
|
||||
testRunner.And("I go to \"my-blog/my-post-2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 62
|
||||
@ -242,7 +242,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 67
|
||||
testRunner.And("I fill in", ((string)(null)), table6, "And ");
|
||||
#line 72
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 73
|
||||
testRunner.And("I go to \"my-blog/my-post-3\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 74
|
||||
@ -274,7 +274,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 80
|
||||
testRunner.And("I fill in", ((string)(null)), table7, "And ");
|
||||
#line 83
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 84
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 85
|
||||
@ -294,7 +294,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 87
|
||||
testRunner.And("I fill in", ((string)(null)), table8, "And ");
|
||||
#line 91
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 92
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 93
|
||||
@ -333,7 +333,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 101
|
||||
testRunner.And("I fill in", ((string)(null)), table9, "And ");
|
||||
#line 104
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 105
|
||||
testRunner.And("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 106
|
||||
@ -377,7 +377,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 116
|
||||
testRunner.When("I fill in", ((string)(null)), table10, "When ");
|
||||
#line 119
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 120
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 121
|
||||
@ -415,7 +415,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 129
|
||||
testRunner.When("I fill in", ((string)(null)), table11, "When ");
|
||||
#line 132
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 133
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 134
|
||||
@ -454,7 +454,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 141
|
||||
testRunner.And("I fill in", ((string)(null)), table12, "And ");
|
||||
#line 145
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 146
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 147
|
||||
@ -474,7 +474,7 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 149
|
||||
testRunner.And("I fill in", ((string)(null)), table13, "And ");
|
||||
#line 153
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 154
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 155
|
||||
@ -518,13 +518,15 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 167
|
||||
testRunner.And("I fill in", ((string)(null)), table14, "And ");
|
||||
#line 170
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 171
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 172
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 173
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 174
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -532,18 +534,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table15.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 1"});
|
||||
#line 174
|
||||
#line 175
|
||||
testRunner.And("I fill in", ((string)(null)), table15, "And ");
|
||||
#line 177
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 178
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 179
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 180
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 181
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 182
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 183
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -551,18 +555,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table16.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 2"});
|
||||
#line 182
|
||||
#line 184
|
||||
testRunner.And("I fill in", ((string)(null)), table16, "And ");
|
||||
#line 185
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 186
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 187
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 188
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 189
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 190
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 191
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 192
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -570,18 +576,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table17.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 3"});
|
||||
#line 190
|
||||
testRunner.And("I fill in", ((string)(null)), table17, "And ");
|
||||
#line 193
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 194
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 195
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I fill in", ((string)(null)), table17, "And ");
|
||||
#line 196
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 197
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 198
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 199
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 200
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 201
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -589,18 +597,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table18.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 4"});
|
||||
#line 198
|
||||
testRunner.And("I fill in", ((string)(null)), table18, "And ");
|
||||
#line 201
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 202
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 203
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 204
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I fill in", ((string)(null)), table18, "And ");
|
||||
#line 205
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 206
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 207
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 208
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 209
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 210
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -608,18 +618,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table19.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 5"});
|
||||
#line 206
|
||||
testRunner.And("I fill in", ((string)(null)), table19, "And ");
|
||||
#line 209
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 210
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 211
|
||||
testRunner.And("I fill in", ((string)(null)), table19, "And ");
|
||||
#line 214
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 215
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 216
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 212
|
||||
#line 217
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 213
|
||||
#line 218
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 219
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -627,18 +639,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table20.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 6"});
|
||||
#line 214
|
||||
testRunner.And("I fill in", ((string)(null)), table20, "And ");
|
||||
#line 217
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 218
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 219
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 220
|
||||
testRunner.And("I fill in", ((string)(null)), table20, "And ");
|
||||
#line 223
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 224
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 225
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 226
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 221
|
||||
#line 227
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 228
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table21 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -646,18 +660,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table21.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 7"});
|
||||
#line 222
|
||||
testRunner.And("I fill in", ((string)(null)), table21, "And ");
|
||||
#line 225
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 226
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 227
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 228
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 229
|
||||
testRunner.And("I fill in", ((string)(null)), table21, "And ");
|
||||
#line 232
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 233
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 234
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 235
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 236
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 237
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table22 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -665,29 +681,10 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table22.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 8"});
|
||||
#line 230
|
||||
testRunner.And("I fill in", ((string)(null)), table22, "And ");
|
||||
#line 233
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 234
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 235
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 236
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 237
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
"value"});
|
||||
table23.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 9"});
|
||||
#line 238
|
||||
testRunner.And("I fill in", ((string)(null)), table23, "And ");
|
||||
testRunner.And("I fill in", ((string)(null)), table22, "And ");
|
||||
#line 241
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 242
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 243
|
||||
@ -696,6 +693,29 @@ this.ScenarioSetup(scenarioInfo);
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 245
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 246
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
"value"});
|
||||
table23.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 9"});
|
||||
#line 247
|
||||
testRunner.And("I fill in", ((string)(null)), table23, "And ");
|
||||
#line 250
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 251
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 252
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 253
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 254
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 255
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table24 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -703,18 +723,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table24.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 10"});
|
||||
#line 246
|
||||
#line 256
|
||||
testRunner.And("I fill in", ((string)(null)), table24, "And ");
|
||||
#line 249
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 250
|
||||
#line 259
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 260
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 251
|
||||
#line 261
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 252
|
||||
#line 262
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 253
|
||||
#line 263
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 264
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table25 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -722,18 +744,20 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table25.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 11"});
|
||||
#line 254
|
||||
#line 265
|
||||
testRunner.And("I fill in", ((string)(null)), table25, "And ");
|
||||
#line 257
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 258
|
||||
#line 268
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 269
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 259
|
||||
#line 270
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 260
|
||||
#line 271
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 261
|
||||
#line 272
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 273
|
||||
testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table26 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@ -741,34 +765,34 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table26.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Post 12"});
|
||||
#line 262
|
||||
testRunner.And("I fill in", ((string)(null)), table26, "And ");
|
||||
#line 265
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 266
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 267
|
||||
testRunner.Then("I should see \"Your Blog Post has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 268
|
||||
testRunner.When("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 269
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?My Blog.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 270
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 12.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 271
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 11.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 272
|
||||
testRunner.And("I should not see \"<h1[^>]*>.*?My Post 10.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 273
|
||||
testRunner.When("I go to \"my-blog?page=2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 274
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?My Blog.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 275
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 1.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 276
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 2.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I fill in", ((string)(null)), table26, "And ");
|
||||
#line 277
|
||||
testRunner.And("I should not see \"<h1[^>]*>.*?My Post 3.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 278
|
||||
testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 279
|
||||
testRunner.Then("I should see \"Your Blog Post has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 280
|
||||
testRunner.When("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 281
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?My Blog.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 282
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 12.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 283
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 11.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 284
|
||||
testRunner.And("I should not see \"My Post 2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 285
|
||||
testRunner.When("I go to \"my-blog?page=2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 286
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?My Blog.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 287
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 1.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 288
|
||||
testRunner.And("I should see \"<h1[^>]*>.*?My Post 2.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 289
|
||||
testRunner.And("I should not see \"My Post 3\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
@ -780,11 +804,11 @@ this.ScenarioSetup(scenarioInfo);
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create a new blog with a percent sign in the title and it gets stripped out" +
|
||||
" of the slug", ((string[])(null)));
|
||||
#line 279
|
||||
#line 291
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 280
|
||||
#line 292
|
||||
testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 281
|
||||
#line 293
|
||||
testRunner.When("I go to \"admin/blogs/create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table27 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
@ -793,15 +817,15 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table27.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"My Blog"});
|
||||
#line 282
|
||||
#line 294
|
||||
testRunner.And("I fill in", ((string)(null)), table27, "And ");
|
||||
#line 285
|
||||
testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 286
|
||||
#line 297
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 298
|
||||
testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 287
|
||||
#line 299
|
||||
testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 288
|
||||
#line 300
|
||||
testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
@ -813,15 +837,15 @@ this.ScenarioSetup(scenarioInfo);
|
||||
table28.AddRow(new string[] {
|
||||
"Body.Text",
|
||||
"Hi there."});
|
||||
#line 289
|
||||
#line 301
|
||||
testRunner.And("I fill in", ((string)(null)), table28, "And ");
|
||||
#line 293
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 294
|
||||
#line 305
|
||||
testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 306
|
||||
testRunner.And("I go to \"my-blog/my-post-with-a-sign\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 295
|
||||
#line 307
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?My Post with a % Sign.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 296
|
||||
#line 308
|
||||
testRunner.And("I should see \"Hi there.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user