【问题标题】:MongoDB C# driver throwing an exception with LINQMongoDB C# 驱动程序使用 LINQ 引发异常
【发布时间】:2012-04-23 19:20:34
【问题描述】:

我正在构建一个使用 Mongo 和官方 C# 驱动程序的应用程序。使用接口和泛型类型约束时我遇到了一个奇怪的问题。考虑以下几点:

interface IMongoObject
{
    BsonObjectId Id { get; set; }
    string Name { get; set; }
}

class MongoObject : IMongoObject
{
    public BsonObjectId Id { get; set; }
    public string Name { get; set; }
}

class Program
{
    MongoServer m_db;
    string m_dbName;

    protected void Save<T>(T entity) where T : IMongoObject
    {
        GetDatabase().GetCollection<T>(typeof(T).Name).Save(entity);
    }

    protected T Get<T>(string name) where T : IMongoObject
    {
        Type t = typeof(T);

        // Throws
        return GetDatabase().GetCollection<T>(typeof(T).Name).AsQueryable().Where(o => o.Name == name).FirstOrDefault();
    }

    protected MongoDatabase GetDatabase()
    {
        if (m_db == null)
        {
            var conString = "mongodb://localhost/MongoTest";
            MongoUrl url = new MongoUrl(conString);
            m_dbName = url.DatabaseName;
            m_db = MongoServer.Create(url);
        }

        return m_db.GetDatabase(m_dbName);
    }

    void Run()
    {
        MongoObject o = new MongoObject();
        o.Name = "Foo";
        Save(o);

        MongoObject b = Get<MongoObject>("Foo");
        Console.ReadKey();
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }
}

除了对 Get(...) 的调用之外,一切正常。使用官方驱动程序,我从 SelectQuery.cs 中的函数 private BsonSerializationInfo GetSerializationInfoMember(IBsonSerializer serializer, MemberExpression memberExpression) 中的调用 var memberSerializationInfo = containingSerializationInfo.Serializer.GetMemberSerializationInfo(memberName); 中得到一个空引用异常。

如果我切换到使用 FluentMongo 进行 LINQ,我会收到一条消息说

“只能为类注册判别器,不能为接口 MyLib.Services.IRepoData 注册。”

这和这家伙基本一样:

FluentMongo throwing error all of a sudden

我知道 Mongo 驱动程序在抱怨,因为它不知道 IMongoObject 是什么。我不明白的是为什么 where 调用中的表达式将“o”视为 IMongoObject 类型而不是 MongoObject 类型(通过调试器确认这是正在发生的事情),就是这样。

如果我改用抽象基类,一切正常。我不知道该怎么做,因为不是所有的“MongoObjects”

谢谢

【问题讨论】:

    标签: c# mongodb fluent-mongo


    【解决方案1】:

    因此,问题实际上在于 C# 编译器如何将对象的表达式树组合在一起。由于您的类型约束,它在访问 Name 属性时将您的 MongoObject 转换为 IMongoObject。因此,IMongoObject 是表达式的类型,我们在 IMongoObject 上找不到任何成员。我会看看在下一个版本的驱动程序中我们是否可以针对这种情况做些什么,但现在,我会坚持使用抽象类。

    另外,最好不要将“域”对象与 DTO 混合。相反,有 2 个,每个职责一个,并在它们之间映射。

    --更新-- 有趣的笔记。显然,这是基于 VB.NET 创建表达式树的方式与 c# 不同的不同问题而得到修复的。因此,在不久的将来,这将正常工作。你可以在这里看到证明这一点的测试:https://github.com/craiggwilson/mongo-csharp-driver/commit/153b9862b122521eee681a86e56806d94fed8b21#diff-1

    【讨论】:

    • 非常感谢您的回复。当编译器清楚地知道 T 的实际类型并且 T 实现了 IMongoObject 时,编译器感觉需要转换为 IMongoObject 是很奇怪的。出于兴趣,我尝试在 T 转换为 (((MongoObject)(IMongoObject))o).Name 的表达式中添加一个明确的强制转换。有帮助;o)。 WRT 关注点分离,上面的代码只是演示问题的一个示例 - 实际代码有 2 个对象树,如您所建议的。我将密切关注修复的发布。谢谢。
    猜你喜欢
    • 2021-11-03
    • 2017-05-21
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多