MongoDb ID 生成器不工作
MongoDb id generator is not working
我有一个简单的需求generate string ID if field is null before inserting
。如果 属性 有名称 Id
,它工作正常,否则它没有。
我关注class:
public abstract class CampaignBase
{
[BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
[BsonRepresentation(BsonType.ObjectId)]
public string CampaignId { get; set; }
}
public class Campaign : CampaignBase {}
现在,当我在数据库中插入 MyData
时,我得到 null
而不是生成的 ID。似乎这些属性只是没有应用,因为如果 属性 有 Id
名称那么如果工作正常并且属性可以更改实际数据布局(string
/objectid
/等) .
我是这样保存的:
campaign
和campaignBase
引用的是同一个对象,不用介意。
其中更新选项:
protected static UpdateOptions UpdateOptions => new UpdateOptions
{
IsUpsert = true
};
这里是:null 到达:
我是不是漏掉了什么?
我只是将命令分解成它在做什么,而不是试图混淆问题:
var myItem = new MyItem() {Name = "Bob"};
if (myItem.MyId == null)
{
mongoCollection.InsertOne(myItem);
}
else
{
mongoCollection.ReplaceOne(x => x.MyId == myItem.MyId, myItem);
}
替换 null
的 ID 只会插入 null 作为文档的 _id
。
我得到了以下扩展:
public static void Save<T, TProperty>(this IMongoCollection<T> collection, T item, Expression<Func<T, TProperty>> idFunc) where TProperty : class
{
var id = idFunc.Compile()(item);
if (id == null)
{
collection.InsertOne(item);
}
else
{
var expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(idFunc.Body, Expression.Constant(id, typeof(TProperty))), idFunc.Parameters);
collection.ReplaceOne(expression, item);
}
}
示例用法:
CampaignsCollection.Save(campaign, c => c.CampaignId);
感谢@KevinSmith 的想法
这里的实现有点复杂,但它更灵活,由于缓存,它具有更好的客户端界面和性能
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);
}
}
一般情况下,如果Id
字段等于default(PropertyType)
,则插入一个项目,否则替换具有指定id的项目。
下面是我们如何使用它:
CampaignsCollection.Save(campaign);
这段代码为我们处理了一切。没有错误的无效 ID 列,没有额外输入,只是保存它,句点:)
我有一个简单的需求generate string ID if field is null before inserting
。如果 属性 有名称 Id
,它工作正常,否则它没有。
我关注class:
public abstract class CampaignBase
{
[BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
[BsonRepresentation(BsonType.ObjectId)]
public string CampaignId { get; set; }
}
public class Campaign : CampaignBase {}
现在,当我在数据库中插入 MyData
时,我得到 null
而不是生成的 ID。似乎这些属性只是没有应用,因为如果 属性 有 Id
名称那么如果工作正常并且属性可以更改实际数据布局(string
/objectid
/等) .
我是这样保存的:
campaign
和campaignBase
引用的是同一个对象,不用介意。
其中更新选项:
protected static UpdateOptions UpdateOptions => new UpdateOptions
{
IsUpsert = true
};
这里是:null 到达:
我是不是漏掉了什么?
我只是将命令分解成它在做什么,而不是试图混淆问题:
var myItem = new MyItem() {Name = "Bob"};
if (myItem.MyId == null)
{
mongoCollection.InsertOne(myItem);
}
else
{
mongoCollection.ReplaceOne(x => x.MyId == myItem.MyId, myItem);
}
替换 null
的 ID 只会插入 null 作为文档的 _id
。
我得到了以下扩展:
public static void Save<T, TProperty>(this IMongoCollection<T> collection, T item, Expression<Func<T, TProperty>> idFunc) where TProperty : class
{
var id = idFunc.Compile()(item);
if (id == null)
{
collection.InsertOne(item);
}
else
{
var expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(idFunc.Body, Expression.Constant(id, typeof(TProperty))), idFunc.Parameters);
collection.ReplaceOne(expression, item);
}
}
示例用法:
CampaignsCollection.Save(campaign, c => c.CampaignId);
感谢@KevinSmith 的想法
这里的实现有点复杂,但它更灵活,由于缓存,它具有更好的客户端界面和性能
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);
}
}
一般情况下,如果Id
字段等于default(PropertyType)
,则插入一个项目,否则替换具有指定id的项目。
下面是我们如何使用它:
CampaignsCollection.Save(campaign);
这段代码为我们处理了一切。没有错误的无效 ID 列,没有额外输入,只是保存它,句点:)