MongoDB C# 驱动程序使用 LINQ 引发异常

本文关键字:异常 LINQ 驱动程序 MongoDB | 更新日期: 2023-09-27 18:32:10

我正在构建一个使用 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 for LINQ,我会收到一条消息,指出

"鉴别器只能注册为类,不能注册接口MyLib.Services.IRepoData。

这和这家伙基本一样:

流利的蒙戈突然投掷错误

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

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

谢谢

MongoDB C# 驱动程序使用 LINQ 引发异常

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

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

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