title: Ambiguous discriminator 'myType' when 'myType' is generated dynamically at run time
body: <p>I have an application which creates new types dynamically at run time, creates objects of that type and inserts them into a MongoDB database collection of type <code>object</code>. Using the shell I can see that the object is inserted correctly and the <code>_t</code> value is the correct name of the dynamically created class.</p>
  
  <p>I am trying to retrieve objects from my collection using <code>AsQueryable</code> while applying a LINQ query to filter the results to only objects of a specific type.</p>
  
  <p>This works fine:</p>
  
  <pre><code>_collection.AsQueryable&lt;object&gt;();
  </code></pre>
  
  <p>while this:</p>
  
  <pre><code>_collection.AsQueryable&lt;object&gt;().Where(t =&gt; t.GetType() == type);
  </code></pre>
  
  <p>throws the exception:</p>
  
  <pre><code>Ambiguous discriminator 'myType'
     at MongoDB.Bson.Serialization.BsonSerializer.LookupActualType(Type nominalType, BsonValue discriminator)
     at MongoDB.Bson.Serialization.Conventions.StandardDiscriminatorConvention.GetActualType(BsonReader bsonReader, Type nominalType)
     at MongoDB.Bson.Serialization.Serializers.ObjectSerializer.Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
     at MongoDB.Driver.Internal.MongoReplyMessage`1.ReadBodyFrom(BsonBuffer buffer)
     at MongoDB.Driver.Internal.MongoReplyMessage`1.ReadFrom(BsonBuffer buffer)
     at MongoDB.Driver.Internal.MongoConnection.ReceiveMessage[TDocument](BsonBinaryReaderSettings readerSettings, IBsonSerializer serializer, IBsonSerializationOptions serializationOptions)
     at MongoDB.Driver.Operations.QueryOperation`1.GetFirstBatch(IConnectionProvider connectionProvider)
     at MongoDB.Driver.Operations.QueryOperation`1.Execute(IConnectionProvider connectionProvider)
     at MongoDB.Driver.MongoCursor`1.GetEnumerator()
     at MongoDB.Driver.Linq.IdentityProjector`1.GetEnumerator()
     at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
     at MongoDB.Driver.Linq.SelectQuery.&lt;TranslateFirstOrSingle&gt;b__a(IEnumerable source)
     at MongoDB.Driver.Linq.SelectQuery.Execute()
     at MongoDB.Driver.Linq.MongoQueryProvider.Execute(Expression expression)
     at MongoDB.Driver.Linq.MongoQueryProvider.Execute[TResult](Expression expression)
     at System.Linq.Queryable.First[TSource](IQueryable`1 source)
     at MongoDBTest.Program.RetreiveTransaction(String transactionType, Int32 version) in c:\projects\mrp\trunk\Source\POC\MongoDBTest\MongoDBTest\Program.cs:line 192
     at MongoDBTest.Program.DynamicDBExample() in c:\projects\mrp\trunk\Source\POC\MongoDBTest\MongoDBTest\Program.cs:line 163
     at MongoDBTest.Program.Main(String[] args) in c:\projects\mrp\trunk\Source\POC\MongoDBTest\MongoDBTest\Program.cs:line 28
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
     at System.Threading.ThreadHelper.ThreadStart()
  </code></pre>
  
  <p>when the type is my dynamically generated type (it works fine for other types).</p>
  
  <p>Also this does work:</p>
  
  <pre><code>_collection.FindAs&lt;object&gt;(Query.EQ("_t", type.Name)).AsQueryable();
  </code></pre>
  
  <p>but unfortunately it returns all the documents of that type from the database and then any LINQ queries are performed locally instead of at the database, which is not what I want.</p>
  
  <hr>
  
  <p>Here is the code I am using to create types at run time:</p>
  
  <pre><code>public static Type CompileResultType(string className, Dictionary&lt;string, string&gt; fields)
  {
      TypeBuilder tb = GetTypeBuilder(className);
      ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
  
      foreach (var field in fields)
      {
          CreateProperty(tb, field.Key, Type.GetType(field.Value));
      }
  
      Type objectType = tb.CreateType();
      return objectType;
  }
  
  private static TypeBuilder GetTypeBuilder(string className)
  {
      var an = new AssemblyName("DynamicClassAssembly");
      AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
      ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
      TypeBuilder tb = moduleBuilder.DefineType("DynamicClassNamespace."+className
                          , TypeAttributes.Public |
                          TypeAttributes.Class |
                          TypeAttributes.AutoClass |
                          TypeAttributes.AnsiClass |
                          TypeAttributes.BeforeFieldInit |
                          TypeAttributes.AutoLayout
                          , null);
      return tb;
  }
  
  private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
  {
      FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
  
      PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
      MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
      ILGenerator getIl = getPropMthdBldr.GetILGenerator();
  
      getIl.Emit(OpCodes.Ldarg_0);
      getIl.Emit(OpCodes.Ldfld, fieldBuilder);
      getIl.Emit(OpCodes.Ret);
  
      MethodBuilder setPropMthdBldr =
          tb.DefineMethod("set_" + propertyName,
              MethodAttributes.Public |
              MethodAttributes.SpecialName |
              MethodAttributes.HideBySig,
              null, new[] { propertyType });
  
      ILGenerator setIl = setPropMthdBldr.GetILGenerator();
      Label modifyProperty = setIl.DefineLabel();
      Label exitSet = setIl.DefineLabel();
  
      setIl.MarkLabel(modifyProperty);
      setIl.Emit(OpCodes.Ldarg_0);
      setIl.Emit(OpCodes.Ldarg_1);
      setIl.Emit(OpCodes.Stfld, fieldBuilder);
  
      setIl.Emit(OpCodes.Nop);
      setIl.MarkLabel(exitSet);
      setIl.Emit(OpCodes.Ret);
  
      propertyBuilder.SetGetMethod(getPropMthdBldr);
      propertyBuilder.SetSetMethod(setPropMthdBldr);
  }
  </code></pre>
  
  <hr>
  
  <p>Full code that exhibits this behavior:</p>
  
  <pre><code>static void ProcessTransaction(IncomingTransaction input, string transactionType, int version)
  {
      var configuration = GetConfiguration(transactionType, version);
  
      //configuration.Fields is just a Dictionary of field names -&gt; types
      Type dynamicType = DynamicClassHelper.CompileResultType(transactionType + version, configuration.Fields);
  
      object transaction = Activator.CreateInstance(dynamicType);
  
      //AutoMapper, just populates the data on transaction object
      Mapper.DynamicMap(input, transaction, typeof(IncomingTransaction), transaction.GetType());
  
      //Just a wrapper around MongoDB, creates a MongoCollection&lt;object&gt;
      var db = new MongoTransactionDB&lt;object&gt;(connectionString, databaseName, "transactions", new ConsoleLogger());
  
      //just calls Insert() on the collection
      db.AddTransaction(transaction);
  }
  
  static void RetreiveTransaction(string transactionType, int version)
  {
      var db = new MongoTransactionDB&lt;object&gt;(connectionString, databaseName, "transactions", new ConsoleLogger());
  
      var config = GetConfiguration(transactionType, version);
  
      Type dynamicType = DynamicClassHelper.CompileResultType(transactionType + version, config.Fields);
  
      //!!! This is where the exception is thrown !!!
      var result = db.GetAllTransactionsOfType(dynamicType).First();
  }
  
  //From MongoTransactionDB class...
  public IQueryable&lt;TTransactionBase&gt; GetAllTransactionsOfType(Type type)
  {
      return _collection.AsQueryable().Where(t =&gt; t.GetType() == type);
  }
  </code></pre>
  
  <p>Result after inserting the dynamic object into MongoDB (<code>transactionType = "Cash"</code> and <code>version = 1</code>):</p>
  
  <p><img src="https://i.stack.imgur.com/mt5yE.png" alt="enter image description here"></p>