我有一个很奇怪的问题,我不能把我的头。也许有人能指出我做错了什么。
基本上,我只是尝试使用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;}
}所以,当我执行下面的查询时,它的工作原理就像它应该做的那样。
var results = context.GetQueryable<SearchResultItem>()
.Where(c => ((string)c["field1"]) == "{GUID}").GetResults();但是,当我执行以下操作时,它将返回0结果。
List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
.Where(c => c.field1.MyValue == "{GUID}").ToList();我读过此链接。我遵循了描述这里的第二个过程,即Sitecore7搜索( "SharedFieldClass“包含所有基本的索引字段)。
这是一个很明显的场景,我相信很多人已经做过了,我在这里做了一些傻事。
提前谢谢。
/##编辑##/
好的,我对此做了更多的调查。不确定是ContentSearch/Luncene.NET API中的一个bug,还是我遗漏了一些东西,但似乎发布的这里不是真的,而且如果您有一个复杂的字段类型(您将这样做),您就不能使用映射的类对Lucene进行查询。(不确定Solr是否也是这种情况)。如果您正在对字符串和int这样的简单类型进行搜索,那么它就像一种魅力。
以下是我的发现:
context.GetQueryable<MyMappedClass>().Where(c => c.field1.MyValue == "{GUID}")那样进行查询,那么它被转换为DEBUG Executing lucene query: field1.value:7e9ed2ae07194d83872f9836715eca8e,而且在名为“found 1.value”的索引中没有这样的内容,所以查询不会返回任何内容。索引的名称实际上只是"field1“。这是个窃听器吗??context.GetQueryable<SearchResultItem>() .Where(c => ((string)c["field1"]) == "{GUID}").GetResults();这样的查询可以工作,因为它会被转换成"DEBUG Executing lucene query: +field1:7e9ed2ae07194d83872f9836715eca8e"。它允许我用我的MyMappedClass编写以下查询。
results2 = context.GetQueryable<MyMappedClass>().Where(c => c["filed1"]== "{GUID}").ToList();这将返回预期的结果。但是-- MyMappedClass中的字段的值没有被填充(实际上,除了填充的文档中填充的核心/共享值(如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" />因此,这将返回使用"IndexViewer2.0“在lucene查询中使用itemid填充的"field1”。但是对于MyMappedClass来说也失败了,因为文档中"field1“的值是System.string。但它在MyMappedClass 中被映射为“MyMappedClass”,因此抛出下面的异常
Exception: System.InvalidCastException
Message: Invalid cast from 'System.String' to 'MyLib.MyKeyValue'.因此,最大的问题是:如何使用他/她映射的类使用凉爽的ContentSearch API ?查询?
发布于 2014-06-20 06:38:25
您可以为lucene创建一个自定义字段映射程序,它将从索引中的Guid转换为一个玻璃模型。我破解了这个,但我还没有测试过:
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部分。
发布于 2014-06-20 06:34:08
我进一步挖掘了一下,找到了一个可行的解决方案。张贴在这里,以防任何人遇到这个问题。
这就是我的"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; }
}玻璃里有一个类做映射。如下所示:
var sitecoreService = new SitecoreService("web");
foreach (var r in results)
{
sitecoreService.Map(r);
}对我来说,这门课没能映射,因为这一行:
[SitecoreId]
[IndexField("_id")]
[TypeConverter(typeof(IndexFieldIDValueConverter))]
public virtual ID Id { get; set; }它在sitecoreService.Map(r);行中抛出一个空异常,因此我将其更改为:
[SitecoreId]
[IndexField("_group")]
[TypeConverter(typeof(IndexFieldIDValueConverter))]
public virtual ID Id { get; set; }而且起作用了。我不确定ItemId的索引字段何时从"_id“更改为"_group”,或者是否总是这样。但它是_group类中的“SearchResultItem”。所以我用了它,地图也成功了。
因此,所有的解决方案都是这样的:
映射的类:
[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;}
}查询内容如下:
List<MyMappedClass> results = context.GetQueryable<MyMappedClass>()
.Where(c => c["field1"] == "{GUID}").ToList();就这样。
/*编辑*/
噢!!等等,不是这样的。--当索引文档中使用guid填充"field1“时,仍然无法转换复杂类型"MyKeyValue”。
因此,为了避免这种情况,我不得不按照迈克尔·爱德华兹的建议写我的自定义转换器。
为了满足我的需要,我不得不稍微修改这门课。
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。
然后我写了这样的查询:
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索引字段我认为是错误的(除非另有证明)。
希望它能帮助某人节省/浪费时间。
发布于 2014-06-19 15:50:54
这里的问题是,SearchResultItem实际上不是一个Item,但是确实有GetItem()方法来获取Sitecore项。您需要做的是:
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();https://stackoverflow.com/questions/24301548
复制相似问题