C# Serialization in MongoDb - _id on nested type, and some properties with private setters - mongodb

I'm in a position where I need to serialize some complex documents into MongoDb, but I can't change the class definition as I don't have control over the source.
However, we need to ensure that callers can still use Linq, so we need to map the class correclty into MongoDb.
Current there are few issues we're faced with:
The _id_ representation is on a nested class.
There are properties with private setters that need to be serialized/ deserialzied.
The shape of the class looks a little like this:
public class AggregateType : AggregateBase
{
public int IntProperty { get; private set; }
public ComplexObject ComplexObjectProperty { get; private set; }
}
With AggregateBase looking like this:
abstract public class AggregateBase
{
public AggregateDetails Details { get; set; }
}
And finally:
public class AggregateDetails
{
public Guid Id { get; set; }
...other properties
}
On the base class AggregateBase, there is a property called Details which contains the Id of the aggregate, which is a Guid. This Id field needs to be mapped to the ObjectId or _id field within a MongoDb document.
I need to be able to serialize the document, forcing the use of the Details.Id as the _id, and have the private setters serialized too.
I've done this with CosmoDb using a custom JsonContractResolver without issue. But the move to MongoDb has proved a little more complex.
It's worth noting that there are many AggregateType classes, all with a different shape. I'd like to find a generic way of serializing them, without having to write lots of specific mappers if possible - much like we do with CosmoDb.
On top of that, we would need this solution to work with the Linq query provider for MongoDb too.

Ive thought a little about this , the only way I can see this working is if you create matching types that will serve as your POCO for inserting into mongodb. Im going to assume you are using the C# Driver for Mongo.
public class AggregateTypeDocument : AggregateBaseDocument
{
public int IntProperty { get; private set; }
public ComplexObject ComplexObjectProperty { get; private set; }
}
abstract public class AggregateBaseDocument
{
public AggregateDetailsDocument Details { get; private set; }
}
public class AggregateDetailsDocument
{
[BsonId]
public Guid Id { get; private set; }
...other properties
}
You will end up replicating the structure but just be appending Document at the end for this example. By no means do you have to conform to this
Now you can mold your types to be more mongo friendly using various attributes.
The next step would be to either in your repository ( or wherever ) to map the types with class definitions you don't have access to to your new mongo friendly ones.
I would suggest AutoMapper for this or plain old instantiation. Now you should be able to safely operate on the collection. See below example for automapper.
var normalAggregateType = new AggregateType();
var client = new MongoClient("yourconnectionstring");
var db = client.GetDatabase("mydatabase");
var collection = db.GetCollection<AggregateTypeDocument>("myaggregatetypes");
var mongoAggregateType = Mapper.Map<AggregateTypeDocument>(normalAggregateType);
collection.InsertOne(mongoAggregateType);

Related

Entity Framework 6 load derived class of entity

In Entity Framework 6, given class A and derived class B: A, I would like to load entities A into instances of B without having to code for each property.
So given:
public class A
{
public Guid AId { get; set; }
public string Value { get; set; }
}
public class B: A
{
[NotMapped]
public string OtherValue { get; set; }
}
public MyDbContext: DbContext
{
public DbSet<A> As { get; set; }
}
I would like to:
using (MyDbContext db = new MyDbContext())
{
IEnumerable<B> Bs = db.As.LoadBsSomehow()
}
I'm guessing I could add DbSet<B> Bs { get; set; } and then in OnModelCreate I could override the table name to As perhaps. I'd like to avoid that if I can.
The purpose of doing this is that we need view models that need the underlying model plus some other properties and I don't want to mess up the models with all the different view model properties. This would simplify coding and maintenance for when the main model is changed -- the inheritance would automatically handle the changes in the derived class (view models).
I can then set the additional properties of the Bs in a Select or other method.
Also, I do NOT want to use reflection. I can code that up if I need it. I'd rather find out if EF 6 has the ability to do this natively.
UPDATE: I can do DbContext.Database.SqlQuery<T>. I would prefer to be able to use LINQ instead of writing SQL. I have no problem writing SQL, but LINQ is much more maintainable from a code perspective. Perhaps if I can use LINQ to create an IQueryable<B> and get the SQL for it?

Mapping custom collection's property to column in EF

I'd like this class:
public class InvertedList<T> : List<T>{
public bool IsInverted { get; set; }
}
when used in the entity like this:
public class Parent {
public InvertedList<Child> Children { get; set; }
}
to map into database tables like
CREATE TABLE Parent (
Child_IsInverted bit
);
CREATE TABLE Child (
ParentId int
)
I've tried putting [Column] on the IsInverted property, [ComplexType] on InvertedList class, but the property is always ignored.
Is there any way to do something like this or anything similar?
Of course I can do it manually like
public class Parent {
public bool Child_IsInverted { get; set; }
public List<Child> Children { get; set; }
}
But I really don't like to put all those Child_IsInverted properties (I'll have quite a lot of such invertable lists) on Parent entity. The only way I can think of to at least partially implement this would be to have separate domain and db models, and transform it using the repository - this way I could work using desirable model, but it looks like a little bit too much effort for such a task. Can you offer any other options?
When EF deserialize a List<> (everything implementing ICollection<>) it does not serialize other properties than the content.
Just a suggestion, Compex types that could be an option does not support generics and does not support navigation properties and you here have both.

TableController: Flatten persistent data into DTO

