仅限 EPi 服务器:
如何搜索给定属性中具有任何值的页面?我可以搜索属性中具有特定值的页面,但我不知道如何搜索“非空”。
例如,这不起作用:
var criterias = newPropertyCriteriaCollection
{
new PropertyCriteria()
{
Condition = CompareCondition.NotEqual,
Name = "MyProperty",
IsNull = false,
Type = PropertyDataType.String,
Value = ""
}
};
var pages = DataFactory.Instance.FindPagesWithCriteria(PageReference.StartPage, criterias);
抛出异常,“crieria 值不能为 null 或空。设置 IsNull 属性以搜索 null。”
有什么想法吗?
是的,这很令人困惑。如果其他人无意中发现了这一点,以下是如何搜索将某个 PageReference 属性设置为某项的页面:
new PropertyCriteria()
{
createdCriteria.Name = "MyProperty";
createdCriteria.Type = PropertyDataType.PageReference;
createdCriteria.Condition = EPiServer.Filters.CompareCondition.NotEqual;
createdCriteria.Value = "0";
createdCriteria.IsNull = false;
}
除非我错过了一个技巧,否则使用 EPiServer PropertyCriteriaCollection 似乎不可能实现这一点。
我对反射器进行了深入研究,这是我的发现。 FPWC 方法最终调用 EPiServer.DataAccess.PropertySearchDB.FastFindPagesWithCriteria()。
此方法的内容如下:
foreach (PropertyCriteria criteria in criterias)
{
if (criteria.IsNull)
{
criteria.Value = null;
}
else if (string.IsNullOrEmpty(criteria.Value))
{
throw new EPiServerException("The crieria value cannot be null or empty. Set the IsNull property to search for null.");
}
...
}
因此,如果不将 IsNull 设置为 true,就不可能搜索空字符串值。然后将其提供给 EPiServer.DataAccess.PropertySearchDB.ExecuteCriteria 方法,该方法构造并格式化 DB 命令。由于 IsNull 为 true,因此使用 netPropertySearchNull 存储过程。搜索字符串需要使用netPropertySearchString存储过程。
if (criteria.IsNull && !PageDB.IsMetaData(criteria.Name))
{
cmd.CommandText = "netPropertySearchNull";
}
我的建议是加载完整的页面列表并使用 linq 进行过滤。或者,您可以考虑绕过 API 并实现直接数据库查询,或使用一些低级 EPiServer 数据访问方法(不推荐)
对我的第一个答案表示歉意 - 我真的应该在发布之前测试代码:)
我看到页面有一个隐藏的布尔属性“Property X contains a value”,该属性在 Saving 事件中设置。
然后,该 bool 属性将用作 PropertyCriteria,而不是您真正感兴趣的属性。
由于以下原因,似乎无法使用
DataFactory
或 PageCriteriaQueryService
来做到这一点:
PropertySearchDB
,内部调用存储过程,不支持NotEqual
比较条件:switch (criteria.Condition)
{
case CompareCondition.Equal:
this.SetValue(cmd, "UseWildCardsBefore", (object) 0);
this.SetValue(cmd, "UseWildCardsAfter", (object) 0);
break;
case CompareCondition.StartsWith:
this.SetValue(cmd, "UseWildCardsBefore", (object) 0);
this.SetValue(cmd, "UseWildCardsAfter", (object) 1);
break;
case CompareCondition.EndsWith:
this.SetValue(cmd, "UseWildCardsBefore", (object) 1);
this.SetValue(cmd, "UseWildCardsAfter", (object) 0);
break;
case CompareCondition.Contained:
this.SetValue(cmd, "UseWildCardsBefore", (object) 1);
this.SetValue(cmd, "UseWildCardsAfter", (object) 1);
break;
default:
throw new EPiServerException("CompareCondition." + criteria.Condition.ToString() + " not supported in PropertySearch for strings.");
}
PropertyCriteria.IsNull
仅在设置为 true 时才起作用; ExecuteCriteria
代码:if (criteria.IsNull && !ContentDB.IsMetaData(criteria.Name))
{
command.CommandText = "netPropertySearchNull";
}
else
...
此外,
netPropertySearchNull
不支持非空逻辑:
CREATE PROCEDURE [dbo].[netPropertySearchNull]
(
@PageID INT,
@PropertyName NVARCHAR(255),
@LanguageBranch NCHAR(17) = NULL
)
一个明显的解决方案是通过
ContentLoader
获取所有数据并比较值。但它的性能很重。
另一种方法是在代码中使用直接 SQL 查询:
SELECT content.pkid AS PkId,
content.contentguid,
cp.longstring
FROM tblcontent content
LEFT JOIN tblcontenttype ct
ON content.fkcontenttypeid = ct.pkid
LEFT JOIN tblcontentproperty cp
ON content.pkid = cp.fkcontentid
LEFT JOIN tblpropertydefinition tpd
ON cp.fkpropertydefinitionid = tpd.pkid
WHERE ct.base = 'Page'
AND tpd.NAME = 'MyProperty'
注:
您可以从
cp.longstring
切换到实际类型。
您也可以省略或用其他类型替换
base
。可能的值:
NULL
然后,您可以在 Optimizely/Episerver 中运行查询,如下所示:
var executor = ServiceLocator.Current.GetRequiredService<IDatabaseExecutor>();
executor.Execute(() =>
{
using var command = executor.CreateCommand();
command.CommandText = sqlQuery;
command.CommandType = CommandType.Text;
using var reader = command.ExecuteReader(CommandBehavior.Default);
using var dt = new DataTable();
dt.Load(reader);
var rows = dt.AsEnumerable();
foreach (DataRow dataRow in rows)
{
// TODO: map like
var id = dataRow.Field<int>("PkId");
}
}
要查找空值,您需要在 PropertyCriteria 上指定 IsNull 属性并使用 Equal 比较条件。
例如
var criterias = newPropertyCriteriaCollection
{
new PropertyCriteria()
{
Condition = CompareCondition.NotEqual,
Name = "MyProperty",
IsNull = true,
Type = PropertyDataType.String
}
};