Метод поиска CFQL с использованием выражения ИЛИ среди нескольких свойств

Я пытаюсь разработать метод SEARCH CFQL.

У меня есть набор свойств TownId или свойство TownLabel в объекте Address:

  • TownId устанавливается, если адрес был затронут городом из ссылки (города хранятся в другой базе данных и ссылаются только по идентификатору).
  • TownLabel устанавливается, если ни один из известных городов не найден. (например, название города за границей)

В моем методе SEARCH я хочу искать пользователей, имеющих в качестве города либо TownLabel, либо возможные города из ссылочного имени whoes, содержащего значение TownLabel.

Короче говоря, мои методы CFQL следующие:

SEARCH(string[] townIds, string townLabel) WHERE Adresses.TownId IN (@townIds) OR Adresses.TownLabel LIKE '%'+@townLabel+'%'

Несмотря на оператор ИЛИ, сгенерированный SQL появляется с оператором И, как показано ниже.

Мой вопрос: это нормально?

CREATE PROCEDURE [dbo].[User_AdvancedSearch]
(
 @townIds [nvarchar] (max) = NULL,
 @townLabel [nvarchar] (256) = NULL,
 @_orderBy0 [nvarchar] (64) = NULL,
 @_orderByDirection0 [bit] = 0
)
AS
SET NOCOUNT ON
DECLARE @sql nvarchar(max), @paramlist nvarchar(max)

SELECT @sql=
'SELECT DISTINCT [User].[User_UserId], [User].[User_Name], [User].[User_Association_AssociationId], [User].[_trackLastWriteTime], [User].[_trackCreationTime], [User].[_trackLastWriteUser], [User].[_trackCreationUser], [User].[_rowVersion] 
    FROM [User]
        LEFT OUTER JOIN [Address] ON ([User].[User_UserId] = [Address].[Address_User_UserId])
    WHERE ((1 = 1) AND (1 = 1))'
SELECT @paramlist = '@townIds nvarchar (max), 
    @townLabel nvarchar (256), 
    @_orderBy0 nvarchar (64), 
    @_orderByDirection0 bit'
IF @townIds IS NOT NULL
    SELECT @sql = @sql + ' AND ([Address].[Address_TownId] IN ((SELECT [Item] FROM [dbo].cf_SplitString(@townIds, nchar(1)))))'
IF @townLabel IS NOT NULL
    SELECT @sql = @sql + ' AND (([Address].[Address_TownLabel] LIKE ((''%'' + @townLabel) + ''%'')))'
EXEC sp_executesql @sql, @paramlist,
    @townIds, 
    @townLabel, 
    @_orderBy0, 
    @_orderByDirection0

RETURN
GO

Схема приведена ниже