I'm new to Azure App Service mobile apps. I'm trying to understand my options for using TableController to expose complex domain objects to clients. My goal of using TableController is to take advantage of client-side querying and offline sync.
Table controllers are designed to perform CRUD operations on simple DTOs. So I'm trying to figure out how a complex domain model could be exposed as the sort of DTOs that TableController is designed for.
I've read this post which explains MappedEntityDomainManager. That example shows a fairly simple mapping between DTOs and persistent objects. But what if I want my mapping to be more complex?
For example, let's say I have persistent types like this:
public class Order {
public Customer Customer { get; set; }
public IList<OrderItem> OrderItems { get; }
}
public class Customer {
public string Name { get; set; }
public string TelephoneNumber { get; set; }
}
public class OrderItem { ... }
And I have a table controller declared like this:
public class OrderController : TableController<OrderDto>
Could the OrderDto then look like this?
public class OrderDto {
public string CustomerName { get; }
public string Customer { get; }
public string OrderItems { get; }
}
The mappings would be as follows. The Order.Customer.Name property is flattened into OrderDto.CustomerName. The complete Customer object is serialized into OrderDto.Customer. And the Order.OrderItems list is serialized into OrderDto.OrderItems.
Can this sort of complex mapping be done with MappedEntityDomainManager? If not then how could it be done? I know about leveraging $expand, but I worry that may be an unsupported hack rather than the recommended approach.
The best way to do this is to use Automapper. The blog post was a simple example, but you can do very complex mapping using automapper.
Here's a more complex example: https://github.com/paulbatum/FieldEngineerLite/blob/master/FieldEngineerLite.Service/Controllers/JobController.cs. It's for Azure Mobile Services, but the same concept applies to Azure Mobile Apps. You just need to change the namespaces.

Entity Framework Code First - Restoring collections of the same type

I'm using Entity Framework Code First. The class i'm trying to create contains two collections (of the same type). I'm having problem recovering my respective collections.
My classes look like this:
public class Destination
{
public int DestinationId { get; set; }
public string Name { get; set; }
public List<Lodging> Lodgings { get; set; }
public List<Lodging> Lodgings2 { get; set; }
}
public class Lodging
{
public int LodgingId { get; set; }
public string Name { get; set; }
public Destination Destination { get; set; }
}
I created a new Destination, then I reopened (closed & opened) the database connection. When I retrieve the destination, my collections (dest.Lodgings and dest.Lodgings2) are null. How do I restore the respective collections? If my class only has one collection of a particular type, I could do the following:
var lodgings = context.Lodgings.Where(l => l.Destination.DestinationId == destId).ToList();
I can see that the relationships are maintained in the database schema (Destination_DestinationId1 and Destination_DestinationId2) but I don't seem to be able to get to them.
Any suggestion would be appreciated.
In addition to using Include (as you've discovered) (which loads the related data from the db at the same time the destination is retrieved) you can also retreive the lodgings after the fact. So if you query for the destination and then you want the lodgings, that's possible. One way is called explicit loading where you will use a Load method. The other is with lazy loading, which requires that your classes be set up a particular way and just the mere mention of the Lodgings property will trigger the call to the database to retrieve them.
there's a great blog post on the Ef team blog about the various ways to load related data with DbContext : http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx
hth
Julie

DataAnnotations MetadataType Class Ignores Base Class Properties

I've run into a bit of a wall in trying to use the .NET DataAnnotations feature to provide simple validations in a derived class. I am marking up my class with the standard annotations included in .NET 4 (from the System.ComponentModel.DataAnnotations namespace), then using the MS Enterprise Library v5 Validation Block to process the rules.
I have a number of objects derived from a common base class, which contains properties common to all of my objects. For validation purposes, I may have different rules for the various classes derived from this class.
Here's a simplified example:
public abstract class PersonBase
{
public int Id { get; set; }
public string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
public class Customer : PersonBase
{
}
[MetadataType(typeof(ManagerMD))]
public class Manager : PersonBase
{
}
public class CustomerMD
{
[Required]
[StringLength(20, ErrorMessage="Customer names may not be longer than 20 characters.")]
public object Name { get; set; }
}
public class ManagerMD
{
[Required]
[StringLength(30, ErrorMessage = "Manager names may not be longer than 30 characters.")]
public object Name { get; set; }
}
// calling code
var invalidCustomer = new Customer {Id=1, Name=string.Empty};
var valFactory = EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
var customerValidator = valFactory.CreateValidator<Customer>();
var validationResults = customerValidator.Validate(invalidCustomer);
// validationResults.IsValid should equal False, but actually equals True.
I have found that I can get the expected validation results if I push the annotations down to the base class, but then I lose the ability to fulfill different requirements for different types. Also, if I put class-specific properties on a derived class and provide metadata for these properties, I get results, but only for these properties, not the properties from the base class.
I haven't yet tried using the EntLib provided validation attributes; I'd prefer to keep the library this lives in free of dependencies from outside the core framework, if at all possible.
Am I missing something, or am I just out of luck here?
I think I have a workable solution for this.
It appears that the Metadata class will not provide validation of properties belonging to the superclass of the target object. In order to get Metadata to work with this, I needed to mark the superclass properties as virtual, then provide overrides for the properties that I wanted to validate.
Example (see question above for original example):
public abstract class PersonBase
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
partial class Customer : PersonBase
{
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
}
With the override in place, the validator works as expected. It's a little more work, but it will get the job done.
I also tried adding annotations to the base class as fallback default rules; this allows me to have a base set of rules and override them as needed on a case by case basis. Looking good.
I run into the same issue and couldn't make it annotate a base class with Attributes using MethadataType. Like Scroll Lock I did the overriding part for base class virtual properties. On top of it I made "shadowing" for the none virtual properties.
public class BaseClass
{
public virtual int Id {get;set;}
public string Name {get;set;}
}
public class DerivedClass
{
[SomeAttribute]
public ovveride int Id {get{ return base.Id;} set{ base.Id = value;}}
[SomeAttribute]
public new string Name {get{ return base.Name;} set{ base.Name = value;}}
}