C#和#x2B;MongoDB-不使用MongoDB数据类型/属性的ObjectId

C#和#x2B;MongoDB-不使用MongoDB数据类型/属性的ObjectId,c#,mongodb,inversion-of-control,C#,Mongodb,Inversion Of Control,使用MongoDB作为数据存储使我在默认情况下将ObjectID类型作为主键。也可以通过使用带有[BsonId]属性的Guid来更改它。它也在MongoDB C#驱动程序库中定义。我希望我的实体独立于数据层。 我可以只使用属性的名称Id来标识主键吗?我还可以尝试什么?选项1:坚持使用BsonId并使用Facade模式 [BsonId]属性用于指示_id属性应链接到特定属性。没有办法解决这个问题(除非在crud操作中完全忽略id,这似乎是个坏主意) 因此,如果您想将“实体”对象与“数据层”分离,那

使用MongoDB作为数据存储使我在默认情况下将ObjectID类型作为主键。也可以通过使用带有[BsonId]属性的Guid来更改它。它也在MongoDB C#驱动程序库中定义。我希望我的实体独立于数据层。 我可以只使用属性的名称Id来标识主键吗?我还可以尝试什么?

选项1:坚持使用BsonId并使用Facade模式 [BsonId]属性用于指示_id属性应链接到特定属性。没有办法解决这个问题(除非在crud操作中完全忽略id,这似乎是个坏主意)

因此,如果您想将“实体”对象与“数据层”分离,那么只需使用poco类即可

--使用a替代记录。该类仅用于数据存储:一种快速获取mongo数据的方法,也是处理bson文档的最佳替代方法

——在实体层的poco类顶部使用一个facade。我觉得重新发明轮子没有什么用处,所以我通常会要求我们的开发人员让实体接口继承数据层(poco)接口,但您可以按照自己的意愿来做

分解示例MyObject类 IMyObjectRecord(在dal声明,仅包含属性和mongo特定属性)

IMyObject:IMyObjectRecord(在实体级别声明,可能包括添加的属性和方法)

MyObjectRecord:IMyObjectRecord(在dal内部声明,包含mongo特定的属性。如果您想严格区分,可以将其声明为内部)

MyObject:IMyObject(例如,可以是从dal中提取的IMyObjectRecord类顶部的外观)

现在,您获得了facade的所有好处,并且在属性之间有一个硬编码链接,但是,您可以在dal中保留Bson属性

好的。但我真的很讨厌这个答案。 嗯。我可以接受好的,那么使用约定包怎么样?如果您绝对承诺将调用您的Id的“Id”,并发誓将它们作为字符串键入(或者——使用其他易于识别的约定),那么我们可以使用约定包

名称空间控制台{
班级计划{
私家班{
//看,妈!没有属性!
公共字符串Id{get;set;}
公共字符串OtherProperty{get;set;}
}
静态void Main(字符串[]参数){
//您通常会在使用的单例例程中执行此操作
//要创建dbClient,只需执行一次。
var pack=新约定包();
pack.Add(新的StringObjectedConvention());
Register(“MyConventions”,pack,=>true);
//请注意,在创建客户端之前,我们已注册。。。
var client=new MongoClient();
//现在,使用该客户端创建集合
var testDb=client.GetDatabase(“test”);
var fooCol=testDb.GetCollection(“foo”);
InsertOne(新的Foo(){OtherProperty=“Testing”,Id=“TEST”});
var foundFoo=fooCol.Find(x=>x.OtherProperty==“Testing”).ToList()[0];
Console.WriteLine(“foundFooId:+foundFoo.Id”);
}
//显然,这属于单一名称空间,其中
//你得到了你的数据库客户端。
私有类StringObjectedConvention:ConventionBase、IPostProcessingConvention{
公共void后处理(BsonClassMap类映射){
var idMap=classMap.IdMemberMap;
if(idMap!=null&&idMap.MemberName==“Id”&&idMap.MemberType==typeof(字符串)){
SetIdGenerator(新的StringObjectiveGenerator());
}
}
}
}
}
什么是会议包 这是一组在序列化/反序列化期间应用的mongo“规则”。您只需注册一次(在设置引擎时)。在本例中,示例包告诉mongo“如果您看到一个名为'Id'的字段,请将其保存为字符串到_Id。”

这些会变得非常复杂和有趣。如果你真的讨厌另一种方法,我会深入研究会议包。这是一种将所有mongo“属性驱动”逻辑强制放到一个自包含位置的好方法。

您可以使用而不是使用属性来保持类“干净”

/“clean”实体,不带mongo属性
公共类MyClass
{
公共Guid Id{get;set;}
}
//数据层中的映射
BsonClassMap.RegisterClassMap(cm=>
{
cm.AutoMap();
cm.MapIdMember(c=>c.Id).SetIdGenerator(combguidgeGenerator.Instance);
});

我自己也遇到了同样的问题,我不想在类中包含mongo属性

我创建了一个小包装器示例,以展示如何保存和查找元素,而不必在业务逻辑的数据类上使用Id属性

包装器类:

public static class Extensions
{
    public static T Unwrap<T>(this MongoObject<T> t)
    {
        return t.Element;
    }
}
public class MongoObject<T>
{
    [BsonId]
    private ObjectId _objectId;
    public T Element { get; }

    public MongoObject(T element)
    {
        Element = element;
        _objectId = new ObjectId();
    }
}
那么我们就可以通过

 public Person FindPersonByName(string name)
 {
     return _collection.AsQueryable().FirstOrDefault(
               personObject => personObject.Element.Name == name).Unwrap();
 }

我们还可以通过使
MongoObject
实现
IQueryable
来进行概括,如果我理解正确,这将使包装器的使用更加方便。您希望将实体放置到没有属性的其他层

我想你可以试试这个

 public object Id { get; set; }

在此之后,您可以将来自mongodb的Id放入,而不带属性

嘿,Peter-这只适用于一个类,对吗?它只适用于我的班级?所以OP需要为他添加到数据访问层的每个新类添加一个新的类映射。@bri-对,很好的观点-这就是如何流畅地映射单个类。您建议使用
ConventionPack
是一个很好的例子,说明了如何定义映射所有
Idpublic void Save<T>(T t)
{
    _collection.InsertOne(new MongoObject<T>(t));
}
public class Person
{
    public string Name { get; set; }
}
 public Person FindPersonByName(string name)
 {
     return _collection.AsQueryable().FirstOrDefault(
               personObject => personObject.Element.Name == name).Unwrap();
 }
 public object Id { get; set; }