2012-04-23 54 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

相關問題