首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Sitecore7 Linq to Sitecore仅适用于SearchResultItem,而不适用于自定义映射类

Sitecore7 Linq to Sitecore仅适用于SearchResultItem,而不适用于自定义映射类
EN

Stack Overflow用户
提问于 2014-06-19 07:58:16
回答 4查看 5.1K关注 0票数 3

我有一个很奇怪的问题,我不能把我的头。也许有人能指出我做错了什么。

基本上,我只是尝试使用Linq搜索物品到Sitecore。

所以,我的课程看起来就像(我也在用玻璃)

代码语言:javascript
复制
[SitecoreType(TemplateId = "{TEMPLATE_GIUD}")]
public class MyMappedClass : SharedFieldClass
{
    [SitecoreField(FieldName = "mylist")]
    public virtual IEnumerable<SharedFieldClass> MyMultilistField { get; set; }


    [SitecoreField(FieldName = "field1")]
    [IndexField("field1")]
    public virtual MyKeyValue field1 { get; set; }    
}
[SitecoreType]
public class MyKeyValue
{
    public virtual Sitecore.Data.ID Id {get;set;}    
    public virtual string MyValue{get;set;}
}

所以,当我执行下面的查询时,它的工作原理就像它应该做的那样。

代码语言:javascript
复制
    var results = context.GetQueryable<SearchResultItem>()
                  .Where(c => ((string)c["field1"]) == "{GUID}").GetResults();

但是,当我执行以下操作时,它将返回0结果。

代码语言:javascript
复制
List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
                              .Where(c => c.field1.MyValue == "{GUID}").ToList();

我读过此链接。我遵循了描述这里的第二个过程,即Sitecore7搜索( "SharedFieldClass“包含所有基本的索引字段)。

这是一个很明显的场景,我相信很多人已经做过了,我在这里做了一些傻事。

提前谢谢。

/##编辑##/

好的,我对此做了更多的调查。不确定是ContentSearch/Luncene.NET API中的一个bug,还是我遗漏了一些东西,但似乎发布的这里不是真的,而且如果您有一个复杂的字段类型(您将这样做),您就不能使用映射的类对Lucene进行查询。(不确定Solr是否也是这种情况)。如果您正在对字符串和int这样的简单类型进行搜索,那么它就像一种魅力。

以下是我的发现:

  1. 在启用调试和登录内容搜索之后,我发现,如果像这个context.GetQueryable<MyMappedClass>().Where(c => c.field1.MyValue == "{GUID}")那样进行查询,那么它被转换为DEBUG Executing lucene query: field1.value:7e9ed2ae07194d83872f9836715eca8e,而且在名为“found 1.value”的索引中没有这样的内容,所以查询不会返回任何内容。索引的名称实际上只是"field1“。这是个窃听器吗??
  2. 但是,像这个context.GetQueryable<SearchResultItem>() .Where(c => ((string)c["field1"]) == "{GUID}").GetResults();这样的查询可以工作,因为它会被转换成"DEBUG Executing lucene query: +field1:7e9ed2ae07194d83872f9836715eca8e"
  3. 我还在映射的类中编写了一个方法,如下所示: 公共字符串这个字符串键{ get {返回key.ToLowerInvariant();} set {}

它允许我用我的MyMappedClass编写以下查询。

代码语言:javascript
复制
results2 = context.GetQueryable<MyMappedClass>().Where(c => c["filed1"]== "{GUID}").ToList();

这将返回预期的结果。但是-- MyMappedClass中的字段的值没有被填充(实际上,除了填充的文档中填充的核心/共享值(如templateid、url等)之外,它们都是空的)。所以结果列表几乎是无用的。我可以对所有这些代码执行一个循环,并手动获得填充的值,因为我有itemid。但是想象一下一个大的结果集的成本。

最后我做了这个:

代码语言:javascript
复制
<fieldType fieldTypeName="droplink"                           storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String"   settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider" />

因此,这将返回使用"IndexViewer2.0“在lucene查询中使用itemid填充的"field1”。但是对于MyMappedClass来说也失败了,因为文档中"field1“的值是System.string。但它在MyMappedClass 中被映射为“MyMappedClass”,因此抛出下面的异常

代码语言:javascript
复制
Exception: System.InvalidCastException
Message: Invalid cast from 'System.String' to 'MyLib.MyKeyValue'.

因此,最大的问题是:如何使用他/她映射的类使用凉爽的ContentSearch API ?查询?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-20 06:38:25

您可以为lucene创建一个自定义字段映射程序,它将从索引中的Guid转换为一个玻璃模型。我破解了这个,但我还没有测试过:

代码语言:javascript
复制
public class IndexFieldDateTimeValueConverter : TypeConverter
{

    public Type RequestedType { get; set; }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        var config = Glass.Mapper.Context.Default.GetTypeConfiguration<SitecoreTypeConfiguration>(sourceType, true);
        if (config != null)
        {
            RequestedType = sourceType;
            return true;
        }
        else
            return base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(string))
            return true;
        else
            return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var scContext = new SitecoreContext();
        return scContext.CreateType(RequestedType,  scContext.Database.GetItem(value.ToString()),true, false, new Dictionary<string, object>());


    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var config = Glass.Mapper.Context.Default.GetTypeConfiguration<SitecoreTypeConfiguration>(value.GetType(), true);
        ID id =config.GetId(value);
        return id.ToShortID().ToString().ToLowerInvariant();
    }

我担心的是,ConvertFrom方法没有传递所请求的类型,因此我们必须将其作为属性存储在类中,以便将其从CanConvertFrom方法传递给ConvertFrom方法。这使得这个类不安全。

将其添加到sitecore配置的indexFieldStorageValueFormatter部分。

票数 4
EN

Stack Overflow用户

发布于 2014-06-20 06:34:08

我进一步挖掘了一下,找到了一个可行的解决方案。张贴在这里,以防任何人遇到这个问题。

这就是我的"SharedFieldClass“的样子(这有点不对)

代码语言:javascript
复制
public abstract class SharedFieldClass
{
    [SitecoreId]
    [IndexField("_id")]
    [TypeConverter(typeof(IndexFieldIDValueConverter))]
    public virtual ID Id { get; set; }

    [SitecoreInfo(SitecoreInfoType.Language)]
    [IndexField("_language")]
    public virtual string Language { get; set; }

    [SitecoreInfo(SitecoreInfoType.Version)]
    public virtual int Version
    {
        get
        {
            return Uri == null ? 0 : Uri.Version.Number;
        }
    }

    [TypeConverter(typeof(IndexFieldItemUriValueConverter))]
    [XmlIgnore]
    [IndexField("_uniqueid")]
    public virtual ItemUri Uri { get; set; }
}

玻璃里有一个类做映射。如下所示:

代码语言:javascript
复制
var sitecoreService = new SitecoreService("web");
foreach (var r in results)
{
    sitecoreService.Map(r);
}

对我来说,这门课没能映射,因为这一行:

代码语言:javascript
复制
        [SitecoreId]
        [IndexField("_id")]
        [TypeConverter(typeof(IndexFieldIDValueConverter))]
        public virtual ID Id { get; set; }

它在sitecoreService.Map(r);行中抛出一个空异常,因此我将其更改为:

代码语言:javascript
复制
    [SitecoreId]
    [IndexField("_group")]
    [TypeConverter(typeof(IndexFieldIDValueConverter))]
    public virtual ID Id { get; set; }

而且起作用了。我不确定ItemId的索引字段何时从"_id“更改为"_group”,或者是否总是这样。但它是_group类中的“SearchResultItem”。所以我用了它,地图也成功了。

因此,所有的解决方案都是这样的:

映射的类:

代码语言:javascript
复制
[SitecoreType(TemplateId = "{TEMPLATE_GIUD}")]
public class MyMappedClass : SharedFieldClass
{
    [SitecoreField(FieldName = "mylist")]
    public virtual IEnumerable<SharedFieldClass> MyMultilistField { get; set; }


    [SitecoreField(FieldName = "field1")]
    [IndexField("field1")]
    public virtual MyKeyValue field1 { get; set; }    

    // Will be set with key and value for each field in the index document
    public string this[string key]
    {
        get
        {
            return key.ToLowerInvariant();
        }
        set { }
    }
}
[SitecoreType]
public class MyKeyValue
{
    public virtual Sitecore.Data.ID Id {get;set;}    
    public virtual string MyValue{get;set;}
}

查询内容如下:

代码语言:javascript
复制
List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
                              .Where(c => c["field1"] == "{GUID}").ToList();

就这样。

/*编辑*/

噢!!等等,不是这样的。--当索引文档中使用guid填充"field1“时,仍然无法转换复杂类型"MyKeyValue”。

因此,为了避免这种情况,我不得不按照迈克尔·爱德华兹的建议写我的自定义转换器。

为了满足我的需要,我不得不稍微修改这门课。

代码语言:javascript
复制
public class IndexFieldKeyValueModelConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        var config = Glass.Mapper.Context.Default.GetTypeConfiguration<SitecoreTypeConfiguration>(sourceType, true);
        if (config != null && sourceType == typeof(MyLib.IKeyValue))
        {
            return true;
        }
        else
            return base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(string))
            return true;
        else
            return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var scContext = new SitecoreContext();
        Guid x = Guid.Empty;
        if(value is string)
        {
            x = new Guid((string)value);
        }

        var item = scContext.Database.GetItem(x.ToString());
        if (item == null)
            return null;
        return scContext.CreateType(typeof(MyLib.IKeyValue), item, true, false, new Dictionary<string, object>());
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var config = Glass.Mapper.Context.Default.GetTypeConfiguration<SitecoreTypeConfiguration>(value.GetType(), true);
        ID id = config.GetId(value);
        return id.ToShortID().ToString().ToLowerInvariant();
    }
}

