Hello. I have never worked with complex projections before, so I decided to fill in the blanks and try to understand what methods of projections there are and how they work in the c# Driver. So, can anyone explain me where I’m wrong?
In a nutshell:
- how to project one data model (class) onto another using the c# mongodb driver (preferable using linq expression), when the properties of these models have different names and some of them have to be configured using c# code?
Project A to B when:
B.State = A.InitialState; //different preperty names
B.Name = $"{A.FirstName} some text".ToUpper(); // .ToUpper() method
- Can I somehow use such code in my project and what are the preconditions?
B b = await _collection.AsQueryable()
.Select(a => new B(a))
.FirstOrDefaultAsync();
- What is the best practices for projection using MongoDb.driver for c#?
Here is more detailed example of mine:
I’m using sample_airbnb.listingsAndReviews
collection from Atlas Sample Dataset.
My c# entities looks like this:
[BsonIgnoreExtraElements]
internal class AirbnbEntity
{
[BsonId]
public string Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("accommodates")]
public int Accomodates { get; set; }
[BsonElement("bedrooms")]
public int Bedrooms { get; set; }
[BsonElement("number_of_reviews")]
public int ReviewsCount { get; set; }
[BsonElement("amenities")]
public string[] Amenities { get; set; }
[BsonElement("price")]
[BsonRepresentation(BsonType.Decimal128)]
public decimal Price { get; set; }
[BsonElement("address")]
public Address Address { get; set; }
}
[BsonIgnoreExtraElements]
internal class Address
{
[BsonElement("street")]
public string Street { get; set; }
[BsonElement("country")]
public string Country { get; set; }
[BsonElement("country_code")]
public string CountryCode { get; set; }
}
Here’s an examples of projections that don’t work for me:
The A
class was created for an example when you want to assign a bunch of properties of the source model to the projection model.
I was trying to do it by creating an object with an empty constructor and assigning fields, but in that case MongoDB.Driver.Linq.ExpressionNotSupportedException
happened. So I tried to find workaround and use specific constructor new A(AirbnbEntity item)
:
public class A
{
[BsonConstructor]
public A(AirbnbEntity item)
{
Name = item.Name;
Location = item.Address.CountryCode + " : " + item.Address.Country;
Price = item.Price;
PriceForWeek = item.Price * 7;
Info = "Number of bedrooms: " + item.Bedrooms;
StreetUpperCase = item.Address.Street.ToUpper();
UpperCase2 = $"{item.Address.Street.ToUpper()}";
}
//public AirbnbEntity Item { get; set; } //it works after this property is added
public string Name { get; init; }
public decimal Price { get; init; }
public string Location { get; set; }
public decimal PriceForWeek { get; set; }
public string Info { get; set; }
public string StreetUpperCase { get; set; }
public string UpperCase2 { get; set; }
}
I call this method:
var personProjection = await _collection
.AsQueryable()
.Select(item => new A(item))
.FirstOrDefaultAsync();
But in that case I got this exception:
MongoDB.Bson.BsonSerializationException: 'Creator map for class AggregationFramework.ProjectionStage+A has 1 arguments, but none are configured.'
The problem is resolved as soon as I add the public AirbnbEntity Item { get; set; }
property to the A
class model, but it looks strange for me, i don’t want to my A
class has AirbnbEntity
inside.