I have the latest 3.1.1 version of AutoMapper. For some reason the IsSourceValueNull when using ForAllMemebers doesn't seem to work or I am expecting a different result:
Here is an example of what I am trying to do. Please refrain from commenting on the DTOs looking exactly like the Entities. This is just an example of what I am running into with a more complex model.
public class User{
public int Id {get;set;}
public string UserName {get;set;}
public virtual int? ContactId {get;set;} //Foreign Key to contact object
public virtual Contact Contact {get;set;}
}
public class Contact {
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
public class UserDto {
public int Id {get;set;}
public string UserName {get;set;}
public int? ContactId {get;set;} //Foreign Key to contact object
public ContactDto Contact {get;set;}
}
public class ContactDto {
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
The code for the mapping looks something like this:
AutoMapper.Mapper.CreateMap<User,UserDto>().ForAllMembers(u => u.Condition(s => !s.IsSourceValueNull));
AutoMapper.Mapper.CreateMap<Contact,ContactDto>();
I am getting an error that the Source Value cannot be null. Meaning, the Contact is null coming back from the DB, which is OK, but AutoMapper is not running the condition for the Cotnact or ContactId. Both can be null in the DB. I have had to resort to checking if the source is null inside a ForMember block.
Related
I have Biller, BillerReference, BillerSetting DbSet.
BillerReference and BillerSetting has BillerId as foreign key relation.
This is Biller.cs
public class Biller : FullAuditedEntity
{
[Required]
public virtual string Name {get;set;}
public virtual decimal? Amount {get;set;}
public virtual List<BillerReference> BillerReferences {get;set;}
public virtual List<BillerSetting> BillerSettings {get;set;}
}
BillerReference.cs
public class BillerReference : FullAuditedEntity
{
[Required]
public virtual int? BillerId {get;set;}
[Required]
public virtual string Key {get;set;}
[Required]
public virtual string Value {get;set;}
}
BillerSetting.cs
public class BillerSetting : FullAuditedEntity
{
[Required]
public virtual int? BillerId {get;set;}
[Required]
public virtual string Name {get;set;}
[Required]
public virtual string URL {get;set;}
}
And then, I created BillerDbContext, which also include the BillerReference DbSet and BillerSetting DbSet.
And then, I created BillerRepository.
And then, I created BillerServiceAppService class in Application Layer.
When I call GetBiller(int Id) function as below
public async Task<BillerForEdit> GetBiller(int Id)
{
var biller = _billerRepo.GetAll()
.Include(x => x.BillerReferences)
.Include(x => x.BillerSettings)
.where(x => x.Id==Id);
//convert and assign data by ObjectMapper here !
//but, when got Biller object, BillerReferences and BillerSettings are Count=0!
In above function, I got Biller, but this is no BillerReferences and BillerSetting.
Please help me :D
It seems like your GetAll function gets all by using something like context.Billers.ToList(). The two list runs a select query and calls the data. Running include after this will not connect to the database to fetch your BillerReferences or BillerSetting.
Based on your usage, your easiest solution is implementing your GetAll class like this:
public IQueryable<Billing> GetAll() => context.Billers;
My domain objects are like:
public class MainType {
public int Id {get;set;}
public string Name {get;set;}
public List<TypeA> A_List {get;set;}
public List<TypeB> B_List {get;set;}
... other properties
}
public class TypeA {
public int Id {get;set;}
public string Name {get;set;}
... other properties
}
public class TypeAMapping {
public int TypeAId {get;set;}
public int MainTypeId {get;set;}
public int DisplayOrder {get;set;}
}
public class TypeB {
public int Id {get;set;}
public string Name {get;set;}
... other properties
}
public class TypeBMapping {
public int TypeBId {get;set;}
public int MainTypeId {get;set;}
public int DisplayOrder {get;set;}
}
Azure Search index documents does not support for complex types so I need to flatten these all classes into a model as described here.
So, I created a class like this one:
public class MainTypeDocumentModel {
public int Id {get;set;}
public string Name {get;set;}
public List<string> A_Id_List {get;set;}
public List<string> A_Name_List {get;set;}
public List<string> A_DisplayOrder_List {get;set;}
public List<string> B_Id_List {get;set;}
public List<string> B_Name_List {get;set;}
public List<string> B_DisplayOrder_List {get;set;}
... other properties
}
The problem is I also need to process DisplayOrder property of the mapping classes. Which the documentation does not cover.
I can create queries to search MainTypeDocumentModel filtered by A_Id_List and/or B_Id_List. But I need to sort the documents (or score higher) with the values in X_DisplayOrder_List property of the documents.
I checked the Scoring Profile docs from Microsoft but couldn't figure out how to implement for this scenario.
It sounds like what you want is the equivalent of correlated sub-queries on the nested A's and B's. Unfortunately this is not currently possible in Azure Search since it requires built-in support for complex types. This is on our radar but there is no ETA at this time.
In the meantime, you can consider other ways of modeling your domain types as Azure Search indexes. One option is full denormalization; Have an A index and a B index, and repeat Id and Name for each combination with As and Bs. Another option is full normalization; Have separate indexes for MainType, A, B, and the relations between them, and do the "joins" on the client side. There are tradeoffs involved depending on your query patterns and update frequency. This thread on the MSDN forums covers these options in a bit more detail.
Can any one suggest to me where i made the mistake?
public class DataModelProduct
{
public int Id {get;set;}
public string Name {get;set;}
public string Price {get;set;};
public string Brand {get;set;}
public string Color {get;set;}
public string Dimentions {get;set;}
public string Type {get;set;}
public string Network {get;set;}
}
public class Product
{
public int Id {get;set;}
public string Name {get;set;}
public string Price {get;set;}
public Specification Spec {get;set;}
}
public class Specification
{
public string Brand {get;set;}
public string Color {get;set;}
public string Dimentions {get;set;}
public string Type {get;set;}
public string Network {get;set;}
}
AutoMapper.Mapper.CreateMap< DataModelProduct, Product>();
AutoMapper.Mapper.CreateMap< DataModelProduct, Specification>();
You can assume Product class is Core Model and DataModelProduct is a Database Model
The Product properties are mapped but the Specification property is null.
You need to give all your properties accessors for AutoMapper to function:
e.g.
public string Brand { get; set; }
public Specification Spec { get; set; }
And your mapping init code should be something like
var config = new MapperConfiguration(cfg => {
cfg.CreateMap< DataModelProduct, Product>();
cfg.CreateMap< DataModelProduct, Specification>();
});
And your runtime code like:
var product = Mapper.Map(dataModelProduct, new Product());
And the mapping to Specification:
var product = Mapper.Map(dataModelProduct, new Product());
product.Specification = new Specification();
Mapper.Map(dataModelProduct, product.Specification);
I use Automapper all the time, and for some reason the issue is escaping me. Below is an example of the code I'm using (names have been changed.)
Problem
All objects are mapped but the Keys object.
Code
I have a flat object coming from a WCF service.
public class FlatDTO
{
public string Key1 {get;set;}
public string Key2 {get;set;}
public string Name {get;set;}
public DateTime Date {get;set;}
}
This is the structure for my Business Object:
public class BaseModel
{
public Datetime Date{get;set;}
}
public class Keys
{
public string Key1 {get;set;}
public string Key2 {get;set;}
}
public class Summary : BaseModel
{
public Keys List {get;set;}
public string Name{get;set;}
public Summary ()
{
List = new Keys();
}
}
Below is my profile for Automapper (the init of the profile is done in the global.aspx page)
internal class MapDTO : Profile
{
protected override void configure()
{
Mapper.CreateMap<FlatDTO,BaseModel>().IgnoreAllNonExisting();
Mapper.CreateMap<FlatDTO,Role>().IgnoreAllNonExisting();
Mapper.CreateMap<FlatDTO,Summary>().IgnoreAllNonExisting();
}
Help with this 'simple' issue would be great.
I am getting an AutoMapper Exception when i try to Map my DomainModel to ViewModel,
Here is my Domain Model Class,
public class Source{
public string Name {get;set;}
..............
public CustomCollection EmpDetails {get;set;}
}
public class CustomCollection:CollectionBase,IEnumerable<ClassA> {
public CustomCollection{}
public int Add(ClassA classA)
{
return List.Add(classA);
}
..........
}
public class ClassA{
public string EmpNumber {get;set;}
public string EmpName {get;set;}
public string Designation {get;set;}
}
Here is my ViewModel
public class SourceDTO{
public string Name {get;set;}
public IList<EmpDTO> EmpDetails {get;set;}
}
public class EmpDTO{
public string EmpNumber {get;set;}
public string EmpName {get;set;}
public string Designation {get;set;}
}
Here is my AutoMapper Code,
AutoMapper.Mapper.CreateMap<Source, SourceDTO>()
.ForMember(x => x.EmpDetails, y => y.MapFrom(src => src.EmpDetails));
I am getting error here, It doesn't say any detail inner exceptions,
I hope someone can help us out.
You need to include a mapping to go from ClassA to EmpDTO:
Mapper.CreateMap<ClassA, EmpDTO>();
And you should be all set.