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

本文关键字:MongoDB 属性 数据类型 ObjectId | 更新日期: 2023-09-27 18:30:30

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

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

您可以使用

BsonClassMap 而不是使用属性来保持类"干净"。

// 'clean' entity with no mongo attributes
public class MyClass 
{
    public Guid Id { get; set; }
}
// mappings in data layer
BsonClassMap.RegisterClassMap<MyClass>(cm => 
{
    cm.AutoMap();
    cm.MapIdMember(c => c.Id).SetIdGenerator(CombGuidGenerator.Instance);
});

选项 1:坚持使用 BsonId 并使用外观模式

[BsonId] 属性用于指示_id属性应链接到特定属性。 没有办法解决这个问题(除了在你的 crud 操作中完全忽略_id这似乎是一个坏主意)。

因此,如果您想将"实体"对象与"数据层"分开,则只需使用 poco 类即可。

-- 使用 poco 类作为记录的替代品。 该类仅用于数据存储:一种将数据传入/传出 mongo 的快速方法,也是处理 bson 文档的绝佳替代方案。

-- 在实体层的 poco 类之上使用立面。 我觉得重新发明轮子没有用,所以我通常会要求我们的开发人员让实体接口继承数据层 (poco) 接口,但你可以随

心所欲地做

分解示例 MyObject 类

IMyObjectRecord(在 dal 处声明,仅包含属性和 mongo 特定属性)

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

MyObjectRecord:IMyObjectRecord(在 dal 中声明,包含特定于 mongo 的属性。 如果你想对分离非常严格,可以声明为内部)。

MyObject:IMyObject(例如,可以是你从 dal 中提取的 IMyObjectRecord 类顶部的立面)。

现在 - 您可以获得立面的所有好处,并且属性之间有一个硬编码链接,但是,您可以将 Bson 属性包含在您的 dal 中。

好的

,好的。但我真的非常讨厌这个答案。

是的。 我可以接受。 好的,那么公约包怎么样? 如果你绝对承诺你会调用你的ID的"Id",并且你发誓你会把它们键入为字符串(或者 - 使用其他一些易于识别的约定),那么我们可以使用一个约定包,就像我从这里偷来的那个一样

namespace ConsoleApp {
    class Program {
        private class Foo {
            // Look Ma!  No attributes!
            public string Id { get; set; }
            public string OtherProperty { get; set; }
        }
        static void Main(string[] args) {
            //you would typically do this in the singleton routine you use 
            //to create your dbClient, so you only do it the one time.
            var pack = new ConventionPack();   
            pack.Add(new StringObjectIdConvention());
            ConventionRegistry.Register("MyConventions", pack, _ => true);
            // Note that we registered that before creating our client...
            var client = new MongoClient();
            //now, use that client to create collections
            var testDb = client.GetDatabase("test");
            var fooCol = testDb.GetCollection<Foo>("foo");
            fooCol.InsertOne(new Foo() { OtherProperty = "Testing", Id="TEST" });
            var foundFoo = fooCol.Find(x => x.OtherProperty == "Testing").ToList()[0];
            Console.WriteLine("foundFooId: " + foundFoo.Id);
       }
        //obviously, this belongs in that singleton namespace where
        //you're getting your db client.
        private class StringObjectIdConvention : ConventionBase, IPostProcessingConvention {
            public void PostProcess(BsonClassMap classMap) {
                var idMap = classMap.IdMemberMap;
                if (idMap != null && idMap.MemberName == "Id" && idMap.MemberType == typeof(string)) {
                    idMap.SetIdGenerator(new StringObjectIdGenerator());
                }
            }
        }
    }
}

什么是公约包

这是在序列化/反序列化期间应用的一小部分 mongo "规则"。 您只需注册一次(在设置引擎时)。 在这种情况下,示例包告诉 mongo"如果您看到一个名为'Id'的字段,请将其保存为字符串以_id。

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

我自己偶然发现了同样的问题,我不想在我的类中有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 void Save<T>(T t)
{
    _collection.InsertOne(new MongoObject<T>(t));
}

要查找一个元素,我们可以执行类似 linq 的查询:

假设我们有一个数据类:

public class Person
{
    public string Name { get; set; }
}

那么我们可以通过以下公式找到这样的元素

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

我们还可以通过使MongoObject实现IQueryable<T>来概括,这将使包装器的使用更加方便

如果我理解正确的话。您希望将实体放入没有属性的其他图层。

我想你可以试试这个

 public object Id { get; set; }

之后,您可以将来自mongodb的ID放在没有属性的情况下