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,查询 abstacts 类实现的属性

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 });
            }
        }
    }