<cf:project defaultNamespace="WcfServices.Model" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" xmlns:cfx="http://www.softfluent.com/codefluent/modeler/2008/1" xmlns:cfps="http://www.softfluent.com/codefluent/producers.sqlserver/2005/1" xmlns:cfom="http://www.softfluent.com/codefluent/producers.model/2005/1" xmlns:cfsps="http://www.softfluent.com/codefluent/producers.sqlpivotscript/2013/1" createDefaultMethodForms="true" createDefaultApplication="false" createDefaultHints="false">
  <cf:import path="Default.Surface.cfp" />
  <cf:entity name="Association" namespace="Example.Model.Association" categoryPath="/WcfServices.Model">
    <cf:property name="AssociationId" key="true" persistenceEnforce="true" />
    <cf:property name="Label" persistenceEnforce="true" />
    <cf:property name="Users" typeName="Example.Model.Association.UserCollection" relationPropertyName="Association" />
  </cf:entity>
  <cf:producer name="SQL Server" typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration produceViews="true" targetDirectory="..\WcfServices.persistence" cfx:targetProject="..\WcfServices.persistence\WcfServices.persistence.sqlproj" cfx:targetProjectLayout="Update, DontRemove" />
  </cf:producer>
  <cf:producer name="Business Object Model (BOM)" typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">
    <cf:configuration compileWithVisualStudio="true" compile="false" codeDomProviderTypeName="CSharp" targetDirectory="..\WcfServices.model" cfx:targetProject="..\WcfServices.model\WcfServices.model.csproj" cfx:targetProjectLayout="Update">
    </cf:configuration>
  </cf:producer>
  <cf:entity name="User" namespace="Example.Model.Association" categoryPath="/WcfServices.Model">
    <cf:property name="UserId" key="true" persistenceEnforce="true" />
    <cf:property name="Name" persistenceEnforce="true" />
    <cf:property name="Association" typeName="Example.Model.Association.Association" relationPropertyName="Users" />
    <cf:property name="Adresses" typeName="Example.Model.Association.AddressCollection" relationPropertyName="User" persistenceEnforce="true" />
    <cf:method name="AdvancedSearch" body="SEARCH(string[] townIds, string townLabel) WHERE Adresses.TownId IN (@townIds) OR Adresses.TownLabel LIKE '%%'+@townLabel+'%%'" />
  </cf:entity>
  <cf:producer name="SQL Server Pivot Script" typeName="CodeFluent.Producers.SqlServer.SqlPivotScriptProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration targetDirectory="..\WcfServices.web" cfx:targetProject="..\WcfServices.web\WcfServices.web.csproj" cfx:targetProjectLayout="Update" />
  </cf:producer>
  <cf:entity name="Address" namespace="Example.Model.Association" categoryPath="/WcfServices.Model">
    <cf:property name="AddressId" key="true" persistenceEnforce="true" />
    <cf:property name="Line" persistenceEnforce="true" />
    <cf:property name="User" typeName="Example.Model.Association.User" relationPropertyName="Adresses" persistenceEnforce="true" />
    <cf:property name="TownLabel" />
    <cf:property name="TownId" typeName="guid" />
  </cf:entity>
</cf:project>

РЕДАКТИРОВАТЬ 15.09.2016 - добавление оригинальной схемы CFQL +.

Оригинальный метод CFQL:

SEARCH (string firstname, string name, int[] groups, string postalCode, string townLabel, string mail, string[] townId, guid structureId, guid countryId) WHERE Firstname LIKE '%'+@firstname+'%' AND Name LIKE '%'+@name+'%' AND (Address.PostalCode LIKE '%'+@postalCode+'%' OR StructureContacts.Address.PostalCode LIKE '%'+@postalCode+'%') AND ( Address.TownLabel LIKE '%'+@townLabel+'%' OR StructureContacts.Address.TownLabel LIKE '%'+@townLabel+'%' OR Address.TownId IN (@townId) OR StructureContacts.Address.TownId IN(@townId)) AND (StructureContacts.Groups.Value IN (@groups) OR Groups.Value IN (@groups)) AND StructureContacts.Structure.StructureId = @structureId and (Address.Email LIKE '%'+@mail+'%' OR StructureContacts.Address.Email LIKE '%'+@mail+'%') AND (Address.CountryId = @countryId OR StructureContacts.Address.CountryId = @countryId) order by Name, Firstname

Схема:

