Closed dannotsys closed 6 years ago
The problem with using the code-first approach is that MongoDb BsonClassMaps are (infuriatingly) statically auto-generated. This means that only one instance can be created per app runtime, which leads to many different problems in terms of trying to map from an EF Core Model, which is a singleton that's created for each DbContext instance that references it. Because of how MongoDb automatically generates the class maps and immediately freezes them, the timing of trying to programmatically apply EF Core Model settings to a BsonClassMap can result in several different kinds of exceptions.
Because of this static generation of BsonClassMap, the recommended approach is to use aspect oriented model declarations and just stick with the annotations/attributes. You can use either [NotMapped] or [BsonIgnore] attributes on the member, and there are already conventions in place to keep the respective mappings in sync.
That said, I can add an IEntityTypeMemberIgnoredConvention implementation to the MongoDbConventionSet to attempt to apply the ignore status. But there's no guarantee that this will work, again because of the MongoDb C# driver's extremely poor design decision of relying heavily on static code over injectable and overridable services.
Thanks for the feedback Chris, I agree. Since there is no better solution at this time, I will consider to create wrapper classes adding the recomended attributes for the purpose.
Do you think that the static based usage of the mongodb driver could be masked by creating a internal wrapper class that manipulates app domains?
.NET Core does not use app domains.
I might be able to work around the problem by adding an EntityType annotation that stores the BsonClassMap, and just create and manage them myself. That way, I should be able to prevent them from getting frozen, or at least guarantee that they're frozen only after the EF Core model is built. But that still won't get around any model mismatches if someone were to proactively create BsonClassMaps before allowing the EF Core model to be generated.
There's another request to allow mapping EntityTypes directly from existing BsonClassMaps, so I might be able to finagle that into some kind of bridge. Once the BsonClassMaps are created, I should be able to generate EntityTypes directly from them and not worry about mismatches in conventions. But this would require users to create BsonClassMaps rather than any of the code-first modeling from EF Core.
No matter how you slice it, the static architecture in the MongoDb C# driver is a pain to try to work around.
Got it, Chris! Hopefully the mongodb team will improve the driver to conform better to the new .net core architecture
I spent some time earlier in the year trying to work around this, and I couldn't figure out how to reliably force the BsonClassMaps to conform to the entity models without removing maps and re-creating them, which might cause problems at runtime if a map has already been created.
The safest way to work around this appears to be to use the aspect-oriented attributes (where available) for modeling, and allow the EFCore-MongoDB provider to generate the class maps in-sync with the EF models.
Hi, I am working now with some third party legacy POCOs classes where I had to remove some properties from the mapping, but the Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder.Ignore(string propertyName) implementation, seems not to be working.
I have been able to workaround it using BsonClassMap.RegisterClassMap(cm => cm.UnmapMember(MemberInfo)) on the context's onModelCreating but I am afraid of problems that this might lead. Is there some mongodb design limitation or is it possible to implement it, Chris?