C# 如何制作整数Id生成器?
众所周知,mongoDb默认驱动程序不支持自动生成整数Id。 我花了两天时间思考如何实现我自己的唯一整数值id生成器。 那么,如何制作呢?类似的东西:C# 如何制作整数Id生成器?,c#,mongodb,C#,Mongodb,众所周知,mongoDb默认驱动程序不支持自动生成整数Id。 我花了两天时间思考如何实现我自己的唯一整数值id生成器。 那么,如何制作呢?类似的东西: public class UniqueIntGenerator : IIdGenerator { private static UniqueIntGenerator _instance; public static UniqueIntGenerator Instance { get { return _instance; } }
public class UniqueIntGenerator : IIdGenerator
{
private static UniqueIntGenerator _instance;
public static UniqueIntGenerator Instance { get { return _instance; } }
static UniqueIntGenerator()
{
_instance = new UniqueIntGenerator();
}
public object GenerateId(object container, object document)
{
var cont = container as MongoCollection;
if (cont == null)
return 0;
var type = cont.Settings.DefaultDocumentType;
var cursor = cont.FindAllAs(type);
cursor.SetSortOrder(SortBy.Descending("_id"));
cursor.Limit = 1;
foreach (var obj in cursor)
return GetId(obj) + 1;
return 1;
}
private int GetId(object obj)
{
var properties = obj.GetType().GetProperties();
var idProperty = properties.Single(y => y.GetCustomAttributes(typeof(BsonIdAttribute), false).SingleOrDefault() != null);
var idValue = (int)idProperty.GetValue(obj, null);
return idValue;
}
public bool IsEmpty(object id)
{
return default(int) == (int)id;
}
}
在MongoDB中生成自动增量Id不是一个好的做法,因为我会在扩展服务器时伤害到您,但是如果您想要生成自动增量值,则不建议迭代集合,而是创建一个单独的表(类似于序列的概念),从表中读取值,然后使用findAndModify对其进行增量。每个表都是唯一的
> db.counters.insert({_id: "userId", c: 0});
> var o = db.counters.findAndModify(
... {query: {_id: "userId"}, update: {$inc: {c: 1}}});
{ "_id" : "userId", "c" : 0 }
> db.mycollection.insert({_id:o.c, stuff:"abc"});
> o = db.counters.findAndModify(
... {query: {_id: "userId"}, update: {$inc: {c: 1}}});
{ "_id" : "userId", "c" : 1 }
> db.mycollection.insert({_id:o.c, stuff:"another one"});
我将使用GUID作为主键,而不是整数。 它主要有两个好处
- 它是线程安全的
- 您不必担心计算下一个ID
- 获取新ID所需的代码非常简单 Guid.NewGuid()
在CodingHorror中检查这个有用的选项,它解释了使用GUID而不是传统整数id的优缺点。一个迟来的答案,但我想我会发布以下内容: 我启动了一个增量ID生成器。
注意——这远远不是理想的,也不是mongodb的初衷 如果不是必需的整数,您可能希望使用GUID作为快速解决方案…@cad:更好的快速解决方案是顺序整数:0,1,2,…不使用
http://www.mongodb.org/display/DOCS/Object+IDs
您是否看过关于customId generator的讨论http://stackoverflow.com/questions/6855084/c-sharp-generate-identity-like-ids-with-nosql-mongodb
@vlad:不确定是否更好。顺序的重点是学习下一个数字。。。通常情况下,这不是线程安全的(可能使用单例可以使其安全),另一方面,GUID可能会有一些问题。如果您有时间查看codinghoror:@cad中的这篇很酷的文章:如果线程安全是一个问题,可以使用锁来保护生成器。如果guid是线程安全的,它们也会这样做。我不熟悉MongoDb,但是:为什么总是将参数作为对象s进行转换?即使是线程安全的,它也不能与多个web服务器一起工作。@Vlad,因为IdGenerator对于许多集合都是通用的。所以方法GenerateId接受对象类型的参数。我发现没有办法获得find item的Id属性。这种方法存在大量并发问题。几乎同时插入的两个文档很容易具有相同的id,这可能会导致崩溃和数据损坏。但我不明白为什么使用另一个集合存储当前最大id不会影响服务器的扩展也是有害的,只是它比迭代整个集合更快更重要的是,此方法是原子的。对整个集合进行迭代是不正确的。这会影响扩展,因为现在需要两个服务器调用来插入记录(一个用于获取生成的ID,另一个用于插入记录)。但在一个典型的事务系统中,这一点并不多见。如果您有流式插入,比如日志记录或检测系统,那么这额外的开销可能会限制IO,尽管.MSSQL确实支持GUI。不使用GUID的一个重要原因是GUID通常是均匀分布的,这将导致使用b树的可怕的索引碎片。如果必须使用GUID,请确保使用具有顺序生成算法的GUID。ObjectID是按顺序生成的。如果不能直接使用Objd,请考虑使用Objutd的字符串形式。这至少不会导致索引碎片。@cad:而且,均匀分布的数据是最糟糕的事情,因为您需要调整磁盘上每个块的大小。对于磁盘上的数据结构,碎片是敌人。顺序ID(各种类型)更好,因为B-树只需要在末尾插入,而存储桶永远不需要拆分:它们可以被写入,直到填满为止,然后可以创建一个全新的存储桶并添加到树的末尾。GUID占用更多的磁盘空间(通过增加记录大小)和更多的搜索计算时间,比较和排序(有16个字节,而不是Int32的4个字节)。此外,顺序ID更易于人类查看、查询和理解:通过查看查询工具、Excel或类似工具中的数据,可以完成数量惊人的工作。大多数人可以立即发现5位或6位数字之间的差异,但是guid需要花费一些精力来处理。我们在工作中的一些表格中使用guid作为pk,它们让我发疯。