10gen driver: inserts do not add _t property, yet my queries always expect it

650 views
Skip to first unread message

Vaevictus

unread,
Mar 1, 2011, 12:54:57 PM3/1/11
to mongodb-csharp
Hi,

I've had some great help so far from this group so first thanks for
that :)

Here is how I am generating a query, I am using query by example and
reflection:

private static QueryDocument
buildQueryDocumentFromObjectTemplate(object template)
{
var query = new QueryDocument();

Type t = template.GetType();
PropertyInfo[] allProperties = t.GetProperties();
//loop through the template object and foreach non-null
property add it to the query
foreach (PropertyInfo p in allProperties)
{

//if it's a storage ignore property, ignore it
if
(p.GetCustomAttributes(typeof(Storage.Attributes.StorageIgnoreAttribute),
false).Count() > 0)
continue;
if (p.GetCustomAttributes(typeof(BsonIgnoreAttribute),
false).Count() > 0)
continue;
MethodInfo methodInf = p.GetGetMethod();

if (methodInf != null)
{
if (methodInf.IsStatic)
continue;
}

//is not an ignored property
object propertyValue = p.GetValue(template, null);
if (!IsNullOrDefault(propertyValue))
{

try
{

var value = p.GetValue(template, null);
BsonValue bsonValue;
bsonValue = BsonDocument.Wrap(value); //I
THINK THIS IS THE PROBLEM WHERE _T IS ADDED

query.Add(new BsonElement(p.Name, bsonValue));
}
catch
{

}
}
}
return query;
}

so, the queries generated by this contain _t: typename for complex
types, but the documents I have inserted into the database do not
contain the _t property so the search always fails to find the
document.

I guess either the query is correct and it's the insert that is wrong
or vice versa.

Here is how I am inserting my objects into the db:

public override void Set(object obj)
{
//what type are we getting?
string typename = obj.GetType().ToString();
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase dataSource =
server.GetDatabase(this.dataSourceDescription);

MongoCollection<BsonDocument> coll =
dataSource.GetCollection<BsonDocument>(typename);


coll.Insert(obj);

}

Any pointers greatly appreciated as always,
Craig

Robert Stam

unread,
Mar 1, 2011, 1:41:01 PM3/1/11
to mongodb-csharp
First of all, it help to understand where the "_t" is coming from. It
is a discriminator value used to record the actual type of the object
that was serialized to BSON. The _t element is only written out when
it appears to be needed, which is basically whenever polymorphism
comes into play. In the terminology of the official C# driver, the _t
element is written when the actualType is different from the
nominalType.

The reason your query is being generated with a _t is because the
actualType of the wrapped object is different from the nominalType.

BsonDocument.Wrap(obj);

is actually equivalent to:

BsonDocument.Wrap<object>(obj);

because the compiler infers the <T> type argument from the argument
supplied. So the nominalType is object, and the actualType is some
subclass of object.

Because you are working at a metadata level you can't supply the <T>
value at compile time, because you don't know it. Instead you can use
a lower level way to create a BsonDocumentWrapper:

new BsonDocumentWrapper(obj.GetType(), obj); // set nominalType to
actual type of obj to prevent _t from being serialized

It's usually much easier than this! It's just made harder by working
at a metadata level.

On a related note, I'm not sure why your documents in the database
don't have a _t element. The Insert statement you showed should have
resulted in a _t element being added because the nominalType was
object and the actualType was some subclass of object. Is there
anywhere else you are inserting documents? You can use the mongo shell
to verify what the documents actually look like in the database.
Reply all
Reply to author
Forward
0 new messages