map configuration or unsupported mapping - c#

I have two types. One in the business layer:
namespace Business
{
public class Car
{
private int _id;
private string _make;
private string _model;
public int id
{
get { return _id; }
set { _id = value; }
}
public string make
{
get { return _make; }
set { _make = value; }
}
public string model
{
get { return _model; }
set { _model = value; }
}
}
}
and the other in the Data layer (Entity Framework):
namespace Data
{
using System;
using System.Collections.Generic;
public partial class Car
{
public Car()
{
this.facttables = new HashSet<facttable>();
}
public int id { get; set; }
public string make { get; set; }
public string model { get; set; }
public virtual ICollection<facttable> facttables { get; set; }
}
}
Here is the code I get from the service layer:
namespace Data
{
public class VehicleDAO : IVehicleDAO
{
private static readonly ILog log = LogManager.GetLogger(typeof(VehicleDAO));
MapperConfiguration config;
public VehicleDAO ()
{
Mapper.Initialize(cfg => cfg.CreateMap<Business.Car, Data.Car>());
config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Business.Car, Data.Car>()
.ForMember(dto => dto.facttables, opt => opt.Ignore());
//.ForMember(d => d.id, opt => opt.MapFrom(c => c.id))
//.ForMember(d => d.make, opt => opt.MapFrom(c => c.make))
//.ForMember(d => d.model, opt => opt.MapFrom(c => c.model));
});
config.AssertConfigurationIsValid();
}
public Data.Car Select(int id)
{
Data.Car car;
using (VehicleEntities VehicleDatabase = new VehicleEntities())
{
car = VehicleDatabase.Cars.Where(c => c.id == id).ToList().Single();
Business.Car cars = AutoMapper.Mapper.Map<Business.Car>(car);
}
return car;
}
The exception is: {"Missing type map configuration or unsupported mapping.\r\n\r\nMapping types:\r\nCar_70BD8401A87DAAD8F5F0EC35BCAE5C9E6EE2D6CB5A1AFCE296B313D8AD87D2E9 -> Car\r\nSystem.Data.Entity.DynamicProxies.Car_70BD8401A87DAAD8F5F0EC35BCAE5C9E6EE2D6CB5A1AFCE296B313D8AD87D2E9 -> Business.Car"}. What is wrong? I have marked the line that causes the exception (third from last line).

Automapper only maps in the direction you created the mapping in. CreateMap<Business.Car, Data.Car> creates a mapping from Business.Car to Data.Car. It looks like you are trying to map from Data.Car to Business.Car, which means you need to CreateMap<Data.Car, Business.Car>
Mapper.Initialize(cfg => cfg.CreateMap<Data.Car, Business.Car>());
config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Data.Car, Business.Car>();
});
config.AssertConfigurationIsValid();

Related

How to map Complex type using automapper

Automapper with complex nested mapping. I am trying to map mydestinationArrayField and
dest1Array, here source objectlist to be copied to dest1array.
here are my classes for source and destination.
namespace AutomapperDemo
{
class Program
{
static void Main(string[] args)
{
try
{
SourceObject request = new SourceObject()
{
sourceTypeField = "1",
SourceObj1Field = new SourceObj1
{
SourceObj1Id = "1",
SourceObjListss = new List<SourceInnerObjList>
{
new SourceInnerObjList
{
SourceObjListItem1Id = 1
},
new SourceInnerObjList
{
SourceObjListItem1Id = 2
}
}
}
};
var mapper = CreateMapper();
DestinationObject destination = new DestinationObject();
destination = mapper.Map<DestinationObject>(request);
}
catch (Exception ex)
{
throw ex;
}
}
public static IMapper CreateMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AllowNullDestinationValues = true;
cfg.CreateMap<SourceObject, DestinationObject>()
.ForMember(dest => dest.destinationTypeField, o => o.MapFrom(src => src.sourceTypeField))
.ForMember(dest => dest.destinationObjectArrayField, o => o.MapFrom(src => new destinationObjectArray()
{
mydestinationArrayField = src.SourceObj1Field.SourceObjListss.Select(x => x.SourceObjListItem1Id).FirstOrDefault().ToString(), //this gives error
//dest1Array = src.SourceObj1Field.SourceObjListss // here source objectlist to be copied to dest1array
}));
});
return config.CreateMapper();
}
}
}
namespace Automapper
{
public class SourceObject
{
public string sourceTypeField;
public SourceObj1 SourceObj1Field { get; set; }
}
public class SourceObj1
{
public string SourceObj1Id { get; set; }
public ICollection<SourceInnerObjList> SourceObjListss { get; set; }
}
public class SourceInnerObjList
{
public int SourceObjListItem1Id { get; set; }
public int SourceObjListItem2d { get; set; }
}
public class SourceInnerObj2List
{
public int? mycount { get; set; }
public int? yourcount { get; set; }
}
}
namespace Automapper
{
public class DestinationObject
{
public string destinationTypeField;
public destinationObjectArray[] destinationObjectArrayField;
}
public class destinationObjectArray
{
public string mydestinationArrayField;
public string myField1;
public destinationInnerObject1Array[] dest1Array;
public destinationInnerObject2Array[] dest2Array;
}
public class destinationInnerObject1Array
{
public string destinationInnerObjectItem11;
public string destinationInnerObjectItem21;
}
public class destinationInnerObject2Array
{
public string categoryTypeField;
public string valueField;
public string NumberField;
}
}
While executing the mapping i am getting "Missing type map configuration or unsupported mapping."
No matter how I configure ignores or custom mappings it seems to not like this nesting. Any Automapper experts out there who could tell me how a mapping with a complex object like this could be done.
It seems like your second ForMember doesn't work:
.ForMember(dest => dest.destinationObjectArrayField, o => o.MapFrom(src => new destinationObjectArray() //...
Because in you're defining your map to return destinationObjectArray()
and not destinationObjectArray[]!
So there is a map like:
destinationObjectArrayField -> destinationObjectArray()
and there is no map like:
destinationObjectArrayField -> destinationObjectArray[]
And Automapper is telling you that.
You should do something like this:
cfg.CreateMap<SourceObject, DestinationObject>()
.ForMember(dest => dest.destinationTypeField, o => o.MapFrom(src => src.sourceTypeField))
.ForMember(dest => dest.destinationObjectArrayField,
o => o.MapFrom(
src => src.SourceObj1Field
.SourceObjListss
.Select(x => new destinationObjectArray
{
myField1 = $"first_id: {x.SourceObjListItem2d} second_id: {x.SourceObjListItem1Id}"
})
.ToArray()
));
});
Also cleaning and formatting code is highly suggested, it's seems like you've simply got lost in it! IDE's can help with that.