<cf:project defaultNamespace="Example.Models" xmlns:cf="http://www.softfluent.com/codefluent/2005/1">
  <cf:enumeration name="enumStructureType" namespace="Example.Models.Contact.Structure" categoryPath="/RH">
    <cf:enumerationValue name="ENTERPRISE" />
    <cf:enumerationValue name="ASSOCIATION" />
    <cf:enumerationValue name="OTHER_ASSOCIATION" />
    <cf:enumerationValue name="SUPPLIER" />
    <cf:enumerationValue name="PUBLIC_ORGANIZATION" />
  </cf:enumeration>
  <cf:entity name="Structure" defaultUsePersistenceDefaultValue="false" defaultPersistenceEnforce="false" namespace="Example.Models.Contact.Structure" categoryPath="/RH" storeName="ExampleStoreName">
    <cf:property name="StructureId" key="true" />
    <cf:property name="Sigle" />
    <cf:property name="CorporateName" />
    <cf:property name="Code" />
    <cf:property name="Comment">
      <cf:rule typeName="StringValidate" maxLength="2000" />
    </cf:property>
    <cf:property name="Siret" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" collectionKey="false">
      <cf:rule typeName="RegularExpressionValidate" expression="[\d]{14,14}" />
    </cf:property>
    <cf:property name="Type" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" defaultValue="EstablishmentType.PRINCIPAL" typeName="{0}.Contact.Structure.enumStructureType" collectionKey="false" />
    <cf:property name="Groups" set="true" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.GroupCollection" />
    <cf:property name="ApeId" typeName="guid" />
    <cf:property name="Address" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.Address" relationSchema="Contact" />
    <cf:property name="EstablishmentType" typeName="{0}.Contact.Structure.enumEstablishmentType" />
    <cf:property name="ParentStructure" readOnSave="true" typeName="{0}.Contact.Structure.Structure" relationPropertyName="ChildrenStructures" />
    <cf:property name="ChildrenStructures" set="true" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Structure.StructureCollection" relationPropertyName="ParentStructure" />
    <cf:property name="OpeningHours" maxLength="2000" />
    <cf:method name="SimpleSearchStructures" body="SEARCH (string keyword) WHERE CorporateName LIKE '%%'+@keyword+'%%' OR Code LIKE '%%'+@keyword+'%%' OR Comment LIKE '%%'+@keyword+'%%' OR Sigle LIKE '%%'+@keyword+'%%' OR Siret LIKE '%%'+@keyword+'%%' OR Address.Email LIKE '%%'+@keyword+'%%' ORDER BY CorporateName" />
    <cf:method name="AdvancedSearchStructures" body="SEARCH (string corporateName, string email, string postalCode, string townLabel, string[] townIds, int[] groups, guid countryId, int[] types) WHERE CorporateName LIKE '%%'+@corporateName+'%%' AND Address.Email LIKE '%%'+@email+'%%'  AND (Address.TownLabel LIKE '%%'+@townLabel+'%%' OR Address.TownId IN (@townIds)) AND Address.PostalCode LIKE '%%'+@postalCode+'%%' AND Address.CountryId = @countryId AND Groups.Value IN (@groups) AND Type IN (@types) ORDER BY CorporateName" />
    <cf:rule typeName="OnBeforeSave" methodName="BeforeSave" />
    <cf:method name="DeleteById" body="DELETE(guid id) WHERE StructureId = @id" />
  </cf:entity>
  <cf:entity name="StructureAssociation" baseTypeName="Example.Models.Contact.Structure.Structure" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models" storeName="ExampleStoreName">
    <cf:property name="ParutionDateOJ" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" typeName="date" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="BasinId" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" typeName="guid" relationSchema="Contact" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="ReceiptNum" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="PrefectureId" typeName="guid" persistenceEnforce="true" />
    <cf:property name="CreationDate" typeName="date" persistenceEnforce="true" />
    <cf:property name="CartePecheAappmaId" persistenceEnforce="true" />
    <cf:method name="LoadAssociationStructure" body="LOADONE WHERE EstablishmentType = 3" />
  </cf:entity>
  <cf:entity name="StructureContact" defaultUsePersistenceDefaultValue="false" setType="List" namespace="Example.Models.Contact.Structure" categoryPath="/RH" storeName="ExampleStoreName">
    <cf:property name="Function" defaultValue="enumFunctionType.PRESIDENT" typeName="{0}.Contact.Structure.enumFunctionType" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="StartDateFunction" usePersistenceDefaultValue="true" typeName="date" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="EndDateFunction" usePersistenceDefaultValue="true" typeName="date" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="Contact" typeName="{0}.Contact.Contact.Contact" relationPropertyName="StructureContacts" relationSchema="Contact" persistenceEnforce="true" />
    <cf:property name="Address" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.Address" relationSchema="Contact" persistenceEnforce="true" />
    <cf:property name="Groups" set="true" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.GroupCollection" persistenceEnforce="true" />
    <cf:property name="DocumentUrl" typeName="guid" persistenceEnforce="true" />
    <cf:property name="Structure" typeName="{0}.Contact.Structure.Structure" persistenceEnforce="true">
      <cf:attribute name="Newtonsoft.Json.JsonIgnore" class="" />
    </cf:property>
    <cf:property name="StructureContactId" key="true" persistenceEnforce="true" />
    <cf:property name="AdditionalDate" usePersistenceDefaultValue="true" typeName="date" persistenceEnforce="true" />
    <cf:property name="DocumentName" persistenceEnforce="true" />
    <cf:method name="LoadBoardMembers" body="LOAD (int[] functions) WHERE Function IN (@functions)" />
  </cf:entity>
  <cf:entity name="StructureEnterprise" baseTypeName="Example.Models.Contact.Structure.Structure" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models" storeName="ExampleStoreName">
    <cf:property name="VATNum" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" persistenceEnforce="true" collectionKey="false" />
  </cf:entity>
  <cf:entity name="StructureOtherAssociation" baseTypeName="Example.Models.Contact.Structure.Structure" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models" storeName="ExampleStoreName">
    <cf:property name="ReceiptNum" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" persistenceEnforce="true" collectionKey="false" />
    <cf:property name="SkillTerritoryType" typeName="{0}.Contact.Structure.enumStructureSkillTerritoryType" persistenceEnforce="true" />
  </cf:entity>
  <cf:entity name="Address" defaultUsePersistenceDefaultValue="false" namespace="Example.Models.Contact.Contact" categoryPath="/RH" persistenceName="Address" storeName="ExampleStoreName">
    <cf:property name="AddressId" key="true" persistenceEnforce="true" />
    <cf:property name="Line1" persistenceEnforce="true" />
    <cf:property name="Line2" persistenceEnforce="true" />
    <cf:property name="IsActive" typeName="bool" persistenceEnforce="true" />
    <cf:property name="Landline" persistenceEnforce="true" />
    <cf:property name="Email" persistenceEnforce="true">
      <cf:rule typeName="EmailValidate" />
    </cf:property>
    <cf:property name="Fax" persistenceEnforce="true" />
    <cf:property name="Website" persistenceEnforce="true" />
    <cf:property name="Mobile" persistenceEnforce="true" />
    <cf:property name="DirectLine" persistenceEnforce="true" />
    <cf:property name="ProfessionalLine" persistenceEnforce="true" />
    <cf:property name="TownId" typeName="guid" persistenceEnforce="true" />
    <cf:property name="TownLabel" persistenceEnforce="true" />
    <cf:property name="CountryId" typeName="guid" persistenceEnforce="true" />
    <cf:property name="PostalCode" persistenceEnforce="true" />
    <cf:rule typeName="OnBeforeSave" methodName="BeforeSave" />
  </cf:entity>
  <cf:entity name="Contact" defaultUsePersistenceDefaultValue="false" namespace="Example.Models.Contact.Contact" categoryPath="/RH" persistenceName="Contact" storeName="ExampleStoreName">
    <cf:property name="Name" persistenceEnforce="true" />
    <cf:property name="Firstname" persistenceEnforce="true" />
    <cf:property name="Civility" defaultValue="CivilityContact.Mr" typeName="{0}.Global.Civility" persistenceEnforce="true" />
    <cf:property name="DateOfBirth" serializationNullable="true" modelNullable="true" typeName="date" persistenceEnforce="true" />
    <cf:property name="Comment" persistenceEnforce="true">
      <cf:rule typeName="StringValidate" maxLength="2000" />
    </cf:property>
    <cf:property name="ContactId" key="true" persistenceEnforce="true" />
    <cf:property name="StructureContacts" set="true" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Structure.StructureContactCollection" relationPropertyName="Contact" relationSchema="Contact" persistenceEnforce="true" />
    <cf:property name="Address" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.Address" relationSchema="Contact" persistenceEnforce="true" />
    <cf:property name="TownOfBirthLabel" persistenceEnforce="true" />
    <cf:property name="TownIdOfBirth" typeName="guid" persistenceEnforce="true" />
    <cf:property name="CountryIdOfBirth" typeName="guid" persistenceEnforce="true" />
    <cf:property name="DepartmentIdOfBirth" typeName="guid" persistenceEnforce="true" />
    <cf:property name="PostalCode" persistenceEnforce="true" />
    <cf:property name="Groups" set="true" cascadeSave="After" cascadeDelete="Before" typeName="{0}.Contact.Contact.GroupCollection" persistenceEnforce="true" />
    <cf:property name="CartePecheMemberId" persistenceEnforce="true" />
    <cf:method name="AdvancedSearchContactsTownLabel" body="SEARCH (string firstname, string name, int[] groups, string postalCode, string townLabel, string mail, string[] townId, guid structureId, guid countryId) WHERE Firstname LIKE '%%'+@firstname+'%%' AND Name LIKE '%%'+@name+'%%' AND (Address.PostalCode LIKE '%%'+@postalCode+'%%' OR StructureContacts.Address.PostalCode LIKE '%%'+@postalCode+'%%') AND ( Address.TownLabel LIKE '%%'+@townLabel+'%%' OR StructureContacts.Address.TownLabel LIKE '%%'+@townLabel+'%%' OR Address.TownId IN (@townId) OR StructureContacts.Address.TownId IN(@townId)) AND (StructureContacts.Groups.Value IN (@groups) OR Groups.Value IN (@groups)) AND StructureContacts.Structure.StructureId = @structureId and (Address.Email LIKE '%%'+@mail+'%%' OR StructureContacts.Address.Email LIKE '%%'+@mail+'%%') AND (Address.CountryId = @countryId OR StructureContacts.Address.CountryId = @countryId) order by Name, Firstname" />
    <cf:method name="SimpleSearchContacts" body="SEARCH(string keywords) WHERE Firstname LIKE '%%'+@keywords+'%%' OR Name LIKE '%%'+@keywords+'%%' OR Address.Email LIKE '%%'+@keywords+'%%' OR StructureContacts.Address.Email LIKE '%%'+@keywords+'%%' order by Name, Firstname" />
    <cf:rule typeName="OnBeforeSave" methodName="BeforeSave" />
    <cf:method name="SearchContactByName" body="SEARCH(string nameOrFirstName, int[] functions) WHERE (Name LIKE '%%'+@nameOrFirstName+'%%' OR Firstname LIKE '%%'+@nameOrFirstName+'%%') AND StructureContacts.Function IN (@functions)" />
    <cf:method name="LoadContactsByDateFunction" body="LOAD (date currentDate, int[] functions) WHERE StructureContacts.Function IN (@functions) AND ( StructureContacts.StartDateFunction &lt;= @currentDate OR NOT StructureContacts.StartDateFunction EXISTS )&#xD;&#xA; AND ( StructureContacts.EndDateFunction &gt; @currentDate OR NOT StructureContacts.EndDateFunction EXISTS )" />
    <cf:method name="DeleteById" body="DELETE(guid id) WHERE ContactId = @id" />
    <cf:method name="AdvancedSearchContactTownId" body="SEARCH (string firstname, string name, int[] groups, string postalCode, string townLabel, string mail, string[] townId, guid structureId, guid countryId) WHERE Firstname LIKE '%%'+@firstname+'%%' AND Name LIKE '%%'+@name+'%%' AND (Address.PostalCode LIKE '%%'+@postalCode+'%%' OR StructureContacts.Address.PostalCode LIKE '%%'+@postalCode+'%%')  AND (Address.TownId IN (@townId) OR StructureContacts.Address.TownId IN(@townId) ) AND (StructureContacts.Groups.Value IN (@groups) OR Groups.Value IN (@groups)) AND StructureContacts.Structure.StructureId = @structureId and (Address.Email LIKE '%%'+@mail+'%%' OR StructureContacts.Address.Email LIKE '%%'+@mail+'%%') AND (Address.CountryId = @countryId OR StructureContacts.Address.CountryId = @countryId) order by Name, Firstname" />
  </cf:entity>
  <cf:entity name="Group" defaultUsePersistenceDefaultValue="false" namespace="Example.Models.Contact.Contact" categoryPath="/RH" storeName="ExampleStoreName">
    <cf:property name="GroupId" key="true" persistenceEnforce="true" />
    <cf:property name="Value" defaultValue="enumGroupType.DGS" typeName="int" persistenceEnforce="true" />
  </cf:entity>
  <cf:entity name="StructureSupplier" baseTypeName="Example.Models.Contact.Structure.Structure" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models" storeName="ExampleStoreName">
    <cf:property name="CartePecheDepositaireId" persistenceEnforce="true" />
    <cf:property name="NumberExt" persistenceEnforce="true" />
    <cf:property name="DocumentUrl" persistenceEnforce="true" />
    <cf:property name="DocumentName" persistenceEnforce="true" />
    <cf:property name="IsKeyAccount" typeName="bool" persistenceEnforce="true" />
    <cf:property name="ConventionDate" typeName="date" persistenceEnforce="true" />
  </cf:entity>
  <cf:enumeration name="enumEstablishmentType" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models">
    <cf:enumerationValue name="HEAD_OFFICE" />
    <cf:enumerationValue name="SECONDARY" />
    <cf:enumerationValue name="DELEGATION" />
    <cf:enumerationValue name="ASSOCIATION" />
  </cf:enumeration>
  <cf:enumeration name="enumFunctionType" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models">
    <cf:enumerationValue name="DIRECTOR" />
    <cf:enumerationValue name="EMPLOYEE" />
    <cf:enumerationValue name="ELECTED" />
    <cf:enumerationValue name="VOLUNTEER" />
    <cf:enumerationValue name="INDIVIDUAL" />
    <cf:enumerationValue name="PRESIDENT" />
    <cf:enumerationValue name="VICE_PRESIDENT" />
    <cf:enumerationValue name="TREASURER" />
    <cf:enumerationValue name="SECRETARY" />
    <cf:enumerationValue name="BOARD_MEMBER" />
    <cf:enumerationValue name="LEGAL_MEMBER" />
    <cf:enumerationValue name="BY_LAW_MEMBER" />
    <cf:enumerationValue name="ACCOUNT_INSPECTOR" />
    <cf:enumerationValue name="RESELLER" />
    <cf:enumerationValue name="OWNER" />
    <cf:enumerationValue name="CONTRACTOR" />
    <cf:enumerationValue name="GENERAL_CONTRACTOR" />
    <cf:enumerationValue name="CONTRACTING_AUTHORITY" />
    <cf:enumerationValue name="LESSOR" />
    <cf:enumerationValue name="OTHER" />
    <cf:enumerationValue name="MEMBER" />
  </cf:enumeration>
  <cf:enumeration name="enumStructureSkillTerritoryType" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models">
    <cf:enumerationValue name="LOCAL" />
    <cf:enumerationValue name="DEPARTEMENTAL" />
    <cf:enumerationValue name="REGIONAL" />
    <cf:enumerationValue name="NATIONAL" />
  </cf:enumeration>
  <cf:entity name="StructurePublicOrganization" baseTypeName="Example.Models.Contact.Structure.Structure" namespace="Example.Models.Contact.Structure" categoryPath="/Example.Models" storeName="ExampleStoreName">
    <cf:property name="ReceiptNum" persistenceEnforce="true" />
  </cf:entity>
