2012-04-23 55 views
1

我正在构建一个使用Mongo和官方C#驱动程序的应用程序。我在使用接口和泛型类型约束时遇到了一个奇怪的问题。考虑以下内容:MongoDB C#驱动程序抛出与LINQ的异常

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

据我所知,蒙哥司机抱怨,因为它不知道IMongoObject是什么。我不明白的是,为什么表达式内的where调用将“o”看作类型为IMongoObject的类型不是MongoObject类型(用调试器确认这是发生了什么),这就是它的原因。

如果我切换到使用抽象基类,它一切正常。我不该做什么这一点,因为不是所有的“MongoObjects”

感谢

回答

0

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

另外,最好不要将你的“域”对象与你的DTO混合使用。相反,有2个,每个责任和地图之间有一个。

--UPDATE - 有趣的音符。显然,这已经被固定在一个不同的问题上,VB.NET如何创建与C#不同的表达式树。所以,在不久的将来,这将会正常工作。您可以在这里看到测试证明:https://github.com/craiggwilson/mongo-csharp-driver/commit/153b9862b122521eee681a86e56806d94fed8b21#diff-1

+0

非常感谢您的答复。它奇怪的是,当它明确知道T的实际类型并且T实现IMongoObject时,编译器觉得需要转换为IMongoObject。出于兴趣,我尝试向T转换为(((MongoObject)(IMongoObject))o).Name的表达式添加一个明确的转换。有帮助; o)。 WRT分离问题,上面的代码只是一个演示问题的例子 - 实际代码有2个对象树,正如你所建议的那样。我会密切关注修复的发布。谢谢。 – didster 2012-04-25 06:51:12

相关问题