Automapper map inside nested Enumerable properties - automapper

I would like to use automapper to map nested enumerable properties in existing enumerable nested properties.
Here is the problem simplify, i have Entities objects, they implement IEntity Interface, and Models objects, they implment IModel interfaces.
I would like to update easily and in a smart way IEntity object with IModel object
Example :
public class PersonEntity : IEntity
{
public int Id { get; set; }
public string Name { get; set }
public IEnumerable<AddressEntity> Addresses { get; set }
}
public class AddressEntity : IEntity
{
public int Id { get; set; }
public string Street { get; set }
public string entityField { get; set }
}
public class PersonModel : IModel
{
public int Id { get; set; }
public string Name { get; set }
public IEnumerable<AddressModel> Addresses { get; set }
}
public class AddressModel : IModel
{
public int Id { get; set; }
public string Street { get; set }
}
If i have these two instance og PersonEntity and AddressEntity :
var personModel = new PersonModel()
{
Id = 1,
Name = "Name",
Addresses = new List<AddressModel>() {
new AdressModel() { Id = 1, Street = "Street B" }
}
var person = new PersonEntity()
{
Id = 1,
Name = "Name",
Addresses = new List<AddressEntity>() {
new AdressEntity() { Id = 1, Street = "StreetA", EntityField ="entityValue" }
}
How can i map by Id, the Addresses element, to only erase the StreetA value by StreetB value, and keep existing entityField value intact ?
Thank you for help !

Related

Custom reference naming convention in ormlite

Is there a way to change the default {PropertyReference}Id naming convention for references and foreign keys ?
For example, I want to do this :
public class Customer
{
[References(typeof(CustomerAddress))]
public int Id_PrimaryAddress { get; set; } // with a prefix
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
instead of that :
public class Customer
{
[References(typeof(CustomerAddress))]
public int PrimaryAddressId { get; set; } // standard
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
Thank you
You can't change the code convention of OrmLite's Reference Conventions globally, but you can use the [Alias("DbColumnName")] to map it to a different underlying RDBMS Table column.
Overriding Conventions with Attributes
You're also able to use the Foreign Key and References Attributes as your example does to override the conventions, e.g. you can play with this Live Example on Gistlyn:
public class CustomerAddress
{
[AutoIncrement]
public int Id { get; set; }
public string Address { get; set; }
public string Country { get; set; }
}
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[References(typeof(CustomerAddress))]
public int Id_PrimaryAddress { get; set; } // with a prefix
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
db.CreateTable<Customer>();
db.CreateTable<CustomerAddress>();
var customer = new Customer
{
Name = "The Customer",
PrimaryAddress = new CustomerAddress {
Address = "1 Home Street",
Country = "US"
},
};
db.Save(customer, references:true);
Where you can load it and its references and view it with:
var c = db.LoadSelect<Customer>(x => x.Name == "The Customer");
c.PrintDump();
Which will output:
[
{
Id: 1,
Name: The Customer,
Id_PrimaryAddress: 1,
PrimaryAddress:
{
Id: 1,
Address: 1 Home Street,
Country: US
}
}
]

Cannot serialize inherited property into JSON via Json.Net

I am using C# .NET 4.0 and Newtonsoft JSON 4.5.0.11
[JsonObject(MemberSerialization.OptIn)]
public interface IProduct
{
[JsonProperty(PropertyName = "ProductId")]
int Id { get; set; }
[JsonProperty]
string Name { get; set; }
}
public abstract class BaseEntity<T>
{
private object _id;
public T Id
{
get { return (T)_id; }
set { _id = value; }
}
}
public class Product : BaseEntity<int>, IProduct
{
public string Name { get; set; }
public int Quantity { get; set; }
}
I need to serialize part of object and I use interfaces with declared concrete properties to do this.
The serialization looks like:
Product product = new Product { Id = 1, Name = "My Product", Quantity = 5};
JsonConvert.SerializeObject(product);
Expected result is:
{"ProductId": 1, "Name": "My Product"}
But actual result is:
{"Name": "My Product"}
How can I serialize this object correctly?
UPD: Looked at the source code of json.net and came to the conclusion that this is a bug with grab information about object through ReflectionUtils.
Have you tried this?
public interface IProduct
{
int Id { get; set; }
string Name { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public abstract class BaseEntity<T>
{
private object _id;
[JsonProperty]
public T Id
{
get { return (T)_id; }
set { _id = value; }
}
}
[JsonObject(MemberSerialization.OptIn)]
public class Product : BaseEntity<int>, IProduct
{
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public int Quantity { get; set; }
}

Automapper and Custom Type Converter with Parent/Child

How can I covert am object to a certain type based on a property of the parent object holding the current object with automapper?
Below I have a class that contains a property called Type of enum type EventAssetType. I want to convert the property Asset to a type called DocumentModel or ImageModel that both inherit from AssetModel by using the Type property. Right now it is just mappering from Asset to AssetModel.
public class EventAssetModel
{
public EventAssetModel()
{
Event = new EventModel();
Asset = new DocumentModel();
Type = Enums.EventAssetType.Other;
}
public int Id { get; set; }
public bool Active { get; set; }
public Enums.EventAssetType Type { get; set; }
public EventModel Event { get; set; }
public AssetModel Asset { get; set; }
}
One way to accomplish this is the ConvertUsing extension method when creating a map. I've included an example for you below:
namespace Some.Namespace
{
class Program
{
static void Main(string[] args)
{
Mapper.CreateMap<Source, Animal>().ConvertUsing(MappingFunction);
Source animal = new Source() {Type = Source.SourceType.Animal, Name = "Some Animal"};
Source dog = new Source() {Type = Source.SourceType.Dog, Name = "Fido"};
Animal convertedAnimal = Mapper.Map<Source, Animal>(animal);
Console.WriteLine(convertedAnimal.GetType().Name + " - " + convertedAnimal.Name);
// Prints 'Animal - Some Animal'
Animal convertedDog = Mapper.Map<Source, Animal>(dog);
Console.WriteLine(convertedDog.GetType().Name + " - " + convertedDog.Name);
// Prints 'Dog - Fido'
}
private static Animal MappingFunction(Source source)
{
switch (source.Type)
{
case Source.SourceType.Animal:
return new Animal() {Name = source.Name};
case Source.SourceType.Dog:
return new Dog() {Name = source.Name};
}
throw new NotImplementedException();
}
}
public class Source
{
public enum SourceType
{
Animal,
Dog
}
public string Name { get; set; }
public SourceType Type { get; set; }
}
public class Animal
{
public string Name { get; set; }
}
public class Dog : Animal
{
// Specific Implementation goes here
}
}

AutoMapper failing to map a simple list

I have used automapper for mapping lists in the past, for for some reason it won't work in this case.
public class MyType1 {
public int Id { get; set; }
public string Description { get; set; }
}
public class MyType2 {
public int Id { get; set; }
public string Description { get; set; }
}
public void DoTheMap() {
Mapper.CreateMap<MyType2, MyType1>();
Mapper.AssertConfigurationIsValid();
var theDto1 = new MyType2() { Id = 1, Description = "desc" };
var theDto2 = new MyType2() { Id = 2, Description = "desc2" };
List<MyType2> type2List = new List<MyType2> { theDto1, theDto2 };
List<MyType1> type1List = Mapper.DynamicMap<List<MyType1>>(type2List);
//FAILURE. NO EXCEPTION, BUT ZERO VALUES
List<MyType1> type1List2 =type2List.Select(Mapper.DynamicMap<MyType1>).ToList();
//SUCCESS, WITH LINQ SELECT
}
Change this:
Mapper.DynamicMap<List<MyType1>>(type2List)
To this:
Mapper.Map<List<MyType1>, List<MyType2>>(type2List);
DynamicMap is only if you don't know the type at compile time - for things like anonymous types.

ValueInjecter question

After working with AutoMapper I came across ValueInjecter on this site. I am trying it out but I am stuck on what is probably a very simple scenario.
But before I dig into the code sample, does anyone know if ValueInjecter works in a Medium-Trust web environment? (Like Godaddy?)
Ok, onto the code! I have the following models:
public class NameComponent
{
public string First { get; set; }
public string Last { get; set; }
public string MiddleInitial { get; set; }
}
public class Person
{
public NameComponent Name { get; set; }
}
that I want to map to the following DTO:
public class PersonDTO : BaseDTO
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { NotifyPropertyChanged(() => FirstName, ref _firstName, value); }
}
private string _middleInitial;
public string MiddleInitial
{
get { return _middleInitial; }
set { NotifyPropertyChanged(() => MiddleInitial, ref _middleInitial, value); }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { NotifyPropertyChanged(() => LastName, ref _lastName, value); }
}
}
So when I want to Map from Model to DTO I need a Model.Name.First -> DTO.FirstName
and when going from DTO to Model I need FirstName -> Name.First. From my understanding this is not a simple Flatten/UnFlatten, because the words also reverse themselves, ie: FirstName <--> Name.First. So First and Last names could use the same kind of rule, but what about MiddleInitial? Model.Name.MiddleInitial -> DTO.MiddleInitial.
I see there are some plugins, but none of them seem to do what I would want. Has anyone else come across this scenario?
the basic idea is that I match the Name with the FirstName, I take this as a pivot point, and in the method that usually sets the value to just one (FirstName) property I set it to 3 properties - that's for the FromNameComp
in the ToNameComp i match the same properties but I take the value from 3 and create one and set it
public class SimpleTest
{
[Test]
public void Testit()
{
var p = new Person { Name = new NameComponent { First = "first", Last = "last", MiddleInitial = "midd" } };
var dto = new PersonDTO();
dto.InjectFrom<FromNameComp>(p);
Assert.AreEqual(p.Name.First, dto.FirstName);
Assert.AreEqual(p.Name.Last, dto.LastName);
Assert.AreEqual(p.Name.MiddleInitial, dto.MiddleInitial);
var pp = new Person();
pp.InjectFrom<ToNameComponent>(dto);
Assert.AreEqual(dto.LastName, pp.Name.Last);
Assert.AreEqual(dto.FirstName, pp.Name.First);
Assert.AreEqual(dto.MiddleInitial, pp.Name.MiddleInitial);
}
public class FromNameComp : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == "Name" && c.SourceProp.Type == typeof(NameComponent)
&& c.TargetProp.Name == "FirstName"
&& c.SourceProp.Value != null;
}
protected override object SetValue(ConventionInfo c)
{
dynamic d = c.Target.Value;
var nc = (NameComponent)c.SourceProp.Value;
//d.FirstName = nc.First; return nc.First does this
d.LastName = nc.Last;
d.MiddleInitial = nc.MiddleInitial;
return nc.First;
}
}
public class ToNameComponent : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.TargetProp.Name == "Name" && c.TargetProp.Type == typeof(NameComponent)
&& c.SourceProp.Name == "FirstName";
}
protected override object SetValue(ConventionInfo c)
{
dynamic d = c.Source.Value;
var nc = new NameComponent { First = d.FirstName, Last = d.LastName, MiddleInitial = d.MiddleInitial };
return nc;
}
}
public class NameComponent
{
public string First { get; set; }
public string Last { get; set; }
public string MiddleInitial { get; set; }
}
public class Person
{
public NameComponent Name { get; set; }
}
public class PersonDTO
{
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
}
}
But before I dig into the code sample,
does anyone know if ValueInjecter
works in a Medium-Trust web
environment? (Like Godaddy?)
it doesn't use reflection.emit so it should work

Resources