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

如何在Sitecore中为SitecoreQuery和SitecoreChildren属性的Glass Mapper启用VersionCountDisabler,sitecore,glass-mapper,Sitecore,Glass Mapper,glass映射器将为放置在GlassModels上的SitecoreQuery和SitecoreChildren属性返回空对象或(无项)。这些属性不接受任何这样的参数,如果上下文Lanague中不存在项,我可以指定它们返回项。例如,项目存在于英语中,但不存在于英语中。我需要在视图中进行大量空检查,以避免出现空异常,并使视图或控制器非常混乱。要使其工作,必须编写大量的锅炉板代码。 在页面编辑器中,SitecoreChildren返回项目,内容作者可以通过编辑项目上的任何字段在该语言版本中创建项目。

glass映射器将为放置在GlassModels上的SitecoreQuery和SitecoreChildren属性返回空对象或(无项)。这些属性不接受任何这样的参数,如果上下文Lanague中不存在项,我可以指定它们返回项。例如,项目存在于英语中,但不存在于英语中。我需要在视图中进行大量空检查,以避免出现空异常,并使视图或控制器非常混乱。要使其工作,必须编写大量的锅炉板代码。 在页面编辑器中,SitecoreChildren返回项目,内容作者可以通过编辑项目上的任何字段在该语言版本中创建项目。这会自动在该语言中创建项目。但是,相同的代码在预览模式下会失败,因为SitecoreChidren将返回null,并且您会看到null指针异常。 SitecoreQuery不会在页面编辑器中返回任何项目,然后内容作者将无法在页面编辑器中创建项目。
如果我们可以将一个参数传递给SiteORequesty属性,使其禁用VsersionCount并返回该语言中不存在的项目,则可以改善体验。

这实际上是不可能的。有一个b,可以很容易地创建一个自定义属性来处理这个问题。目前,您需要创建一个新的类型映射器,并从
SitecoreQueryMapper
复制所有代码。我已经写了一篇关于如何创建自定义类型映射器的文章。您需要创建以下类(例如
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;
    }
}
对于子项,您可以使用共享查询映射器并查询子项,或者为新的
SitecoreSharedChildren
查询创建相同的类


Edit:添加了
IEnumerable
的绑定,因为它们丢失了,因此它抛出了一个错误。

谢谢Kevin。要想让这一切顺利进行是相当棘手的。我还没试过这个,我会试试的。在对它进行了更多的思考之后,对我来说,GlassMapper似乎在做正确的事情。否则,您将如何处理内容不希望在该语言中显示某些项目的场景,如果我们强制这样做,那么我们将永远无法实现它。我知道,如果我们使用回退模块,它会通过设置需要版本冻结的时间来帮助我们。此外,我认为这个解决方案给了我们一些灵活性,我们可以选择对某些模板使用这种行为。因此,这绝对值得一试,再次感谢您花时间将其记录下来。希望我能在第二天或第二天尝试一下,并将其标记为已回答。无法重新测试并尝试,我在注册组件时遇到此错误:无法创建组件“Company.GlassExtensions.SitecoreSharedQueryTypeMapper”,因为它需要满足依赖关系Company.GlassExtensions.SitecoreSharedQueryTypeMapper“正在等待以下依赖项:-服务”System.Collections.Generic.IEnumerable`1[[Glass.Mapper.Sc.DataMappers.SitecoreQueryParameters.ISitecoreQueryParameter,Glass.Mapper.Sc,版本=3.2.2.44,区域性=中性,PublicKeyToken=null]]'未注册。也只是为了calrify,我尝试在container.Install(new SitecoreInstaller(config))之前和之后注册;但同样的结果。在SitecoreInstaller()类中,我确实看到这些组件正在注册。所以我不确定发生了什么。@TMalik你读过我的博文()了吗?关于如何注册映射器,有一个更好的例子。你的第一个评论完全正确。不应将此映射器用于所有属性。仅当所有要映射的项都只有共享字段,因此不需要每种语言的版本时,我们才使用此属性。否则,请考虑使用正常<代码> SitecoreQuery < /Cord>属性。你能给我发送一个模型,渲染和错误消息的例子,你收到Mike @ GLULL。LU?米迦勒。我会尝试制定一封电子邮件并发送给你。凯文在下面所建议的是像一个魔咒一样工作。
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);
[SitecoreSharedQuery("./*")]
public virtual IEnumerable<YourModel> YourItems { get; set; }