Last active
December 15, 2017 13:27
-
-
Save Pzixel/a16e0ded2204c84fb057480f704548a6 to your computer and use it in GitHub Desktop.
Mongo extension class that provide old provider Save functionallity (like CampaignsCollection.Save(campaign); )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using MongoDB.Bson; | |
using MongoDB.Bson.Serialization.Attributes; | |
using MongoDB.Driver; | |
using MongoDB.Driver.Core.Bindings; | |
using MongoDB.Driver.Core.Operations; | |
namespace XXX | |
{ | |
public static class MongoExtensions | |
{ | |
public static void Save<T>(this IMongoCollection<T> collection, T item) | |
{ | |
if (item == null) | |
throw new ArgumentNullException(nameof(item)); | |
if (MongoSaveCommandHelper<T>.ShouldInsert(item)) | |
{ | |
collection.InsertOne(item); | |
} | |
else | |
{ | |
var expression = MongoSaveCommandHelper<T>.GetIdEqualityExpression(item); | |
collection.ReplaceOne(expression, item); | |
} | |
} | |
private static class MongoSaveCommandHelper<T> | |
{ | |
private static readonly Expression<Func<T, bool>> IdIsEqualToDefaultExpression; | |
private static readonly Func<T, object> GetId; | |
public static Func<T, bool> ShouldInsert { get; } | |
static MongoSaveCommandHelper() | |
{ | |
var members = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public); | |
var idProperty = members.SingleOrDefault(x => x.IsDefined(typeof(BsonIdAttribute))) | |
?? members.FirstOrDefault(m => m.Name.Equals("id", StringComparison.OrdinalIgnoreCase)); | |
if (idProperty == null) | |
throw new InvalidOperationException("Id property has not found"); | |
var idPropertyType = idProperty.PropertyType; | |
var parameter = Expression.Parameter(typeof(T)); | |
var idPropertyAccess = Expression.MakeMemberAccess(parameter, idProperty); | |
var getIdFuncExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(idPropertyAccess, typeof(object)), parameter); | |
GetId = getIdFuncExpression.Compile(); | |
IdIsEqualToDefaultExpression = Expression.Lambda<Func<T, bool>>(Expression.Equal(idPropertyAccess, Expression.Default(idPropertyType)), getIdFuncExpression.Parameters); | |
ShouldInsert = IdIsEqualToDefaultExpression.Compile(); | |
} | |
public static Expression<Func<T, bool>> GetIdEqualityExpression(T item) => | |
(Expression<Func<T, bool>>)new IdConstantVisitor(GetId(item)).Visit(IdIsEqualToDefaultExpression); | |
} | |
private class IdConstantVisitor : ExpressionVisitor | |
{ | |
private readonly object _value; | |
public IdConstantVisitor(object value) => _value = value; | |
protected override Expression VisitDefault(DefaultExpression node) => Expression.Constant(_value, node.Type); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment