Sitecore7 Linq到Sitecore仅适用于SearchResultItem,但不适用于自定义映射类

Ali*_*hid 3 linq sitecore linq-query-syntax sitecore7 glass-mapper

我有这个非常奇怪的问题,我无法理解.也许有人可以指出我做错了什么.

基本上,我只是尝试使用Linq搜索项目到Sitecore.

所以,我的班级看起来像(我也在使用玻璃)

[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;}
}
Run Code Online (Sandbox Code Playgroud)

因此,当我执行以下查询时,它可以正常工作.

    var results = context.GetQueryable<SearchResultItem>()
                  .Where(c => ((string)c["field1"]) == "{GUID}").GetResults();
Run Code Online (Sandbox Code Playgroud)

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

List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
                              .Where(c => c.field1.MyValue == "{GUID}").ToList();
Run Code Online (Sandbox Code Playgroud)

我看过这个链接.我已经按照此处描述的第二个过程使用Glass来使用Sitecore7 Search("SharedFieldClass"包含所有基本索引字段).

这是一个非常明显的场景,我相信很多人已经做过了,我在做一些愚蠢的事情.

提前致谢.

/ ##编辑## /

好的,所以我已经做了更多的挖掘.不确定它是否是ContentSearch/Luncene.NET API中的错误或者我遗漏了什么但是看起来这里发布的内容可能不正确如果你有一个复杂的字段类型(你会)你不能用映射类查询反对Lucene.(不确定Solr是否也是如此).如果您正在搜索像string和int这样的简单类型,那么它就像魅力一样.

这是我的发现:

  1. 在为contentsearch启用DEBUG和LOG之后,我发现如果我像这样查询context.GetQueryable<MyMappedClass>().Where(c => c.field1.MyValue == "{GUID}")它被翻译成什么,DEBUG Executing lucene query: field1.value:7e9ed2ae07194d83872f9836715eca8e并且因为在名为"field1.value"的索引中没有这样的东西,查询不会返回任何内容.索引的名称实际上只是"field1".这是一个错误?
  2. 但是,这样的查询是context.GetQueryable<SearchResultItem>() .Where(c => ((string)c["field1"]) == "{GUID}").GetResults();有效的,因为它被翻译成了"DEBUG Executing lucene query: +field1:7e9ed2ae07194d83872f9836715eca8e".
  3. 我也在我的映射类中编写了一个方法,如下所示:

    public string this[string key]
    {
        get
        {
            return key.ToLowerInvariant();
        }
        set { }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这允许我使用MyMappedClass编写以下查询.

results2 = context.GetQueryable<MyMappedClass>().Where(c => c["filed1"]== "{GUID}").ToList();
Run Code Online (Sandbox Code Playgroud)

这返回了预期的结果.但是 MyMappedClass中的字段值没有被填充(事实上它们都是null,除了核心/共享值,比如填充文档中填充的templateid,url等).所以结果列表几乎没用.我可以循环遍历所有这些并手动获取填充的值,因为我有itemid.但想象一下大型结果集的成本.

最后我这样做了:

<fieldType fieldTypeName="droplink"                           storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String"   settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider" />
Run Code Online (Sandbox Code Playgroud)

所以这使用"IndexViewer2.0"在lucene查询中返回带有itemid的填充"field1".失败了MyMappedClass太为"字段1"的文档中的值以System.String ..但它是在MyMappedClass映射为"MyKeyValue" SO它抛出以下异常

Exception: System.InvalidCastException
Message: Invalid cast from 'System.String' to 'MyLib.MyKeyValue'.
Run Code Online (Sandbox Code Playgroud)

所以,最大的问题是: 如何使用酷的ContentSearch API查询他/她的映射类?

Ali*_*hid 6

我更进一步挖掘让我找到一个有效的解决方案.在此处发布以防万一有人遇到此问题.

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

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; }
}
Run Code Online (Sandbox Code Playgroud)

Glass中有一个类可以进行映射.如下所示:

var sitecoreService = new SitecoreService("web");
foreach (var r in results)
{
    sitecoreService.Map(r);
}
Run Code Online (Sandbox Code Playgroud)

对我来说,由于这一行,这个课没有映射:

        [SitecoreId]
        [IndexField("_id")]
        [TypeConverter(typeof(IndexFieldIDValueConverter))]
        public virtual ID Id { get; set; }
Run Code Online (Sandbox Code Playgroud)

它在sitecoreService.Map(r)上抛出一个NULL异常; 所以我把它改成了以下:

    [SitecoreId]
    [IndexField("_group")]
    [TypeConverter(typeof(IndexFieldIDValueConverter))]
    public virtual ID Id { get; set; }
Run Code Online (Sandbox Code Playgroud)

它奏效了.我不确定sitecore中ItemId的索引字段何时从"_id"更改为"_group",或者它是否始终如此.但它是SearchResultItem类中的"_group".所以我使用它并且映射成功.

总而言之,所有解决方案看起来像这样:

映射类:

[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;}
}
Run Code Online (Sandbox Code Playgroud)

查询是:

List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
                              .Where(c => c["field1"] == "{GUID}").ToList();
Run Code Online (Sandbox Code Playgroud)

而已.

/*编辑*/

哦!!等等不是这样.当在索引文档中使用guid填充"field1"时,仍然无法转换复杂类型"MyKeyValue".

所以为了避免这种情况,我不得不像@Michael Edwards建议的那样编写我的自定义转换器.

我不得不稍微修改一下这个课程以满足我的需求..

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

然后我写了这样的查询:

results = context.GetQueryable<MyMappedGlassClass>().Where(c => c["field1"] == field1value && c["field2"] == field2value && c["_template"] == templateId).Filter(selector => selector["_group"] != currentId).ToList();
Run Code Online (Sandbox Code Playgroud)

看起来有点工作要让它发挥作用.我想使用LinqHelper.CreateQuery方法是一种简单的方法..但是正如Pope先生在这里建议的那样,不使用这种方法,因为这是一种内部方法.

不知道这里的平衡是什么./*结束编辑*/

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

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

此外,在玻璃映射器教程的itemid索引字段这里是我想错了(除非另有证实).

希望它可以帮助某人节省/浪费时间.