</cf:project>

Сгенерированный SQL (обратите внимание на дополнительное И в параметре townLabel)

CREATE PROCEDURE [Contact].[Contact_AdvancedSearchContactsTownLabel]
(
 @firstname [nvarchar] (256) = NULL,
 @name [nvarchar] (256) = NULL,
 @groups [Contact].[cf_type_Contact_AdvancedSearchContactsTownLabel_2] READONLY,
 @postalCode [nvarchar] (256) = NULL,
 @townLabel [nvarchar] (256) = NULL,
 @mail [nvarchar] (256) = NULL,
 @townId [nvarchar] (max) = NULL,
 @structureId [uniqueidentifier] = NULL,
 @countryId [uniqueidentifier] = NULL,
 @_orderBy0 [nvarchar] (64) = NULL,
 @_orderByDirection0 [bit] = 0
)
AS
SET NOCOUNT ON
DECLARE @_c_groups int; SELECT @_c_groups= COUNT(*) FROM @groups
DECLARE @sql nvarchar(max), @paramlist nvarchar(max)

SELECT @sql=
'SELECT DISTINCT [Contact].[Contact].[Contact_Name], [Contact].[Contact].[Contact_Firstname], [Contact].[Contact].[Contact_Civility], [Contact].[Contact].[Contact_DateOfBirth], [Contact].[Contact].[Contact_Comment], [Contact].[Contact].[Contact_ContactId], [Contact].[Contact].[Contact_Address_AddressId], [Contact].[Contact].[Contact_TownOfBirthLabel], [Contact].[Contact].[Contact_TownIdOfBirth], [Contact].[Contact].[Contact_CountryIdOfBirth], [Contact].[Contact].[Contact_DepartmentIdOfBirth], [Contact].[Contact].[Contact_PostalCode], [Contact].[Contact].[Contact_CartePecheMemberId], [Contact].[Contact].[_trackLastWriteTime], [Contact].[Contact].[_trackCreationTime], [Contact].[Contact].[_trackLastWriteUser], [Contact].[Contact].[_trackCreationUser], [Contact].[Contact].[_rowVersion] 
    FROM [Contact].[Contact]
        LEFT OUTER JOIN [Contact].[Address] ON ([Contact].[Contact].[Contact_Address_AddressId] = [Contact].[Address].[Address_AddressId])
        LEFT OUTER JOIN [Contact].[StructureContact] ON ([Contact].[Contact].[Contact_ContactId] = [Contact].[StructureContact].[StructureContact_Contact_ContactId])
                LEFT OUTER JOIN [Contact].[Address] [Address$1] ON ([Contact].[StructureContact].[StructureContact_Address_AddressId] = [Address$1].[Address_AddressId])
                LEFT OUTER JOIN [Contact].[StructureContact_Groups_Group] ON ([Contact].[StructureContact].[StructureContact_StructureContactId] = [Contact].[StructureContact_Groups_Group].[StructureContact_StructureContactId])
                        LEFT OUTER JOIN [Contact].[Group] ON ([Contact].[StructureContact_Groups_Group].[Group_GroupId] = [Contact].[Group].[Group_GroupId])
                LEFT OUTER JOIN [Contact].[Structure] ON ([Contact].[StructureContact].[StructureContact_Structure_StructureId] = [Contact].[Structure].[Structure_StructureId])
        LEFT OUTER JOIN [Contact].[Address] [Address$2] ON ([Contact].[Contact].[Contact_Address_AddressId] = [Address$2].[Address_AddressId])
        LEFT OUTER JOIN [Contact].[Contact_Groups_Group] ON ([Contact].[Contact].[Contact_ContactId] = [Contact].[Contact_Groups_Group].[Contact_ContactId])
                LEFT OUTER JOIN [Contact].[Group] [Group$1] ON ([Contact].[Contact_Groups_Group].[Group_GroupId] = [Group$1].[Group_GroupId])
        LEFT OUTER JOIN [Contact].[Address] [Address$3] ON ([Contact].[Contact].[Contact_Address_AddressId] = [Address$3].[Address_AddressId]) 
    WHERE (((1 = 1) AND ((1 = 1) AND ((1 = 1) AND ((1 = 1) AND ((1 = 1) AND ((1 = 1) AND ((1 = 1) AND (1 = 1)))))))) AND (1 = 1))'
SELECT @paramlist = '@firstname nvarchar (256), 
    @name nvarchar (256), 
    @groups [Contact].[cf_type_Contact_AdvancedSearchContactsTownLabel_2] READONLY, 
    @postalCode nvarchar (256), 
    @townLabel nvarchar (256), 
    @mail nvarchar (256), 
    @townId nvarchar (max), 
    @structureId uniqueidentifier, 
    @countryId uniqueidentifier, 
    @_orderBy0 nvarchar (64), 
    @_orderByDirection0 bit'
IF @firstname IS NOT NULL
    SELECT @sql = @sql + ' AND (([Contact].[Contact].[Contact_Firstname] LIKE ((''%'' + @firstname) + ''%'')))'
IF @name IS NOT NULL
    SELECT @sql = @sql + ' AND (([Contact].[Contact].[Contact_Name] LIKE ((''%'' + @name) + ''%'')))'
IF @_c_groups > 0
    SELECT @sql = @sql + ' AND (([Contact].[Group].[Group_Value] IN ((SELECT * FROM @groups)) OR [Group$1].[Group_Value] IN ((SELECT * FROM @groups))))'
IF @postalCode IS NOT NULL
    SELECT @sql = @sql + ' AND ((([Contact].[Address].[Address_PostalCode] LIKE ((''%'' + @postalCode) + ''%'')) OR ([Address$1].[Address_PostalCode] LIKE ((''%'' + @postalCode) + ''%''))))'
