-
Type:
Bug
-
Resolution: Won't Fix
-
Priority:
Major - P3
-
None
-
Affects Version/s: 2.11.0
-
Component/s: LINQ2
-
Environment:I've verified this behaviour both on Windows as well as in a Linux container
I believe I’ve found a bug related to projection, specifically when you map an array that is a deep descendant of the document root.
Suppose this is my model:
public class DummyContainer { public DummyContainer(IList<Dummy> dummies) { Dummies = dummies; this.Id = ObjectId.GenerateNewId().ToString(); } public string Id { get; private set; } public IList<Dummy> Dummies { get; private set; } } public class Dummy { public Dummy(string name) { this.Name = name; this.Id = ObjectId.GenerateNewId().ToString(); } public string Id { get; private set; } public string Name { get; private set; } }
First, an example that works:
Let’s say I insert one document of type DummyContainer into an empty collection:
collection.InsertOneAsync(new DummyContainer(new[] { new Dummy("SomeValue1"), new Dummy("SomeValue2"), }));
And then I load all documents from that collection, projected into this type:
class DummyContainerWithDummyNames { public string ContainerId { get; set; } public IEnumerable<string> DummyNames { get; set; } }
Here we go:
var dummyNamesByUsingFindAsync = await (await collection.FindAsync(Builders<DummyContainer>.Filter.Empty, new FindOptions<DummyContainer, DummyContainerWithDummyNames> { Projection = Builders<DummyContainer>.Projection.Expression(x => new DummyContainerWithDummyNames { ContainerId = x.Id, DummyNames = x.Dummies.Select(d => d.Name) }) })).ToListAsync(); var dummyNamesUsingQuery = await collection.AsQueryable() .Select(x => new DummyContainerWithDummyNames { ContainerId = x.Id, DummyNames = x.Dummies.Select(d => d.Name) }) .ToListAsync();
Result:
Both dummyNamesByUsingFindAsync and dummyNamesUsingQuery contain one document, and in both cases the property DummyNames is populated with ["SomeValue1", "SomeValue2"].
An example that shows the bug:
Ok, in order to reproduce the bug, we’re gonna wrap the DummyContainer in a DummyContainerWrapper and let this be our root entity:
public class DummyContainerWrapper { public DummyContainerWrapper(DummyContainer container) { Container = container; this.Id = ObjectId.GenerateNewId().ToString(); } public string Id { get; private set; } public DummyContainer Container { get; private set; } }
We’re gonna insert such a document to a new collection:
await collection.InsertOneAsync(new DummyContainerWrapper(new DummyContainer(new[] { new Dummy("SomeValue1"), new Dummy("SomeValue2"), })));
And just like before, we’re gonna query the collection for all documents and project them into the same type we used above:
var dummyNamesByUsingFindAsync = await (await collection.FindAsync(Builders<DummyContainerWrapper>.Filter.Empty, new FindOptions<DummyContainerWrapper, DummyContainerWithDummyNames> { Projection = Builders<DummyContainerWrapper>.Projection.Expression(x => new DummyContainerWithDummyNames { ContainerId = x.Id, DummyNames = x.Container.Dummies.Select(d => d.Name) }) })).ToListAsync(); var dummyNamesUsingQuery = await collection.AsQueryable() .Select(x => new DummyContainerWithDummyNames { ContainerId = x.Id, DummyNames = x.Container.Dummies.Select(d => d.Name) }) .ToListAsync();
And this is where we see the bug:
dummyNamesUsingQuery has one element, who’s DummyNames }}property is an {{IEnumerable<string> (the concrete type is List<string>) populated with{{ ["SomeValue1", "SomeValue2"]}}.
dummyNamesByUsingFindAsync }}on the other hand also has one element, but it´s {{DummyNames }}property is of type {{System.Linq.Enumerable.SelectListIterator<MyTestProgram.Dummy, string>, and the values are both null.
- mentioned in
-
Page Loading...