2014-11-21 75 views
0

我有3個對象Vehicle,Car和MotorCycle。 Vehicle是Car和MotorCycle的抽象基類。RavenDb,關於abstcts類實現的屬性的查詢

public abstract class Vehicle 
{ 
    public String Color {get;set}; 
    public Int Price {get;set}; 
    public DateTime ReleaseDate {get;set}; 
} 

public class Car : Vehicle 
{ 
    public Int EnginePower {get;set}; 
    public Int TrunkSpace {get;set}; 
    public bool GearBoxType {get;set}; 
    public Int Seats {get;set}; 
} 

public class MotorCycle : Vehicle 
{ 
    public Int EnginePower {get;set}; 
    public String Type{get;set}; 
} 

我想在RavenDb的同一份文件中存儲所有車輛(汽車,摩托車......)。所以我使用這個慣例,它的工作原理:

documentStore.Conventions.FindTypeTagName = 
    type => type.IsSubclassOf(typeof(Vehicle)) ? 
     DocumentConvention.DefaultTypeTagName(typeof(Vehicle)) : 
     DocumentConvention.DefaultTypeTagName(type); 

現在我想爲我的所有車輛的請求做索引。但我想請求車輛屬性和實現(汽車,MotorCycle)屬性。請求

實施例I將:

  • 所有車輛用顏色= 「紅色」,EnginePower> 100
  • 所有車輛用顏色= 「紅色」,EnginePower> 100,座椅= 5
  • 具有type =「滑板車」
  • 等所有車輛....

而結果只有一個採集驅動車輛類型,以便通過RealeaseDate的。 如何在C#和linq中執行這樣的查詢?

回答

1

RavenDB會將實體保存爲它們的派生類型並根據這些類型構建任何自動索引。

你需要做的是創建一個新的索引,索引所有不同類型的基類中的屬性,然後從該索引中進行選擇。

public class VehicleIndex : AbstractMultiMapIndexCreationTask 
{ 
public VehicleIndex() 
{ 
this.AddMap<Car>(vehicle => from v in vehicle select new { v.Price , v.Color , v.ReleaseDate }); 
this.AddMap<Motorcycle>(vehicle => from v in vehicle select new { v.Price , v.Color , v.ReleaseDate }); 
} 
} 

我已經使用接口編寫了更深入的博客文章,但是完全相同的技巧適用於抽象基類。請參閱blog post here

它實際上是一種非常強大的技術,可以充分利用Raven的無模式特性。

+0

只是一個簡短的提示,如果您想通過EnginePower查詢,您需要將該屬性移動到基類並將其包含在索引中。 – 2014-11-21 18:14:17

+0

感謝您的回覆,但我不想移動Property EnginePower。我可以從我的單個文檔集合(多種類型)查詢RavenDb studio中的兒童類屬性。在C#中不可能做到這一點? – k4st0r42 2014-11-22 16:52:46

+0

然後你需要使用一個接口並建立索引。在RavenDB中要記住的事情就是一切都是索引,你從來不會像數據庫那樣真正「查詢」它。 – 2014-11-23 20:47:57

1

我碰到這個線程,並想更正迄今發佈在這裏的評論/答案。

可能創建一個所有繼承索引。

一般來說,最好將所有繼承保存在單獨的集合中。換句話說,不要把汽車當作一輛汽車在烏鴉裏,而是作爲一輛汽車。

然後,您可以使用MultiMapIndex對不同的遺產之間的相似性查詢,同時也保留創建一個特定的繼承一個單獨的索引選項,在需要時。

得到你需要,只需將結果保存爲一個新的類型,其中包含想要的所有屬性索引(甚至是創建新的基於子類的輸入)

public class VehicleIndex : AbstractMultiMapIndexCreationTask 
{ 
    public class Mapping 
    { 
     public string Price { get; set; } 
     public string Color { get; set; } 
     public string ReleaseDate { get; set; } 
     public int? EnginePower { get; set;} 
    } 

    public VehicleIndex() 
    { 
     this.AddMap<Car>(vehicle => from v in vehicle select new Mapping() 
     { 
      Price = v.Price, 
      Color = v.Color, 
      ReleaseDate = v.ReleaseDate, 
      EnginePower = v.EnginePower 
     }); 
     this.AddMap<Motorcycle>(vehicle => from v in vehicle select new Mapping() 
     { 
      Price = v.Price, 
      Color = v.Color, 
      ReleaseDate = v.ReleaseDate, 
      EnginePower = v.EnginePower 
     }); 
    } 
} 

我的結果將EnginePower保存爲int?,以便您可以向該課程添加沒有EnginePower的孩子並將其存儲爲null。這允許你通過做過濾摩托車和汽車where(a => a.EnginePower.HasValue && (a.EnginePower > 50 || a.EnginePower < 100))

編輯:我已經添加了自定義過載,只是掃描從T派生的類的整個解決方案,並將它們添加到索引作爲新地圖。這意味着如果添加一個新的孩子,你不必手動將它們添加到索引定義,但只需重新編譯索引,你就可以走了。

public void AddMapForPolymorphic<TBase>(Expression<Func<IEnumerable<TBase>, IEnumerable>> expr) 
    { 
     AddMap(expr); 
     var children = Modules.Modules.Instance.GetModules() 
      .SelectMany(a => AssemblyHelper.GetClassesWithBaseType<TBase>(a.GetType().Assembly) 
      ); 

     var addMapGeneric = GetType() 
      .GetMethod("AddMap", BindingFlags.Instance | BindingFlags.NonPublic); 

     foreach (var child in children) 
     { 
      if (!child.HasAttribute<IgnorePolymorpAttribute>()) 
      { 
       var genericEnumerable = typeof(IEnumerable<>) 
        .MakeGenericType(child); 

       var delegateType = typeof(Func<,>) 
        .MakeGenericType(genericEnumerable, typeof(IEnumerable)); 

       var lambdaExpression = Expression.Lambda(delegateType, expr.Body, Expression 
        .Parameter(genericEnumerable, expr.Parameters[0].Name)); 

       addMapGeneric 
        .MakeGenericMethod(child).Invoke(this, new[] { lambdaExpression }); 
      } 
     } 
    }