搜索属性中具有任意值的页面

问题描述 投票:0回答:5

仅限 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。”

有什么想法吗?

c# .net episerver
5个回答
2
投票

是的,这很令人困惑。如果其他人无意中发现了这一点,以下是如何搜索将某个 PageReference 属性设置为某项的页面:

new PropertyCriteria()
{
    createdCriteria.Name = "MyProperty";
    createdCriteria.Type = PropertyDataType.PageReference;
    createdCriteria.Condition = EPiServer.Filters.CompareCondition.NotEqual;
    createdCriteria.Value = "0";
    createdCriteria.IsNull = false;
}

1
投票

除非我错过了一个技巧,否则使用 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 数据访问方法(不推荐)

对我的第一个答案表示歉意 - 我真的应该在发布之前测试代码:)


0
投票

我看到页面有一个隐藏的布尔属性“Property X contains a value”,该属性在 Saving 事件中设置。

然后,该 bool 属性将用作 PropertyCriteria,而不是您真正感兴趣的属性。


0
投票

由于以下原因,似乎无法使用

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");
    }
}

-2
投票

要查找空值,您需要在 PropertyCriteria 上指定 IsNull 属性并使用 Equal 比较条件。

例如

var criterias = newPropertyCriteriaCollection
{
  new PropertyCriteria()
  { 
    Condition = CompareCondition.NotEqual, 
    Name = "MyProperty", 
    IsNull = true, 
    Type = PropertyDataType.String
  }
};
© www.soinside.com 2019 - 2024. All rights reserved.