您的位置:首页 > 数据库 > Mongodb

扩展MongoDB C# Driver的QueryBuilder

2017-05-11 11:39 423 查看
扩展MongoDB C# Driver的QueryBuilder

因为不想直接hardcode "ClassA.MemberA.MemberB" 这种字符串 。写了下面几个类,用于下面经常使用的场景:
1. 表达式转换成字符串函数: ExpToStr()
2. Collection函数:当有集合成员时,能够使用此类,将返回QueryCollection对象,这个类的代码之后附上
3. CollectionAs函数:当使用了继承。希望将基类转换为子类并返回子类的QueryCollection

使用演示样例:

//获得表达式的字符串形式
1. QueryEx<ClassA>.ExpToStr ((ClassA m)=> m.MemberA.MemberB.MemberC)

//集合.成员.字段
//PoppedSegments为集合,AssignedNetwork.Name为成员
//将返回PoppedSegments.AssignedNetwork.Name
2. QueryEx<MDDelivery>.Collection(x => x.PoppedSegments).Matches(p => p.AssignedNetwork.Name, bsonRegex),

//子类集合.成员.字段
//STPaymentTransaction为基类,STPaymentCompanyCredit为子类,Company字段在子类中
//将返回Payments.Company.Name
3. QueryEx<MDDelivery>.CollectionAs<STPaymentTransaction, STPaymentCompanyCredit>(x=>x.Payments).Matches(p=>p.Company.Name, bsonRegex)

//集合.集合.成员.字段
//Parcels为集合,STCustomPropertyRuntime为基类,STNumericPropertyRuntime为子类,CustomProps为STNumericPropertyRuntime中成员,Value为CustomProp中成员
//将返回Parcels.CustomProps.Value
4. QueryEx<MDDelivery>.Collection(x=>x.Parcels).CollectionMemberAs<STCustomPropertyRuntime, STNumericPropertyRuntime>(p=>p.CustomProps).Matches(p=>p.Value, bsonRegex),


实现代码:

public class QueryEx<TDocument>
{
public static QueryCollection<TDocument, TCollection> Collection<TCollection>(
Expression<Func<TDocument, IEnumerable<TCollection>>> collectionExpression)
{
return new QueryCollection<TDocument, TCollection>(collectionExpression);
}

//for those cases using inheritance
//e.g STPaymentTransaction
//Payments will return STPaymentTransaction
//need to cast to sub classes(STPaymentCompanyCredit) so that be able to filter by child members (e.g. Company)
public static QueryCollection<TDocument, TSub> CollectionAs<TCollection, TSub>(
Expression<Func<TDocument, IEnumerable<TCollection>>> collectionExpression)
where TSub : TCollection
{
var argParam = Expression.Parameter(typeof (TDocument), "x");
var memberStr = ExpToStr(collectionExpression);
MemberExpression nameProperty = Expression.Property(argParam, memberStr);

var subExp = Expression.Convert(nameProperty, typeof(IEnumerable<TSub>));

var exp = Expression.Lambda<Func<TDocument, IEnumerable<TSub>>>(
subExp,
argParam);

return new QueryCollection<TDocument, TSub>(exp);
}

/// <summary>
/// return string value for a expression:
/// for s.Name.Val1.Val2 will return Name.Val1.Val2
/// </summary>
/// <typeparam name="MDClass"></typeparam>
/// <typeparam name="Member"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
public static string ExpToStr<TDocument, Member>(Expression<Func<TDocument, Member>> exp)
{
return new QueryExpressionHelper().MemberExpression(exp);
}
}