IF @townLabel IS NOT NULL
    SELECT @sql = @sql + ' AND ((([Address$2].[Address_TownLabel] LIKE ((''%'' + @townLabel) + ''%'')) OR (([Contact].[Address].[Address_TownLabel] LIKE ((''%'' + @townLabel) + ''%'')) OR ([Contact].[Address].[Address_TownId] IN ((SELECT [Item] FROM [dbo].cf_SplitString(@townId, nchar(1)))) OR [Contact].[Address].[Address_TownId] IN ((SELECT [Item] FROM [dbo].cf_SplitString(@townId, nchar(1))))))) AND ([Contact].[Address].[Address_TownLabel] LIKE ((''%'' + @townLabel) + ''%'')))'
IF @mail IS NOT NULL
    SELECT @sql = @sql + ' AND ((([Address$3].[Address_Email] LIKE ((''%'' + @mail) + ''%'')) OR ([Contact].[Address].[Address_Email] LIKE ((''%'' + @mail) + ''%''))))'
IF @townId IS NOT NULL
    SELECT @sql = @sql + ' AND (([Contact].[Address].[Address_TownId] IN ((SELECT [Item] FROM [dbo].cf_SplitString(@townId, nchar(1)))) OR [Contact].[Address].[Address_TownId] IN ((SELECT [Item] FROM [dbo].cf_SplitString(@townId, nchar(1))))))'