Dapper Dommel - query join automatic mapping

I'm sorry for my bad english, but here it goes, I am using Dapper with Dapper Dommel to simplify operations like crud, but in Dommel's Github says that it supports Join operations too, so I'm trying to implement it on my code, so far I managed to return a simple entity with Get.
But when I am trying to use it for more complex operations like join, it raises an exception.
The error message says: SqlException: Need declare the scalar variable "#product_id".
But in single Get< T > it works.
Packages:
Dapper
Dommel
Dapper-FluentMap.Dommel
Dapper-FluentMap
GitHub Dommel
https://github.com/henkmollema/Dommel
Does someone managed to use Dapper Dommel to return multiple entities in join queries with automatic mapping ?
public class DbContext : IDisposable
{
public SqlConnection Connection { get; private set; }
public DbContext()
{
Connection = new SqlConnection("Server=localhost;Database=BikeStores;Trusted_Connection=True;");
OpenConnection();
}
private bool OpenConnection()
{
try
{
if (Connection.State != System.Data.ConnectionState.Open)
Connection.Open();
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
public void Dispose() => Connection.Close();
}
Dommel fluent map:
public class ProductMap : DommelEntityMap<Product>
{
public ProductMap()
{
ToTable("production.products");
Map(m => m.Id)
.ToColumn("product_id")
.IsKey()
.IsIdentity();
Map(m => m.Name)
.ToColumn("product_name");
Map(m => m.BrandId)
.ToColumn("brand_id");
Map(p => p.CategoryId)
.ToColumn("category_id");
Map(p => p.ModelYear)
.ToColumn("model_year");
Map(p => p.ListPrice)
.ToColumn("list_price");
}
}
Category mapping:
public class CategoryMap : DommelEntityMap<Category>
{
public CategoryMap()
{
ToTable("production.categories");
Map(m => m.Id)
.ToColumn("category_id")
.IsKey()
.IsIdentity();
Map(m => m.Name)
.ToColumn("category_name");
}
}
Register mappings:
public RegisterMappings()
{
FluentMapper.Initialize(config =>
{
config.AddMap(new ProductMap());
config.AddMap(new CategoryMap());
config.ForDommel();
});
}
Model:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int BrandId { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public int ModelYear { get; set; }
public decimal ListPrice { get; set; }
}
Get simple that works:
using (var connect = new DbContext())
{
var product = connect.Connection.Get<Product>(id);
return product;
}
Get Doesn't work:
using (var connect = new DbContext())
{
var prod = connect.Connection.Get<Product, Category, Product>(1, (product, category) =>
{
product.Category = category;
return product;
});
return prod;
}

AutoMapper not working with covariant interface

using AutoMapper;
namespace MapTest
{
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<X, Interf<object>>()
.ForMember(dest => dest.B, opt => opt.MapFrom(src => src.K))
.ForMember(dest => dest.A, opt => opt.Ignore());
});
X x = new X { K = 1 };
Interf<object> instance = new Cl<Y> { A = new Y() };
Mapper.Map(x, instance);
}
}
class Cl<T> : Interf<T>
{
public T A { get; set; }
public int B { get; set; }
}
interface Interf<out T>
{
T A { get; }
int B { get; set; }
}
class X
{
public int K { get; set; }
}
class Y
{
}
}
This code will cause an exception at Mapper.Map(x, instance), because AutoMapper seems to be unable to find the X -> Interf<object> map for mapping to the Cl<Y> object, even though I'm giving it a hint that instance is indeed of type Interf<object>. If I change the CreateMap line to:
cfg.CreateMap<X, Interf<Y>>()
it no longer crashes, because it can resolve Cl<Y> to Interf<Y>.
Is there any way to fix this?