public class QueryCollection<TDocument, TCollection>
{
private readonly QueryExpressionHelper _queryExpression;
private string _collectionName;

public string Context
{
get { return _collectionName; }
}

public QueryCollection(Expression<Func<TDocument, IEnumerable<TCollection>>> collectionExpression)
{
_queryExpression = new QueryExpressionHelper();
_collectionName = _queryExpression.MemberExpression(collectionExpression);
}

public QueryMember<TCollection, TMember> Member<TMember>(Expression<Func<TCollection, TMember>> exp)
{
var expStr = QueryEx<TCollection>.ExpToStr(exp);
var context = string.Format("{0}.{1}", _collectionName, expStr);
var obj = new QueryMember<TCollection, TMember>(context);

return obj;
}

public QueryCollection<TCollection, TMember> CollectionMember<TMember>(
Expression<Func<TCollection, IEnumerable<TMember>>> exp)
{
var expStr = QueryEx<TCollection>.ExpToStr(exp);
var obj = new QueryCollection<TCollection, TMember>(exp)
{
_collectionName = string.Format("{0}.{1}", _collectionName, expStr)
};

return obj;
}

/// <summary>
/// this method only support 1 layer nested(not for Query Collection.Collection , but for Collection.Member)
/// if member is collection and need convert to sub class
/// </summary>
/// <typeparam name="TMember">Base Type</typeparam>
/// <typeparam name="TMemberSub">Child Class Type</typeparam>
/// <param name="collectionExpression"></param>
/// <returns></returns>
public QueryCollection<TCollection, TMemberSub> CollectionMemberAs<TMember, TMemberSub>(
Expression<Func<TCollection, IEnumerable<TMember>>> collectionExpression)
where TMemberSub : TMember
{
var obj = QueryEx<TCollection>.CollectionAs<TMember, TMemberSub>(collectionExpression);
obj._collectionName = string.Format("{0}.{1}", _collectionName, obj._collectionName);

return obj;
}

public IMongoQuery LT<TMember>(Expression<Func<TCollection, TMember>> memberExpression, TMember value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.LT(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery LT<TValue>(Expression<Func<TCollection, IEnumerable<TValue>>> memberExpression, TValue value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.LT(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery EQ<TMember>(Expression<Func<TCollection, TMember>> memberExpression, TMember value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.EQ(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery EQ<TValue>(Expression<Func<TCollection, IEnumerable<TValue>>> memberExpression, TValue value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.EQ(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery NE<TMember>(Expression<Func<TCollection, TMember>> memberExpression, TMember value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.NE(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery NE<TValue>(Expression<Func<TCollection, IEnumerable<TValue>>> memberExpression, TValue value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.NE(string.Format("{0}.{1}", _collectionName, memberName), BsonValue.Create(value));
}

public IMongoQuery In<TMember>(Expression<Func<TCollection, TMember>> memberExpression, params TMember[] values)
{
return In<TMember>(memberExpression, new List<TMember>(values));
}

public IMongoQuery In<TMember>(Expression<Func<TCollection, TMember>> memberExpression,
IEnumerable<TMember> values)
{
var memberName = _queryExpression.MemberExpression(memberExpression);
return Query.In(string.Format("{0}.{1}", _collectionName, memberName), values.Select(x => BsonValue.Create(x)));
}

public IMongoQuery In<TCastC, TMember>(Expression<Func<TCastC, TMember>> memberExpression,
IEnumerable<TMember> values) where TCastC : TCollection
{
var memberName = _queryExpression.MemberExpression(memberExpression);
return Query.In(string.Format("{0}.{1}", _collectionName, memberName), values.Select(x => BsonValue.Create(x)));
}

public IMongoQuery In<TValue>(Expression<Func<TCollection, IEnumerable<TValue>>> memberExpression, IEnumerable<TValue> values)
{
var memberName = _queryExpression.MemberExpression(memberExpression);
return Query.In(string.Format("{0}.{1}", _collectionName, memberName), values.Select(x => BsonValue.Create(x)));
}

public IMongoQuery In<TCastC, TValue>(Expression<Func<TCastC, IEnumerable<TValue>>> memberExpression, IEnumerable<TValue> values) where TCastC : TCollection
{
var memberName = _queryExpression.MemberExpression(memberExpression);
return Query.In(string.Format("{0}.{1}", _collectionName, memberName), values.Select(x => BsonValue.Create(x)));
}

public IMongoQuery Matches<TMember>(Expression<Func<TCollection, TMember>> memberExpression, BsonRegularExpression value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.Matches(string.Format("{0}.{1}", _collectionName, memberName), value);
}

public IMongoQuery Matches<TValue>(Expression<Func<TCollection, IEnumerable<TValue>>> memberExpression, BsonRegularExpression value)
{
var memberName = _queryExpression.MemberExpression(memberExpression);

return Query.Matches(string.Format("{0}.{1}", _collectionName, memberName), value);
}
}

public class QueryMember<TDocument, TCollection>
{
private readonly QueryExpressionHelper _queryExpression;
private string _collectionName;

public string Context
{
get { return _collectionName; }
}

public QueryMember(Expression<Func<TDocument, TCollection>> exp)
{
_queryExpression = new QueryExpressionHelper();
_collectionName = _queryExpression.MemberExpression(exp);
}

public QueryMember(string context)
{
_collectionName = context;
}

}

public class QueryExpressionHelper
{
public string Context;

public string MemberExpression<TMember>(Expression<TMember> expression)
{
MemberExpression me;
switch (expression.Body.NodeType)
{
case ExpressionType.MemberAccess:
me = expression.Body as MemberExpression;
break;
case ExpressionType.Convert:
dynamic convertedBody = expression.Body;
me = convertedBody.Operand as MemberExpression;
break;

default:
throw new NotSupportedException(string.Format("Member with node type {0} is not supported. expression {1}", expression.Body.NodeType, expression));
}
var stack = new Stack<string>();

while (me != null)
{
stack.Push(me.Member.Name);
me = me.Expression as MemberExpression;
}

var expStr = string.Join(".", stack.ToArray());
return expStr;

}
}

public static class QueryMoney
{
public static IMongoQuery Value(string name, double val)
{
var accuracy = 0.005;

return Query.And(
Query.LT(name, new BsonDouble(val + accuracy)),
Query.GT(name, new BsonDouble(val - accuracy)));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: