I'm having difficulty using AutoMapper to convert Object from Nhibernate queries into my DTO in the following conf
Let's say I have 4 class.
class A
{
//some fields of built-in type
}
abstract class B //Some class derived this one, but this is not important here
{
//some fields of built-in type
public A refA { get; set; }
}
class C
{
//some fields of built-in type
public B refB { get; set; }
}
class D
{
//some fields of built-in type
public B refC { get; set; }
}
I use AutoMapper to convert it to my DTO, lets assume for simplicity here that the DTO is an exact copy of these class.
I want to send this through the wire, so before serializing, I ask AutoMapper to convert it in the DTO corresponding to the D-Class.
If I make these Object and configure the field my-self, when I call
Mapper.Map<T1,T2>(T1 source)
This is working. So my configuration AutoMap is working. More its also working with
Mapper.Map<IList<T1>,List<T2>
Very well.
Now I make these object, I put them in a Database and call a request to my SQL DB with Nhibernate to retrieve an IList (List of class D).
If I now try to convert it in DTO, it doesnt work anymore.
I trace the code in AutoMap, it maps correctly all the built-in type field in class D and then it comes to the refC and here it crash somewhere.
I know about lazy-loading and the fact that Nhibernate just gimme a proxy of my ref to class C but I dont see how to solve this.
Just so you know the NHibernateUtil.IsInitialized(refC) is true
Many Thanks
You will have to unproxy your entities before passing it to automapper. This is basically the same issue as if you would run a Json serialization.
You can use
Session.GetSessionImplementation().PersistenceContext.Unproxy();
to unproxy something.
Or you disable lazy loading.
Or you do not use automapper and instead use standard transformations... e.g.
.Query().Select(p => new SomeDto(){ PropA = p.PropA, ...});
You can also use another standard way:
resultSet = session.CreateCriteria(typeof(DataObject))
.Add(query criteria, etc.)
.SetResultTransformer(Transformers.AliasToBean<DTOObject>())
.List<IDTOObject>()
Basically you don't have to iterate all of the props. It is enough to be the same all class props between your DTO and data object.
Related
I have a basic table with a few FK references. So when I retrieve an entity for an update operation; that entity contains ICollectionsof related entites. I also have a main ViewModel inside which each entity is a sub viewModel. My aim is to use Automapper like:
mapper.Map(MainViewmodel obj,MainEntity obj);
For this I have a MappingConfiguration like:
CreateMap<MainViewModel, MainEntity>();
CreateMap<subViewModel1, subEntity1>();
CreateMap<subViewModel2, subEntity2>();
This gives me an Unmapped properties exception because the ICollections are not getting mapped. Could anyone please guide me on the best way to deal with this kind of situation?
thanks.
If I understand you correctly, you has classes like this:
class MainViewModel
{
ICollection<SubViewModel1> SubViewModels { get;set; }
}
class SubViewModel1
{
}
and
class MainEntity
{
ICollection<SubEntity1> SubEntities { get;set; }
}
class SubEntity1
{
}
Then you should create rules for each class, and collection of such classes automaper map automatically.
CreateMap<MainViewModel, MainEntity>();
CreateMap<SubViewModel1, SubEntity1>();
Addditions 1:
Try this method: var mappedMainEntity = rmapper.Map<MainEntity>(MainViewmodel obj);
If you map MainEntity to MainViewModel you need add .ReverseMap() to map rule, like this:
CreateMap().ReverseMap();
CreateMap().ReverseMap();
Additions 2:
AutoMapper mapping public Properties only
If the mapping Properties have different names, you need to use explicitly indicating how to map these Properties. Using ForMember method and MapFrom option. Example
Our project has a framework and an own code base, which implements entities of the framework.
The idea is also to have several indexes in the framework that will return the results of all inheritances of certain framework types like user.
Apparantly, the only way Raven supports this (without creating the index on the highest level and manually adding maps) is to store all objects in the same collection by overwriting the Clr-type. However, this means we lose the derived information and cannot query on it.
Some samples:
class A {
public string Id {get; set; },
public string Name {get; set; }
}
class B : A { }
class C : A { }
class D : C { }
Then I want to query something along the lines of:
store.Query<IndexOfA>().Where(a => a.Name == "foo").As<A>().ToList();
AND be able to still do this;
store.Query<IndexOfC>().As<C>().ToList()
My idea was to add a convention that saves both the derived and the base class to the metadata when storing documents in RavenDB, but I have no idea how to go about this and cannot find any documentation on the subject.
Any ideas?
You can create an index that used a multi map index with AddMapForAll<Base>, which will generate a separate entry for each derived class.
You could then use that index to do polymorphic queries.
Is there a way to implicitly exclude certain fields/types in some DB model in C#'s MongoDB, while still allowing to get them explicitly? for instance, I have a Model with two big lists:
public class Model {
public string SomeName;
public List<string> ManyManyStrings; // exclude implicitly?
public List<ComplexType> VeryBigList; // exclude implicitly?
public int SomeNumber;
public byte[] LittleArrayOfBytes_NotBigDeal;
}
And when I call IMongoCollection<Model>.Find(SomeFilter), I have to explicitly exclude ManyManyStrings and VeryBigList:
var fastModel = modelCollection.Find(SomeFilter).Project<Model>(
Builders<Model>.Projection
.Exclude(m => m.ManyManyStrings)
.Exclude(m => m.VeryBigList));
Yes, I can separate them to different types or different Collections and associate them via ObjectId or so...
But the model is so "right"! they just have to be there, logically... my Model has ManyManyStrings and VeryBigList, it's just so much pain to start linking between Models and lists of List<string> ManyManyStrings or List<ComplexType> VeryBigList in some other collections...
(btw, I don't think [BsonIgnore] will help here, as it prevents explicit retrieval as well. Or am I wrong? is there a way to "bypass" it?)
Using MongoDB as my data store makes me to have ObjectID type as primary key by Default. It also can be changed by using Guid with [BsonId] attribute. Which is also defined in MongoDB C# Driver library. I would like to have my Entities independent from Data layer.
Can I just use name Id for the property to identify primary key? What else I can try?
You can use BsonClassMap instead of using attributes to keep your classes "clean".
// 'clean' entity with no mongo attributes
public class MyClass
{
public Guid Id { get; set; }
}
// mappings in data layer
BsonClassMap.RegisterClassMap<MyClass>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id).SetIdGenerator(CombGuidGenerator.Instance);
});
OPTION 1: Stick with BsonId and use the Facade Pattern
The [BsonId] property is what you'd use to indicate that the _id property should be linked to a specific property. There isn't a way around that (short of ignoring _id entirely in your crud operations which seems like a bad idea).
So, if you want to separate your "entity" object from your "data layer" then just use a poco class.
-- Use a poco class as a substitute for a record. That class is only for data storage: a quick way to get data in/out of mongo, and a great alternative to working with bson documents.
-- Use a facade on top of that poco class for your entity layer. I don't find it useful to re-invent the wheel, so I typically ask our devs have the entity interface inherit the data-layer (poco) interface, but you can do it however you'd like
Breaking up a sample MyObject class
IMyObjectRecord (declared at the dal and contains only properties and mongo-specific attributes)
IMyObject:IMyObjectRecord (declared at the entity level and may include added properties and methods)
MyObjectRecord:IMyObjectRecord (declared inside the dal, contains mongo-specific attributes. Could be declared internal if you wanted to be really strict about separation).
MyObject:IMyObject (could be, for example, a facade on top of the IMyObjectRecord class you pull from the dal).
Now - you get all the benefits of the facade, and you have a hard-coded link between the properties BUT, you get to keep Bson attributes contained in your dal.
OK, fine. But I really really really HATE that answer.
Yeah. I can accept that. OK, so how about a Convention Pack? If you ABSOLUTELY PROMISE that you'll call your Id's "Id" and you SWEAR that you'll type them as strings (or -- use some other convention that is easy to identify), then we could just use a convention pack like the one I stole from here
namespace ConsoleApp {
class Program {
private class Foo {
// Look Ma! No attributes!
public string Id { get; set; }
public string OtherProperty { get; set; }
}
static void Main(string[] args) {
//you would typically do this in the singleton routine you use
//to create your dbClient, so you only do it the one time.
var pack = new ConventionPack();
pack.Add(new StringObjectIdConvention());
ConventionRegistry.Register("MyConventions", pack, _ => true);
// Note that we registered that before creating our client...
var client = new MongoClient();
//now, use that client to create collections
var testDb = client.GetDatabase("test");
var fooCol = testDb.GetCollection<Foo>("foo");
fooCol.InsertOne(new Foo() { OtherProperty = "Testing", Id="TEST" });
var foundFoo = fooCol.Find(x => x.OtherProperty == "Testing").ToList()[0];
Console.WriteLine("foundFooId: " + foundFoo.Id);
}
//obviously, this belongs in that singleton namespace where
//you're getting your db client.
private class StringObjectIdConvention : ConventionBase, IPostProcessingConvention {
public void PostProcess(BsonClassMap classMap) {
var idMap = classMap.IdMemberMap;
if (idMap != null && idMap.MemberName == "Id" && idMap.MemberType == typeof(string)) {
idMap.SetIdGenerator(new StringObjectIdGenerator());
}
}
}
}
}
What's a Convention Pack
It's a little set of mongo "rules" that get applied during serialize/deserialize. You register it once (when you setup your engine). In this case, the sample pack is telling mongo "if you see a field called 'Id', then save it as a string to _id, please."
These can get really complex and fun. I'd dig into convention packs if you really really really hate the other approach. It's a good way to force all your mongo "attribute driven" logic into one self-contained location.
I have stumbled on the same problem myself, and I didn't want to have mongo attributes inside my classes.
I have created a small wrapper example to show how I save and find elements without having an Id property on the data classes of my business logic.
The wrapper class:
public static class Extensions
{
public static T Unwrap<T>(this MongoObject<T> t)
{
return t.Element;
}
}
public class MongoObject<T>
{
[BsonId]
private ObjectId _objectId;
public T Element { get; }
public MongoObject(T element)
{
Element = element;
_objectId = new ObjectId();
}
}
I have also added an extension method to easily unwrap.
Saving an element is simple
public void Save<T>(T t)
{
_collection.InsertOne(new MongoObject<T>(t));
}
To find an element we can do a linq-like query:
Say we have a data class:
public class Person
{
public string Name { get; set; }
}
then we can find such an element by
public Person FindPersonByName(string name)
{
return _collection.AsQueryable().FirstOrDefault(
personObject => personObject.Element.Name == name).Unwrap();
}
We can also generalize by making MongoObject implement IQueryable<T> and this would make the use of the wrapper even more convenient
If i understand correctly. You want to put your entity to other layer without attribute.
I think you can try this
public object Id { get; set; }
after that you can put your Id which is coming from mongodb without attribute
Update 1: for reasons I won't go into, I want to avoid having anything other than the properties to be persisted in my entity objects. This means no extra properties or methods...
I have an entity called Entity1 with (say) 10 public properties. In
one place in my code I want to output serialized JSON with (say) 3 of
those fields, in a second place I need to output 7 fields and in a
third place I might need to output (say) all 10 fields. How do I do
this using Newtonsoft's JSON library?
I can't use [JsonIgnore] or [DataMember] as that will apply to all
cases, so I won't be able to create "custom views" of the data (my own
terminology :-).
I tried to achieve this using an interface:
public interface Entity1View1
{
string Property1;
string Property2;
string Property5;
}
had Entity1 implement Entity1View1 and I passed an
IList<Entity1View1> to the JSON serializer (the objects were
actually just Entity1 objects). Didn't work: the serializer output
all the 10 public properties of Entity1.
The only other way I could think of was to implement
Entity1Wrapper1, Entity1Wrapper2 etc. type of classes where each
object would hold a corresponding instance of Entity1 and in turn
expose only those public properties that correspond to the properties
I want to show in "View1", "View2" etc. Then I pass lists of these
wrapper objects to the serializer (should work, haven't tried it yet).
Is there a better way?
If it matters, here's my configuration:
.Net 4.5
MVC 5
Don't know it that's the best way... but that's one.
One good point is that it will work either with json serialization or xml serialization, for example (which you may don't mind at all).
You can use ShouldSerialize<yourpropertyName> to manage what is serialized or not. <yourpropertyName> must match exactly the name of the property you wanna manage.
For example
public class Entity {
//assuming you want the default behavior to be "serialize all properties"
public Entity() {
ShouldSerializeProperty1 = true;
ShouldSerializeProperty2 = true;
ShouldSerializeProperty3 = true;
}
public string Property1 {get;set;}
public bool ShouldSerializeProperty1 {get;set;}
public string Property2 {get;set;}
public bool ShouldSerializeProperty2 {get;set;}
public int Property3 {get;set;}
public bool ShouldSerializeProperty3 {get;set;}
}
Then you could do, before all your serialization (of course, this could / should be extension methods).
var list = myListOfEntity;
//serialization1
foreach (var element in list) {
element.ShouldSerializeProperty3 = false;
}
//or serialization2
foreach (var element in list) {
element.ShouldSerializeProperty2 = false;
element.ShouldSerializeProperty3 = false;
}
I just wanted to make sure that this was the final step in processing.
You can create anonymous objects to serialize based on circumstance:
var json1Source1 = new {
Property1 = entityView1.Property1,
Property3 = entityView1.Property3
};
var json1Source2 = new {
Property2 = entityView1.Property2,
Property3 = entityView1.Property3
};
You can create jsonSource1 (or 2, 3, 4 etc) as anonymous objects that capture just what you need and then serialize them. The serializer will not care that they are anonymous.
Update 1:
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize..
This means that the solution suggested by Raphaël Althaus doesn't work as it relies on properties, whereas the serializer's documentation mentions that it has to be a method. I have verified that only a method returning a bool works as expected.
Original:
I finally went with a mix of Wrapper classes and the methodology suggested by Raphaël Althaus (with modifications): use Wrappers where some amount of sophistication may be required and use Raphaël's suggestion when simplicity will do.
Here's how I am using wrappers (intentionally left out null checks):
public class Entity1View1
{
protected Entity1 wrapped;
public Entity1View1(Entity1 entity)
{
wrapped = entity;
}
public String Property1
{
get { return wrapped.Property1; }
}
public String Property2
{
get { return wrapped.Property2; }
}
public String Property3
{
get { return wrapped.Property3.ToUpper(); }
}
}
This allows me to modify properties as their values are returned (as done with Property3 above) and lets me leverage inheritance to create new ways of serialization. For example, I can flatten the structure/hierarchy:
public class Entity1View2 : Entity1View1
{
pulic Entity1View2(Entity1 entity) : base(entity) { }
public long? SubEntityID
{
get { return wrapped.SubEntity.ID; }
}
}
For simpler cases where complexity/transformation of this sort is not required, I can simply use the ShouldSerialize* methods.
Same entity classes, different serialization outputs.