Solution to Error: ORDER BY items must appear in the select list if SELECT DISTINCT is specified
Solution to Error: ORDER BY items must appear in the select list if SELECT DISTINCT is specified
错误原因:
我正在 TimeCard 实体上创建一个方法。 TimeCard 实体与 Employee 实体相关。该方法按员工姓名对 TimeCards 进行排序。
显而易见的解决方案
从 [project_name]_procedures.sql 文件复制存储过程,并将排序列添加到 select 语句。然后使用存储过程创建原始方法。
问题:
有没有更好的解决办法。我不喜欢明显的解决方案,因为如果我向 TimeCard 实体添加额外的属性,它就会中断。
我想出了一个出色的解决方案,我正在分享。如果有更好的解决方案请告诉我。
为什么会出现这个错误:
使用 CFQL 并添加使用相关实体属性的 WHERE 子句时,生成的存储过程将 DISTINCT 添加到 SELECT 语句。如果您还添加基于相关实体的 属性 的排序顺序,这将生成错误。
步骤 1
使用没有排序顺序的 CFQL 创建方法
步骤 2
在 BOM Producer 上,将 NameSpaceImports 属性设置为 System.Linq
步骤 3
创建一个使用 LINQ 按相关实体排序的 Snipped 方法 属性
警告
调用方法时,return 类型是 List 而不是 TimeCardCollection
下面是完整的 xml 定义。要重现原始错误,请将方法 LoadForActiveEmployeesSortedByEmployee 的 enabled 设置为 true
<cf:project defaultNamespace="DemoSortByRelatedEntity" 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:cfasp="http://www.softfluent.com/codefluent/producers.aspnet/2011/1" defaultTargetFramework="4.0" defaultConnectionString="Database=DemoSortByRelatedEntity;Integrated Security=true" createDefaultMethodForms="true" createDefaultApplication="false" createDefaultHints="false">
<cf:import path="Default.Surface.cfp" />
<cf:producer name="SQL Server Producer" typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
<cf:configuration connectionString="Database=DemoSortByRelatedEntity;Integrated Security=true;Server=.\SQLExpress" produceViews="true" targetVersion="Sql2014" targetDirectory="..\DemoSortByRelatedEntity.Persistence" cfx:targetProjectLayout="UpdateItems, DontRemove" cfx:targetProject="..\DemoSortByRelatedEntity.Persistence\DemoSortByRelatedEntity.Persistence.dbproj" />
</cf:producer>
<cf:producer name="BOM Producer" typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1bb6d7cccf1045ec">
<cf:configuration compileWithVisualStudio="true" targetDirectory="..\DemoSortByRelatedEntity" cfx:targetProject="..\DemoSortByRelatedEntity\DemoSortByRelatedEntity.csproj" namespaceImports="System.Linq" cfx:targetProjectLayout="Update" />
</cf:producer>
<cf:producer name="ASP.NET WebForms Producer" typeName="CodeFluent.Producers.UI.AspNetProducer, CodeFluent.Producers.UI">
<cf:configuration categoryPath="UI\AspNetWebForms" targetDirectory="..\DemoSortByRelatedEntity.Web" cfx:targetProject="..\DemoSortByRelatedEntity.Web\DemoSortByRelatedEntity.Web.csproj" />
</cf:producer>
<cf:entity name="TimeCard" namespace="DemoSortByRelatedEntity">
<cf:property name="Id" key="true" />
<cf:property name="InTime" typeName="datetime" />
<cf:property name="OutTime" typeName="datetime" />
<cf:property name="Employee" typeName="{0}.Employee" />
<cf:method name="LoadForActiveEmployeesSortedByEmployee" body="LOAD() WHERE Employee.IsActive = TRUE ORDER BY Employee.Name" enabled="false" />
<cf:method name="LoadForActiveEmployees" body="LOAD() WHERE Employee.IsActive = TRUE" />
<cf:instance>
<cf:instanceValue name="Id">58138358-1578-4f3a-9273-4fea17aa7dd5</cf:instanceValue>
<cf:instanceValue name="InTime">1/1/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/2/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">a57ba60a-5e6a-4df0-88b9-283d60517b66</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">487a8bcf-89a1-49d6-b970-ae8d32c0f7f2</cf:instanceValue>
<cf:instanceValue name="InTime">2/3/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/4/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">4762eeea-dcc7-4d7e-8b07-1f78b73657ed</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">5f039986-e423-460f-aa7e-9b28e2a507b3</cf:instanceValue>
<cf:instanceValue name="InTime">2/5/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/6/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">c7ae6667-55d4-4ba2-8576-4c0c950b7231</cf:instanceValue>
</cf:instance>
<cf:setSnippet name="LoadForActiveEmployeesSortedByEmployeeFix1" language="CSharp"><![CDATA[
public static System.Collections.Generic.List<TimeCard> LoadForActiveEmployeesSortedByEmployeeFix1()
{
return LoadForActiveEmployees().OrderBy(x => x.Employee.Name).ToList();
}
]]></cf:setSnippet>
</cf:entity>
<cf:entity name="Employee" namespace="DemoSortByRelatedEntity">
<cf:property name="Id" key="true" />
<cf:property name="Name" entityDisplay="true" />
<cf:property name="IsActive" typeName="bool" />
<cf:instance>
<cf:instanceValue name="Id">a57ba60a-5e6a-4df0-88b9-283d60517b66</cf:instanceValue>
<cf:instanceValue name="IsActive">True</cf:instanceValue>
<cf:instanceValue name="Name">Jon</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">4762eeea-dcc7-4d7e-8b07-1f78b73657ed</cf:instanceValue>
<cf:instanceValue name="Name">Mike</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">c7ae6667-55d4-4ba2-8576-4c0c950b7231</cf:instanceValue>
<cf:instanceValue name="IsActive">True</cf:instanceValue>
<cf:instanceValue name="Name">Lisa</cf:instanceValue>
</cf:instance>
</cf:entity>
</cf:project>
CFE 生成的 SQL 无效,如 post 中所述:How SQL DISTINCT and ORDER BY are Related。我认为有 2 个解决方法:
如果不需要,请从存储过程中删除DISTINCT
:
<cf:method name="LoadForActiveEmployeesSortedByEmployee" distinct="false" ... />
对有效的 SQL 查询使用原始方法:
<cf:method body="LOAD() raw" rawBody="SELECT DISTINCT $TimeCard{Columns}$, EmployeeName FROM $TimeCard$ JOIN ... WHERE ... ORDER BY ...">
错误原因: 我正在 TimeCard 实体上创建一个方法。 TimeCard 实体与 Employee 实体相关。该方法按员工姓名对 TimeCards 进行排序。
显而易见的解决方案 从 [project_name]_procedures.sql 文件复制存储过程,并将排序列添加到 select 语句。然后使用存储过程创建原始方法。
问题: 有没有更好的解决办法。我不喜欢明显的解决方案,因为如果我向 TimeCard 实体添加额外的属性,它就会中断。
我想出了一个出色的解决方案,我正在分享。如果有更好的解决方案请告诉我。
为什么会出现这个错误: 使用 CFQL 并添加使用相关实体属性的 WHERE 子句时,生成的存储过程将 DISTINCT 添加到 SELECT 语句。如果您还添加基于相关实体的 属性 的排序顺序,这将生成错误。
步骤 1
使用没有排序顺序的 CFQL 创建方法
步骤 2
在 BOM Producer 上,将 NameSpaceImports 属性设置为 System.Linq
步骤 3
创建一个使用 LINQ 按相关实体排序的 Snipped 方法 属性
警告
调用方法时,return 类型是 List 而不是 TimeCardCollection
下面是完整的 xml 定义。要重现原始错误,请将方法 LoadForActiveEmployeesSortedByEmployee 的 enabled 设置为 true
<cf:project defaultNamespace="DemoSortByRelatedEntity" 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:cfasp="http://www.softfluent.com/codefluent/producers.aspnet/2011/1" defaultTargetFramework="4.0" defaultConnectionString="Database=DemoSortByRelatedEntity;Integrated Security=true" createDefaultMethodForms="true" createDefaultApplication="false" createDefaultHints="false">
<cf:import path="Default.Surface.cfp" />
<cf:producer name="SQL Server Producer" typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
<cf:configuration connectionString="Database=DemoSortByRelatedEntity;Integrated Security=true;Server=.\SQLExpress" produceViews="true" targetVersion="Sql2014" targetDirectory="..\DemoSortByRelatedEntity.Persistence" cfx:targetProjectLayout="UpdateItems, DontRemove" cfx:targetProject="..\DemoSortByRelatedEntity.Persistence\DemoSortByRelatedEntity.Persistence.dbproj" />
</cf:producer>
<cf:producer name="BOM Producer" typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1bb6d7cccf1045ec">
<cf:configuration compileWithVisualStudio="true" targetDirectory="..\DemoSortByRelatedEntity" cfx:targetProject="..\DemoSortByRelatedEntity\DemoSortByRelatedEntity.csproj" namespaceImports="System.Linq" cfx:targetProjectLayout="Update" />
</cf:producer>
<cf:producer name="ASP.NET WebForms Producer" typeName="CodeFluent.Producers.UI.AspNetProducer, CodeFluent.Producers.UI">
<cf:configuration categoryPath="UI\AspNetWebForms" targetDirectory="..\DemoSortByRelatedEntity.Web" cfx:targetProject="..\DemoSortByRelatedEntity.Web\DemoSortByRelatedEntity.Web.csproj" />
</cf:producer>
<cf:entity name="TimeCard" namespace="DemoSortByRelatedEntity">
<cf:property name="Id" key="true" />
<cf:property name="InTime" typeName="datetime" />
<cf:property name="OutTime" typeName="datetime" />
<cf:property name="Employee" typeName="{0}.Employee" />
<cf:method name="LoadForActiveEmployeesSortedByEmployee" body="LOAD() WHERE Employee.IsActive = TRUE ORDER BY Employee.Name" enabled="false" />
<cf:method name="LoadForActiveEmployees" body="LOAD() WHERE Employee.IsActive = TRUE" />
<cf:instance>
<cf:instanceValue name="Id">58138358-1578-4f3a-9273-4fea17aa7dd5</cf:instanceValue>
<cf:instanceValue name="InTime">1/1/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/2/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">a57ba60a-5e6a-4df0-88b9-283d60517b66</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">487a8bcf-89a1-49d6-b970-ae8d32c0f7f2</cf:instanceValue>
<cf:instanceValue name="InTime">2/3/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/4/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">4762eeea-dcc7-4d7e-8b07-1f78b73657ed</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">5f039986-e423-460f-aa7e-9b28e2a507b3</cf:instanceValue>
<cf:instanceValue name="InTime">2/5/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="OutTime">2/6/2019 12:00:00 AM</cf:instanceValue>
<cf:instanceValue name="Employee">c7ae6667-55d4-4ba2-8576-4c0c950b7231</cf:instanceValue>
</cf:instance>
<cf:setSnippet name="LoadForActiveEmployeesSortedByEmployeeFix1" language="CSharp"><![CDATA[
public static System.Collections.Generic.List<TimeCard> LoadForActiveEmployeesSortedByEmployeeFix1()
{
return LoadForActiveEmployees().OrderBy(x => x.Employee.Name).ToList();
}
]]></cf:setSnippet>
</cf:entity>
<cf:entity name="Employee" namespace="DemoSortByRelatedEntity">
<cf:property name="Id" key="true" />
<cf:property name="Name" entityDisplay="true" />
<cf:property name="IsActive" typeName="bool" />
<cf:instance>
<cf:instanceValue name="Id">a57ba60a-5e6a-4df0-88b9-283d60517b66</cf:instanceValue>
<cf:instanceValue name="IsActive">True</cf:instanceValue>
<cf:instanceValue name="Name">Jon</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">4762eeea-dcc7-4d7e-8b07-1f78b73657ed</cf:instanceValue>
<cf:instanceValue name="Name">Mike</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">c7ae6667-55d4-4ba2-8576-4c0c950b7231</cf:instanceValue>
<cf:instanceValue name="IsActive">True</cf:instanceValue>
<cf:instanceValue name="Name">Lisa</cf:instanceValue>
</cf:instance>
</cf:entity>
</cf:project>
CFE 生成的 SQL 无效,如 post 中所述:How SQL DISTINCT and ORDER BY are Related。我认为有 2 个解决方法:
如果不需要,请从存储过程中删除
DISTINCT
:<cf:method name="LoadForActiveEmployeesSortedByEmployee" distinct="false" ... />
对有效的 SQL 查询使用原始方法:
<cf:method body="LOAD() raw" rawBody="SELECT DISTINCT $TimeCard{Columns}$, EmployeeName FROM $TimeCard$ JOIN ... WHERE ... ORDER BY ...">