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

问题描述 投票:4回答:4

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

c# mongodb inversion-of-control
4个回答
4
投票

选项1:坚持使用BsonId并使用Facade Pattern

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

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

- 使用poco class代替记录。该类仅用于数据存储:快速获取/输出mongo的数据,以及使用bson文档的绝佳替代方法。

- 在poco类的顶部使用外观作为实体层。我发现重新发明轮子没有用,所以我通常会问我们的开发人员有实体接口继承数据层(poco)界面,但是你可以这样做但是你喜欢

分解示例MyObject类

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

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

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

MyObject:IMyObject(例如,可以是从dal拉出的IMyObjectRecord类之上的外观)。

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

好的。但我真的很讨厌这个答案。

是啊。我可以接受。好的,那么约会呢?如果你绝对承诺你会称你的Id为“Id”并且你想要将它们键入字符串(或者 - 使用其他易于识别的约定),那么我们可以使用一个约定包like the one I stole from here

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“属性驱动”逻辑强制转换为一个自包含位置的好方法。


8
投票

您可以使用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
投票

我自己偶然发现了同样的问题,我不想在我的课程中使用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>来概括,这将使包装器的使用更加方便


1
投票

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

我想你可以尝试一下

 public object Id { get; set; }

在那之后你可以把你的Id来自mongodb没有属性

© www.soinside.com 2019 - 2024. All rights reserved.