How store objects in MongoDb without assembly fully qualified name - mongodb

I store item that contains fields like Dictionary
In mongo this field has _t = System.Collections.Generic.Dictionary`2[System.String,[Namespace.MyType, Namespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=89b48272fdae8cae]]
I don't need Version and PublicKeyToken and farther this be a trouble with next version of assembly
How can I store data with _t property like System.Collections.Generic.Dictionary`2[System.String,[Namespace.MyType]]?

The type discriminator is used for inheritance and resolving declared type to stored type.
If you have a concrete class with a concrete property, you should not need a discriminator.
Let's say you have a property on a class:
public class Foo : MyBase{
...
public string Title {get;set;}
}
public class Bar: MyBase{
...
public string Title {get;set;}
}
The driver might be able to map that IN to a string array and store in mongodb
{_id: ..., Title: "Hello" }
On the way OUT though, the driver has to decide what the BSON array would become. Absent a type discriminator, should it generate an instance of : Foo? Bar? MyBase?
If you have a class that has-a concrete dictionary rather than is-a dictionary, you can avoid much of this.

Related

Entity Framework navigation with only foreign key

Following the guide lines from Domain Driven Design, I try to avoid having one aggregate referencing a different aggregate. Instead, an aggregate should reference another aggregate using the other aggregate's id, for example:
public class Addiction
{
private Addiction(){} //Needed for EF to populate non-simple types
//DrugType belongs to the aggregate,
//inflate when retrieving the Addiction from the db
//EF does not need DrugId for navigation
Drug Drug{get;set;}
//The supplier is not part of the aggregate,
//aggregates only reference eachother using Ids
int SupplierId{get;set;}
//Other properties
}
public class AddictionConfiguration : IEntityTypeConfiguration<Addiction>
{
builder.HasOne(addiction => addiction.Drug); //Works
builder.HasOne("SupplierId") //Does not work.
}
In this (not very realistic) example, Drug is part of the Addiction's aggregate. When loading this entity from the database using EF, it will also inflate the Drug property without me having to specify the DrugId as the foreign key.
However, now I need to get a list of all Addictions and their suppliers by mapping the relevant properties to a Dto. I try to achieve this by using AutoMapper's ProjectTo functionality, e.g.
_mapper.ProjectTo<AddictionDto>(_dbContext.Addictions.Where(x => x.Id > 1));
where AddictionDto is defined as
public class AddictionDto
{
DrugDto Drug {get;set;}
SupplierDto Supplier {get;set;}
//other properties
}
And
public class SupplierDto
{
public int Id {get;set;}
public string Name {get;set;}
}
Automapper correctly loads the Addiction and also the Drug, but I cannot get it to load the Supplier. I've tried all the options of the IEntityTypeConfiguration to tell EF that there is a navigation property, but I cannot get it to work. Does anyone know if is even possible to do what I described above?

Go, Mongo problems

I am new using Go, but I would like to know if there is a problem if I add new attributes to a Collection in Mongo, once my model is defined in Go. Form example
I defined in Go this Model:
type material struct {
ID string `bson:"_id" json:"_id"`
Name string `bson:"name" json:"name"`
Entity string `bson:"entity" json:"entity"`
}
and I create new attributes on Material Collection for example:
Collection Material
All Attributes: ID, Name, Entity,Country(NEW ONE)
Is it necessary to update the model knowing that I will not use that attribute for the project?

Entity Framework TPH - Additional WHERE clause only for one subtype

Suppose I have a class Parent, with two subclasses, AChild and BChild. I have these mapped to a single table using Entity Framework 5.0.0 on .NET 4.5, using TPH.
public abstract class Parent {
public string Type { get; set; } // Column with this name in DB is discriminator.
public string Status { get; set; }
}
public class AChild : Parent {
// Other stuff.
}
public class BChild : Parent {
// Other stuff.
}
The code to configure the mapping:
class ParentConfiguration : EntityTypeConfiguration<Parent> {
Map((EntityMappingConfiguration<AChild> mapping) => mapping
.Requires("Type")
.HasValue("A"));
Map((EntityMappingConfiguration<BChild> mapping) => mapping
.Requires("Type")
.HasValue("B"));
}
I have a need to run a query that returns both AChild and BChild objects. However, it needs to filter ONLY the AChild rows by a second column, which in this example I will call Status.
Ideally I would want to do the following:
public IList<Parent> RunQuery() {
IQueryable<Parent> query =
this.context.Set<Parent>()
.Where((Parent parent) => !parent.Type.Equals("A") || parent.Status.Equals("Foo"))
.OrderBy((Parent parent) => parent.Number);
return query.ToList();
}
This doesn't work. It insisted on looking for a "Type1" column instead of just letting both the discriminator and a "Type" property be mapped to the same "Type" column.
I know of the "OfType" extension method that can be used to completely filter down to one type, but that's too broad a brush in this case.
I could possibly run multiple queries and combine the results, but the actual system I'm building is doing paging, so if I need to pull back 10 rows, it gets messy (and inefficient) to query since I'll either end up pulling back too many rows, or not pull back enough and have to run extra queries.
Does anyone have any other thoughts?
There are few problems. First of all you cannot have discriminator mapped as a property. That is the reason why it is looking for Type1 column - your Type property results in second column because the first one is already mapped to .NET types of your classes. The only way to filter derived types is through OfType.
The query you want to build will be probably quite complex because you need to query for all Bs and concatenate them with result of query for filtered As. It will most probably not allow you to concatenate instances of Bs with As so you will have to convert them back to parent type.

