【问题标题】:Generic Find Method on Repository using Mongo使用 Mongo 在存储库上的通用查找方法
【发布时间】:2015-02-06 20:44:43
【问题描述】:

我正在尝试使用带有表达式的查找操作创建一个通用存储库。我现在有以下内容(我正在使用 FastMapper 从我的实体对象投影到外部合同对象):

    public override List<T> Find(Expression<Func<T, bool>> predicate)
    {
        var collection = _database.GetCollection<Y>(_collectionName);
        return collection.AsQueryable<Y>().Project().To<T>().Where(predicate).ToList();
    }

问题是我得到以下异常:“不支持投影后的谓词。”

我可以执行以下操作,但这会严重影响性能,因为它需要在执行过滤之前从数据库中检索每条记录:

    public override List<T> Find(Expression<Func<T, bool>> predicate)
    {
        var collection = _database.GetCollection<Y>(_collectionName);
        return collection.AsQueryable<Y>().Project().To<T>().ToList().AsQueryable().Where(predicate).ToList();
    }

我想知道是否有一种方法可以将表达式从 T 转换为 Y 对象,以便我可以执行以下操作(我认为这将是最高效的,因为它会将过滤传递到数据库并只对结果集执行项目):

    public override List<T> Find(Expression<Func<T, bool>> predicate)
    {
        var collection = _database.GetCollection<Y>(_collectionName);
        return collection.AsQueryable<Y>().Where(predicate).Project().To<T>().ToList();
    }

任何帮助将不胜感激。谢谢。

更新

因此,使用来自这个问题 (Question) 的信息,我能够更接近我正在寻找的内容。我现在可以执行以下操作:

    public override List<T> Find(Expression<Func<T, bool>> predicate)
    {
        var newPredicate = TransformPredicateLambda<T, Y>(predicate);
        var collection = _database.GetCollection<Y>(_collectionName);
        return collection.AsQueryable<Y>().Where(newPredicate).Project().To<T>().ToList();
    }

此时我唯一需要解决的是检索 fastmapper 映射(如果属性为空部分):

        protected override Expression VisitMember(MemberExpression node)
        {
            var dataContractType = node.Member.ReflectedType;
            var activeRecordType = _typeConverter(dataContractType);

            var property = activeRecordType.GetProperty(node.Member.Name);

            if (property == null)
            {

            }
            var converted = Expression.MakeMemberAccess(
                    base.Visit(node.Expression),
                    property
                    );

                return converted;


        }

基本上,我的一些对象可能看起来像这样:

//object used throughout my code
public class Store
{
     public string StoreId {get; set;}

     public Account Account {get; set;}
     ...
}

//object used in access layer only
public class Store 
{
     public string StoreId {get; set;}

     public string AccountId {get; set;}
     ...
}

在我的初始化脚本中,我定义了一个类型适配器,如下所示:

            TypeAdapterConfig<Store, Models.Store>.NewConfig()
            .MapFrom(a => a.Id, s => s.StoreId != null ? new ObjectId(s.StoreId) : new ObjectId())
            .MapFrom(d => d.AccountId, s => s.Account.AccountId)
            .IgnoreNullValues(true);

【问题讨论】:

    标签: c# mongodb generics repository


    【解决方案1】:

    在将查询提交给 MongoDB 之前,您无法进行从 Y 到 T 的投影的原因是 MongoDB 对 T 一无所知。我们只知道 Y(因为这是集合的类型)。例如:

    class Person
    {
      [BsonElement("fn")]
      public string FirstName { get; set; }
      [BsonElement("ln")]
      public string LastName { get; set; }
    }
    
    class PersonView
    {
      public string FullName { get; set; }
    }
    

    你的投影仪会做这样的事情:

    person => new PersonView { FullName = person.FirstName + person.LastName }
    

    我们无法访问投影仪中的代码,也不知道 FullName 是 FirstName 和 LastName 的串联,因此无法告诉 MongoDB 这样做。

    驱动程序 1.x 版本中的 LINQ 支持不能针对聚合框架,这是唯一合法的地方,并且仅假设您的投影仪生成 Expression&lt;Func&lt;Person, PersonView&gt;&gt; 而不是编译的 Func&lt;Person, PersonView&gt;。但是,2.x 版本的驱动程序会对此有更好的支持,尽管这实际上取决于 FastMapper 在底层做了什么。

    ======

    所以,你目前的选择是这样的:

    1. 将方法签名更改为Expression&lt;Func&lt;Y, bool&gt;&gt;。这不仅可以满足您的需求,还可以将您投影的文档限制为仅通过过滤器的文档。

    2. 如果 T 继承自 Y,您可以从 OfType 开始,甚至不需要投影仪:collection.AsQueryable&lt;Y&gt;().OfType&lt;T&gt;.Where(predicate).ToList();

    【讨论】:

    • 我想将我的应用程序逻辑与我的数据存储逻辑分开,因此我不想在我的整个应用程序中使用的模型对象上拥有 Mongo 属性。我在数据库交互周围放置了一个存储库,其中包含单独的模型对象,其中包括 Mongo 的所有注释(这样我的应用程序的其余部分对 mongo 元素一无所知,如果我改用 Cassandra,我不会根本不必修改应用程序使用的对象,只需修改存储库和它使用的对象)。这就是为什么我不想在存储库之外公开 Y。
    • 是的,我明白了。当前驱动程序不支持在过滤器之前进行投影。即使支持,MongoDB 也不会表现良好,因为它无法在投影后应用索引。所以,你需要想出另一个解决方案。有一个方法封装你想要做的操作。不要使用谓词,而是调用方法 GetPeopleWithFirstName(string firstName) 并让您的 DAL 尽其所能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-09
    • 2014-12-04
    • 1970-01-01
    • 2021-05-22
    • 2020-11-28
    • 2022-01-27
    • 1970-01-01
    相关资源
    最近更新 更多