如何在Sitecore中为SitecoreQuery和SitecoreChildren属性启用VersionCountDisabler for Glass Mapper

时间:2014-10-29 18:07:13

标签: sitecore glass-mapper

对于放置在GlassModel上的SitecoreQuery和SitecoreChildren属性,glass mapper将返回null对象或(无项)。这些属性不带任何这样的参数,我可以指定它们返回项目,如果它们不存在于上下文中。物品,例如存在于EN中但在en-ES中不存在。我需要在我的视图中进行大量的空检查以避免Null异常并使视图或控制器非常混乱。为了使它工作,必须编写许多锅炉板代码。 在页面编辑器中,SitecoreChildren返回项目和内容作者可以通过编辑项目上的任何字段来创建该语言版本中的项目。这会自动在该语言中创建项目。但是,相同的代码将在预览模式下失败,因为SitecoreChidren将返回null并且您看到空指针异常。 SitecoreQuery不会在页面编辑器中返回任何项目,然后内容作者将无法在页面编辑器中创建项目。 如果我们可以将参数传递给SiteocreQuery属性以使其体验良好,那么它将禁用VsersionCount并返回该项目中的项目(如果它们不存在于该语言中)。

1 个答案:

答案 0 :(得分:2)

实际上这是不可能的。有一个issue on GitHu b可以很容易地创建自定义属性来处理这个非常简单。目前,您需要创建一个新的类型映射器并复制SitecoreQueryMapper中的所有代码。我写了一篇关于如何创建自定义类型映射器的blog post here。您需要创建以下类(SitecoreQuery的示例)。

新配置:

public class SitecoreSharedQueryConfiguration : SitecoreQueryConfiguration
{
}

新属性:

public class SitecoreSharedQueryAttribute : SitecoreQueryAttribute
{
    public SitecoreSharedQueryAttribute(string query) : base(query)
    {
    }

    public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
    {
        var config = new SitecoreSharedQueryConfiguration();
        this.Configure(propertyInfo, config);
        return config;
    }
}

新类型映射器:

public class SitecoreSharedQueryTypeMapper : SitecoreQueryMapper
{
    public SitecoreSharedQueryTypeMapper(IEnumerable<ISitecoreQueryParameter> parameters)
        : base(parameters)
    {
    }

    public override object MapToProperty(AbstractDataMappingContext mappingContext)
    {
        var scConfig = Configuration as SitecoreQueryConfiguration;
        var scContext = mappingContext as SitecoreDataMappingContext;

        using (new VersionCountDisabler())
        {
            if (scConfig != null && scContext != null)
            {
                string query = this.ParseQuery(scConfig.Query, scContext.Item);

                if (scConfig.PropertyInfo.PropertyType.IsGenericType)
                {
                    Type outerType = Glass.Mapper.Sc.Utilities.GetGenericOuter(scConfig.PropertyInfo.PropertyType);

                    if (typeof(IEnumerable<>) == outerType)
                    {
                        Type genericType = Utilities.GetGenericArgument(scConfig.PropertyInfo.PropertyType);

                        Func<IEnumerable<Item>> getItems;
                        if (scConfig.IsRelative)
                        {
                            getItems = () =>
                                {
                                    try
                                    {
                                        return scContext.Item.Axes.SelectItems(query);
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new MapperException("Failed to perform query {0}".Formatted(query), ex);
                                    }
                                };
                        }
                        else
                        {
                            getItems = () =>
                                {
                                    if (scConfig.UseQueryContext)
                                    {
                                        var conQuery = new Query(query);
                                        var queryContext = new QueryContext(scContext.Item.Database.DataManager);

                                        object obj = conQuery.Execute(queryContext);
                                        var contextArray = obj as QueryContext[];
                                        var context = obj as QueryContext;

                                        if (contextArray == null)
                                            contextArray = new[] { context };

                                        return contextArray.Select(x => scContext.Item.Database.GetItem(x.ID));
                                    }

                                    return scContext.Item.Database.SelectItems(query);
                                };
                        }

                        return Glass.Mapper.Sc.Utilities.CreateGenericType(typeof(ItemEnumerable<>), new[] { genericType }, getItems, scConfig.IsLazy, scConfig.InferType, scContext.Service);
                    }

                    throw new NotSupportedException("Generic type not supported {0}. Must be IEnumerable<>.".Formatted(outerType.FullName));
                }

                {
                    Item result;
                    if (scConfig.IsRelative)
                    {
                        result = scContext.Item.Axes.SelectSingleItem(query);
                    }
                    else
                    {
                        result = scContext.Item.Database.SelectSingleItem(query);
                    }

                    return scContext.Service.CreateType(scConfig.PropertyInfo.PropertyType, result, scConfig.IsLazy, scConfig.InferType, null);
                }
            }
        }

        return null;
    }

    public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
    {
        return configuration is SitecoreSharedQueryConfiguration;
    }
}

在glass配置中配置新类型映射器(映射器和构造函数的参数):

container.Register(Component.For<AbstractDataMapper>().ImplementedBy<SitecoreSharedQueryTypeMapper>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdNoBracketsParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemEscapedPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemDateNowParameter>>().LifeStyle.Transient);

然后,您只需将模型上的SitecoreQuery属性更改为SitecoreSharedQuery

即可
[SitecoreSharedQuery("./*")]
public virtual IEnumerable<YourModel> YourItems { get; set; }

对于孩子,您可以使用共享查询映射器并查询子项,也可以为新的SitecoreSharedChildren查询创建相同的类。

修改:添加了IEnumerable<ISitecoreQueryParameter>的绑定,因为它们丢失了,因此引发了错误。