IF @structureId IS NOT NULL
    SELECT @sql = @sql + ' AND (([Contact].[Structure].[Structure_StructureId] = @structureId))'
IF @countryId IS NOT NULL
    SELECT @sql = @sql + ' AND ((([Contact].[Address].[Address_CountryId] = @countryId) OR ([Contact].[Address].[Address_CountryId] = @countryId)))'
SELECT @sql = @sql + ' ORDER BY [Contact].[Contact].[Contact_Name] ASC,[Contact].[Contact].[Contact_Firstname] ASC'
EXEC sp_executesql @sql, @paramlist,
    @firstname, 
    @name, 
    @groups, 
    @postalCode, 
    @townLabel, 
    @mail, 
    @townId, 
    @structureId, 
    @countryId, 
    @_orderBy0, 
    @_orderByDirection0

RETURN
GO

РЕДАКТИРОВАТЬ 16/09/2016 - найдены возможные обходные пути.

Я нашел два возможных обходных пути:

  • Во-первых, иметь более простой метод поиска с остальными параметрами (без townId, без townLabel) и повторно фильтровать в памяти с помощью механизма LINQ.

  • Во-вторых, использовать сгенерированный код в методе RAW и адаптировать его, чтобы он работал так, как мы хотим.


person Olivier ROMAND    schedule 15.09.2016    source источник