不确定这是否是预期的行为。但出于某种原因,在从转换方法中,“对象值”参数的值是短字符串id格式。因此,为了使scContext.Database.GetItem工作,我必须将它转换为适当的GUID,然后它开始返回正确的项而不是null。

然后我写了这样的查询:

代码语言:javascript
复制
results = context.GetQueryable<MyMappedGlassClass>().Where(c => c["field1"] == field1value && c["field2"] == field2value && c["_template"] == templateId).Filter(selector => selector["_group"] != currentId).ToList();

看上去还挺不错的。我想使用LinqHelper.CreateQuery方法是一条简单的出路。但正如波普先生所建议的那样,这里认为这种方法是不被使用的,因为这是一种内部方法。

不知道这里的余额是多少。/*结束编辑*/

请参阅我的问题描述部分,以了解为什么我必须这样做。

此外,(我的偏见意见)是技巧所描述的这里可能不再有效(请参阅我的问题描述的编辑部分的原因背后)。

此外,Glass教程这里中的itemid索引字段我认为是错误的(除非另有证明)。

希望它能帮助某人节省/浪费时间。

票数 6
EN

Stack Overflow用户

发布于 2014-06-19 15:50:54

这里的问题是,SearchResultItem实际上不是一个Item,但是确实有GetItem()方法来获取Sitecore项。您需要做的是:

代码语言:javascript
复制
List<MyMappedClass> results = context.GetQueryable<SearchResultItem>()
    .Select(sri => sri.GetItem())
    .Where(i => i != null)
    .Select(i => i.GlassCast<MyMappedClass>())
    .Where(c => c.field1.MyValue == "{GUID}").ToList();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24301548

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档