Deserialize different json documents to the same object structure

I'm looking for the best approach for such scenario:
I'd like to create WebApi which returns to the client some object like:
{
id: 1,
name: "name1",
type: "type1"
}
I can retrieve such data from different data providers (document dbs) which can have different data structures like:
First source:
{
id: 1,
name: "name1",
type: "type1"
}
Second source:
{
productId: 1,
productName: "product",
productType: "type"
}
Third source:
{
itemId: 1,
itemName: "name",
itemType: "type"
}
What will be the best approach to make it easy to extend with next data providers? I'd like to add that I was thinking about JSON.NET lib as always. So I believe I'm looking for examples of different json mappings depend on data providers? Anyone can help with some example? Let me add also that it's just 'read-only' scenario, so I mean that WebApi calls different dbs => deserialize to some object => eventually manipulates on the object itself => send over http.
Automapper and three different dtos would be the most correct way imo. But if you want to do it a really simple way you could just create a single class with all the different properties and have corresponding properties use the same backing variable
class Item
{
string _id;
public string id
{
get
{
return _id;
}
set
{
_id = value;
}
}
public string productId
{
get
{
return _id;
}
set
{
_id = value;
}
}
public string itemId
{
get
{
return _id;
}
set
{
_id = value;
}
}
string _name;
public string name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public string productName
{
get
{
return _name;
}
set
{
_name = value;
}
}
public string itemName
{
get
{
return _name;
}
set
{
_name = value;
}
}
string _type;
public string type
{
get
{
return _type;
}
set
{
_type = value;
}
}
public string productType
{
get
{
return _type;
}
set
{
_type = value;
}
}
public string itemType
{
get
{
return _type;
}
set
{
_type = value;
}
}
}
One more possible way to do that is use serialization settings with custom contract resolver object which overrides ResolvePropertyName method.
You can use AutoMapper to solve this problem.
http://automapper.org/
https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
Try the sample below
public class ReturnObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
public class Source1
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
public class Source2
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductType { get; set; }
}
public class Source3
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string ItemType { get; set; }
}
AutoMapper Profile
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
//Same properties
CreateMap<Source1, ReturnObject>();
//Difference properties
CreateMap<Source2, ReturnObject>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(f => f.ProductId))
.ForMember(dest => dest.Name, opt => opt.MapFrom(f => f.ProductName))
.ForMember(dest => dest.Type, opt => opt.MapFrom(f => f.ProductType));
CreateMap<Source3, ReturnObject>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(f => f.ItemId))
.ForMember(dest => dest.Name, opt => opt.MapFrom(f => f.ItemName))
.ForMember(dest => dest.Type, opt => opt.MapFrom(f => f.ItemType));
}
}

System.InvalidOperationException' occurred in AutoMapper.dll. Additional information: Mapper not initialized

I use to find AutoMapper very simple to use. I am struggling with the new version. I have two types:
namespace VehicleMVC.Models
{
public class CarModel
{
public int id { get; set; }
public string make { get; set; }
public string model { get; set; }
}
}
and:
namespace Business
{
public class Car
{
private int _id;
private string _make;
private string _model;
public int id
{
get { return _id; }
set { _id = value; }
}
public string make
{
get { return _make; }
set { _make = value; }
}
public string model
{
get { return _model; }
set { _model = value; }
}
}
}
I have tried this in CarController:
public CarController()
{
service = new Service.Service();
//Mapper.Initialize(cfg => cfg.CreateMap<Business.Car,CarModel>());
//Mapper.Initialize(cfg => cfg.CreateMap<List<CarModel>, List<Business.Car>>());
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Business.Car, CarModel>();
} );
config.AssertConfigurationIsValid();
}
private CarModel getCarModel(Business.Car BusinessCar)
{
CarModel CarModel = AutoMapper.Mapper.Map<CarModel>(BusinessCar);
return CarModel;
}
The error I get is: An exception of type 'System.InvalidOperationException' occurred in AutoMapper.dll. Additional information: Mapper not initialized. Call Initialize with appropriate configuration. but was not handled in user code. What is wrong?
Once you have created your configuration, you must initialize the mapper with it:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Business.Car, CarModel>();
};
config.AssertConfigurationIsValid();
Mapper.Initialize(config);

Categories

Resources