Ответы (1)


Методы Search очень сложно генерировать. Фактически производитель должен разделить тело метода по параметрам. Затем он создает оператор IF @param IS NOT NULL и объединяет их с помощью оператора (по умолчанию AND). Если вы хотите изменить этот оператор, вы можете добавить в метод следующий атрибут xml:

<cf:method cfps:searchOperation="OR" ... />

Если у вас не слишком много аргументов (1 или 2), вы можете использовать метод LOAD с параметрами, допускающими значение NULL:

<cf:method name="LoadNullable" body="LOAD(string text1, string text2) WHERE Name = @text1 AND Name = @text2">
  <cf:parameter nullable="True" name="text1" modelNullable="False" />
</cf:method>

Сгенерированный код выглядит так:

CREATE PROCEDURE [dbo].[Customer_LoadNullable]
(
 @text1 [nvarchar] (256) = NULL,
 @text2 [nvarchar] (256)
)
AS
SET NOCOUNT ON
IF(@text1 IS NULL)
BEGIN
    SELECT [Customer].[Customer_Id], [Customer].[Customer_Name]
        FROM [Customer] 
        WHERE ([Customer].[Customer_Name] = @text2)
END
ELSE
BEGIN
    SELECT [Customer].[Customer_Id], [Customer].[Customer_Name]
        FROM [Customer] 
        WHERE (([Customer].[Customer_Name] = @text1) AND ([Customer].[Customer_Name] = @text2))
END

Таким образом, у вас не возникнет проблем с OR и AND, но это не подходит для методов со многими параметрами, допускающими значение NULL.

person meziantou    schedule 15.09.2016
comment
Спасибо за Ваш ответ. К сожалению, если у меня всего 10 параметров, допускающих значение NULL, только 2 из них являются частью операции ИЛИ. Почему скобки не помогают? - person Olivier ROMAND; 15.09.2016
comment
Можете ли вы добавить к своему вопросу полный метод CFQL? - person meziantou; 15.09.2016
comment
Я отредактировал свой вопрос, чтобы прикрепить исходный метод CFQL, схему и сгенерированную процедуру SQL. Схема сложнее приведенного примера. - person Olivier ROMAND; 15.09.2016