Entity Framework TPT inheritance - How to get from database?

I have a BaseTable with TypeId column which is foreign key to Type table. I mapped this into entity framework model by using template per hierarchy pattern.
Now i have a BaseClass and two subclasses named SubClass1 and SubClass2 and make BaseClass abstract.
From one of my page to second page i get an id (which is an id of BaseClass of course) and i want to get this object from database.
How i will make my query? Coming id is owned by an Subclass of course.
For example, can i write like this:
BaseClass object = provider.getfrombaseclassbyid(id);
Can i make a boxing like this? if can, how can i know what is object is really. It is a Subclass1 or Subclass2? How can i know it?
Can you help me what should i do?
I am not sure if the following answers your question, but you can indeed query on a set that respresents abstract entities:
BaseClass entity = context.BaseClasses.SingleOrDefault(b => b.Id == id);
Of course the result will never be of type BaseClass because no instance of an abstract type can be created. It will either be of type SubClass1 or SubClass2 (or null if an entity with that id doesn't exist). Entity Framework can decide which type has to be used when the object is created by looking either at the value of the discriminator column (for Table-Per-Hierarchy (TPH) inhericance) or by joining from the base table into the tables of the derived types (for Table-Per-Type (TPT) inheritance).
You can check the materialized type for example by using:
string typeName = entity.GetType().Name; // will be "Subclass1" or "Subclass2"
Or:
if (entity is SubClass1)
// ...
else if (entity is SubClass2)
// ...
If you know in advance that you want to load an entity of type SubClass1 you can use the OfType<T> operator:
SubClass1 entity = context.BaseClasses.OfType<SubClass1>()
.SingleOrDefault(b => b.Id == id);
If the entity with the given id is not a SubClass1 but a SubClass2 instead, the result of this query will be null. Otherwise it is guaranteed to be a SubClass1.

mongodb insert creation time separated from objectId

I am using mongodb with the official c# driver.
I am using Guids as Id field for my objects. I don't want to introduce a dependency on the mongodb bson classes so I am not using ObjectId in my domain layer.
Is it possible to instruct mongodb to insert a creation timestamp into objects that I insert into the datastore?
Example:
public class Foo
{
public Guid Id {get;set;}
public DateTime CreatedOn {get;set;}
}
Using mongodb idGenerators I can get the Guids generated upon insert. I know ObjectId has the timestamp included but as mentioned I wouldn't want my class to look like this
public class Foo
{
public ObjectId Id { get; set; }
public DateTime CreatedOn {get { return Id.CreationTime;}}
}
Is it important that it's the inserted timestamp and not the object's created timestamp? If not then do it in the constructor of the class. Or even better, a base class for your class(es).
public abstract class BaseClass
{
[BsonId]
public Guid Id {get;set;}
public DateTime CreatedOn {get;set;}
protected BaseClass()
{
Guid = new Guid();
CreatedOn = new DateTime.UtcNow;
}
}
public class Foo : BaseClass
{
}
Is this something you can use for it?
You can have an _id which is itself a document :
in json : { _id : {guid : ...., createdOn : ....} , field1 : ..., field2:....}
You just have to modify your idGenerator to have this behavior.
I recommend, however, that you really re-consider to use ObjectId.
If you're trying to make your domain layer pure and free of persistence concerns, then it makes sense to populate the creation date yourself in the domain layer, when deciding to create an entity, instead of relying on the database technology to put in a server timestamp.
This makes "creation date" a logical domain concept rather than the DB's concept of "timestamp when first stored in DB". The two can differ e.g. in cases of migrating data (but keeping the timestamp), deferring execution (e.g. in jobs), etc.
It also creates a healthy separation between "physical timestamp" and "logical timestamp" which you can further exploit during testing/mocking (e.g. you could have a test that says "do X, then change the logical time to 2 days in the future, then assert Y").
Finally, it forces you to think of what the creation date means in your domain layer instead of blindly assuming that it will be correct.
All this being said, if you insist on having it in MongoDB you can have a mapping that creates an ObjectID into some kind of hidden field (e.g. an explicitly-implemented interface) at insert time, and extracts its timestamp into the CreationDate field at read time.