version 5.xc#
NEST 直接支持返回協變結果集合。這意味着,能夠將搜索結果的類型指定爲一個接口或者基類,可是其真實類型仍然是接口或基類的一個子類型。this
讓咱們來看一個例子,假設咱們想要搜索的多個類型都實現了 ISearchResult
接口code
public interface ISearchResult { string Name { get; set; } } public abstract class BaseX : ISearchResult { public string Name { get; set; } }
針對 ISearchResult
,咱們提供了三種實現,分別叫 A
, B
和 C
對象
public class A : BaseX { public int PropertyOnA { get; set; } } public class B : BaseX { public int PropertyOnB { get; set; } } public class C : BaseX { public int PropertyOnC { get; set; } }
要想搜索多個類型,最直接的方式是,先將響應的類型指定爲接口或者基類,而後使用 .Type()
傳遞咱們想搜索的實際類型接口
var result = this._client.Search<ISearchResult>(s => s .Type(Types.Type(typeof(A), typeof(B), typeof(C))) .Size(100) );
NEST 會把這份邏輯代碼轉化爲 /index/a,b,c/_search
,有 "_type" : "a"
的命中結果會被序列化爲 A
類型的對象,以此類推。文檔
在這裏,咱們假設全部的響應都是有效的,而且咱們將接收到預期的 100 份文檔。記住, result.Document
是一個 IReadOnlyCollection<ISearchResult>
類型的對象get
result.ShouldBeValid(); result.Documents.Count.Should().Be(100);
爲了證實返回的結果集合是協變的,咱們根據它們的真實類型過濾文檔,並斷言這些子集是咱們指望的大小string
var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50);
另外,假設只存在於子類自己的屬性會被正確填充it
aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);
一個相對較低級別的方式是,本身檢查命中結果,並肯定要反序列化的 CLR 類型io
var result = this._client.Search<ISearchResult>(s => s .ConcreteTypeSelector((d, h) => h.Type == "a" ? typeof(A) : h.Type == "b" ? typeof(B) : typeof(C)) .Size(100) );
對於每個命中結果,咱們會調用傳遞給 ConcreteTypeSelector
的委託
d
表示 _source
公開爲一個 dynamic
類型h
表明着對命中結果的封裝(例如:Hit<dynamic>
)咱們假設響應是有效的,而且接收到了預期的 100 份文檔。記住, result.Document
是一個 IReadOnlyCollection<ISearchResult>
類型的對象
result.ShouldBeValid(); result.Documents.Count.Should().Be(100);
爲了證實返回的結果集合是協變的,咱們根據它們的真實類型過濾文檔,並斷言這些子集是咱們指望的大小
var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50);
另外,假設只存在於子類自己的屬性會被正確填充
aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);
Scroll API 是上一個搜索示例的延伸,咱們再也不使用 Types() 。你可使用 .CovariantTypes()
來指示類型。
var result = this._client.Scroll<ISearchResult>(TimeSpan.FromMinutes(60), "scrollId", s => s .CovariantTypes(Types.Type(typeof(A), typeof(B), typeof(C))) );
NEST 會把這份邏輯代碼轉化爲 /index/a,b,c/_search
,有 "_type" : "a"
的命中結果會被序列化爲 A
類型的對象,以此類推。
後續的驗證過程同上(也許你已經發現前面的兩節內容裏存在者相同的步驟)
相對較低級別的 concrete type selector 也能夠用在 scroll 中
var result = this._client.Scroll<ISearchResult>(TimeSpan.FromMinutes(1), "scrollid", s => s .ConcreteTypeSelector((d, h) => h.Type == "a" ? typeof(A) : h.Type == "b" ? typeof(B) : typeof(C)) );
重複驗證工做
協變不單單在接口方式中工做,下面即是子類型協變的示例:
var result = this._client.Search<BaseX>(s => s .Type(Types.Type(typeof(A), typeof(B), typeof(C))) .Size(100) ); result.ShouldBeValid(); result.Documents.Count.Should().Be(100); var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50); aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);