RavenDb,查询 abstacts 类实现的属性
本文关键字:实现 属性 abstacts 查询 RavenDb | 更新日期: 2023-09-27 18:31:35
我有 3 个对象车辆、汽车和摩托车。Vehicle 是 Car 和 MotorCycle 的抽象基类。
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);
现在我想为所有车辆的请求做索引。但我想请求车辆属性和实现(汽车、摩托车)属性。
我会请求的示例:
- 所有颜色="红色"的车辆,引擎功率>100
- 颜色="红色", 发动机功率>100, 座位数=5 的所有车辆
- 类型="踏板车"的所有车辆
- 等。。。。
结果只有一个车辆类型的集合,按RealeaseDate排序。如何在 C# 和 linq 中进行这样的查询?
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 });
}
}
我已经使用接口写了一篇更深入的博客文章,但完全相同的技术适用于抽象基类。在此处查看博客文章
它实际上是一种非常强大的技术,允许您充分利用 Raven 的无模式特性。
我遇到了这个线程,想更正到目前为止在这里发布的评论/答案。
可以创建所有继承的索引。
一般来说,最好将所有遗产保存在单独的集合中。所以,换句话说,不是把汽车作为乌鸦的车辆,而是作为汽车。
然后,您可以使用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 });
}
}
}