Automapper - Map model from lowercase to pascal case - c#

I have two models.
Source model:
public sealed class adresse
{
public string strasse { get; set; }
public string hausnummer { get; set; }
public string plz { get; set; }
public string ort { get; set; }
public string landCode { get; set; }
}
Destination model:
public sealed class Adresse
{
public string Strasse { get; set; }
public string Hausnummer { get; set; }
public string Plz { get; set; }
public string Ort { get; set; }
public string LandCode { get; set; }
}
Therefore I created a mapping with automapper and a unit test.
public class AddressMapper
{
public Address map()
{
adresse add = new adresse();
add.hausnummer = "1";
add.ort = "Test";
AutoMapper.Mapper.Initialize(cfg => {
cfg.AddProfile<Profile1>();
});
return AutoMapper.Mapper.Map<Address>(add);
}
}
public class LowerNamingConvention : INamingConvention
{
public Regex SplittingExpression
{
get { return new Regex(#"[\p{Ll}a-z A-Z 0-9]+(?=_?)"); }
}
public string SeparatorCharacter
{
get { return string.Empty; }
}
}
public class Profile1 : Profile
{
protected override void Configure()
{
SourceMemberNamingConvention = new LowerNamingConvention();
DestinationMemberNamingConvention = new PascalCaseNamingConvention();
CreateMap<adresse, Address>();
}
}
[TestFixture]
public class AddressMapperTest
{
[Test]
public void TestMapper()
{
var sut = new AddressMapper();
var value = sut.map();
}
}
When I'm running the test every field in the destination model is null.
As you can see there is a problem with the naming because some names in the source model I have some times different naming conventions like lower case or lower camel case. Does anyone have an idea to solve this problem? Or do I have to map everything manualy?

You should use DataContract and DataMember attributes as below, so that you don't need to give property a same name and also you can follow coding standards.
[DataContract(Namespace = "")]
public class YourClass
{
[DataMember(EmitDefaultValue = false, Name = "myVariable")]
public string MyVariable { get; set; }
}

I think i found a proper solution for my problem. Sorry for not being familar with Regex. I just combined the RegExes from
AutoMapper/src/AutoMapper/PascalCaseNamingConvention.cs
and
AutoMapper/src/AutoMapper/LowerUnderscoreNamingConvention.cs
into my own naming convention. Might be that there are cases wich can cause issues. But as far as I have tested it works.
public class LowerNamingConvention : INamingConvention
{
public Regex SplittingExpression
{
get { return new Regex(#"[\p{Ll}0-9]+(?=$|\p{Lu}[\p{Ll}0-9])|\p{Lu}?[\p{Ll}0-9]+)"); }
}
public string SeparatorCharacter
{
get { return string.Empty; }
}
}

Related

How to elegantly map form flat object to complex list object using Automapper?

I have a flat complex type which I need to map to a complex type within a list. I have achieved it using the below code but it is not elegant. The mapping for each individual item has to be specified explicitly even though the types and names match. I wanted to know if there is a more elegant way of doing this without such verbosity and tight coupling?
using AutoMapper;
MapperConfiguration _config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<FlatObject, MyDTO>()
.ForMember(dst => dst.ListObject, opt => opt.MapFrom(src => new List<ListObject> {
new ListObject {
DTOCustObject = new DTOCustObject {
MyString = src.CustType.MyString,
MyInt = src.CustType.MyInt,
MyBool = src.CustType.MyBool,
//Others...
DTOMyObject = new DTOMyObject {
SomeString = src.CustType.MyObject.SomeString
//Others...
}
}
}
}));
});
_config.AssertConfigurationIsValid();
var flatObject = new FlatObject();
flatObject.CustType.MyString = "ABC123";
flatObject.CustType.MyInt = 12345;
flatObject.CustType.MyBool = true;
flatObject.CustType.MyObject.SomeString = "Some String Content";
IMapper mapper = new Mapper(_config);
var myDTO = mapper.Map<MyDTO>(flatObject);
Console.ReadKey();
//###############
//Entity - Source
//###############
public class FlatObject
{
public CustType CustType { get; set; } = new CustType();
}
public class CustType
{
public string? MyString { get; set; }
public int MyInt { get; set; }
public bool MyBool { get; set; }
public MyObject MyObject { get; set; } = new MyObject();
}
public class MyObject
{
public string? SomeString { get; set; }
}
//#################
//DTO - Destination
//#################
public class MyDTO
{
public List<ListObject> ListObject { get; set; } = new List<ListObject>();
}
public class ListObject
{
public DTOCustObject DTOCustObject { get; set; } = new DTOCustObject();
}
public class DTOCustObject
{
public string? MyString { get; set; }
public int MyInt { get; set; }
public bool MyBool { get; set; }
public DTOMyObject DTOMyObject { get; set; } = new DTOMyObject();
}
public class DTOMyObject
{
public string? SomeString { get; set; }
}
public class MyDTO
{
public List<DTOCustObject> DTOCustObjectList{ get; set; } = new List<DTOCustObject>();
}
public class DTOCustObject
{
public string? MyString { get; set; }
public int MyInt { get; set; }
public bool MyBool { get; set; }
public DTOMyObject DTOMyObject { get; set; } = new DTOMyObject();
public DTOCustObject(ICustObjectMapper mapper){
MyString = mapper.GetMyString();
MyInt = mapper.GetMyInt();
MyBool = mapper.GetMyBool();
DTOMyObject = mapper.GetDTOMyObject();
}
}
public class DTOMyObject
{
public string? SomeString { get; set; }
public DTOMyObject(IDTOmyObjectMapper mapper)
{
SomeString = mapper.GetSomeString();
}
}
Now simply implement the Interfaces and their GetMethods on the source object, in the corresponding classes. And presto. No need for any framework of any kind.
This means, no framework, will try change syntax, and force a rewrite. You aren't locked into keeping it updated, there won't be any dependencies on it, etc.
You are free, and the time it takes you to configure, and annotate the code, is equal to the amount of time it takes you to just write the damn interfaces and implementations.
If your objects are autogenerated, simply use the partial keyword, and make the interface implementations in a partial class. Problem solved.
Something to this effect:
public class CustType : ICustObjectMapper
{
public string? MyString { get; set; }
public int MyInt { get; set; }
public bool MyBool { get; set; }
public MyObject MyObject { get; set; } = new MyObject();
string GetMyString(){
return MyString;
}
// etc for the rest of the basic types.
DTOMyObject GetMyObject(){
return new DTOMyObject(MyObject)
}
}
public class MyObject : IDTOmyObjectMapper
{
public string? SomeString { get; set; }
public string GetSomeString()
{
return SomeString;
}
}
Of course, if you don't know how to declare an interface...
public interface ICustObjectMapper {
string GetMyString();
//etc.
}
Now please, for the love of everything on this planet. STOP USING MAPPING FRAMEWORKS IN C#, IT MAKES NO SENSE!

Abstract class generator

I'm at loss here. I want to refactor a part of the code that uses no abstract classes. I'm familiar with json2csharp. That converts a JSON file to the C# classes so it can be easily deserialized.
Is there a similar site/tool that accepts as input several C# classes and generates basic abstract classes based on those?
This would make the refactoring easier as I don't need to create all the different abstract classes.
Very simple example:
Input:
public class TestClass1
{
public string TestID { get; set; }
public string TestName { get; set; }
public int TestValue1 { get; set; }
public TestClass1()
{
}
}
public class TestClass2
{
public string TestID { get; set; }
public string TestName { get; set; }
public int TestValue2 { get; set; }
public TestClass2()
{
}
}
Output:
public abstract class ATestClass
{
public string TestID { get; set; }
public string TestName { get; set; }
protected ATestClass()
{
}
}
You can get something working pretty quickly if you use the Roslyn code analysis and code generation. Here’s a quick example how that could work. Note that this is somewhat fragile with detecting common properties since its based on the syntax instead of the actual semantics (making string Foo and String Foo incompatible properties). But for code that is actually generated by another code generator, this should work fine since the input should be consistent.
var input = #"
public class TestClass1
{
public string TestID { get; set; }
public string TestName { get; set; }
public string OtherTest { get; set; }
public int TestValue1 { get; set; }
public TestClass1()
{
}
}
public class TestClass2
{
public string TestID { get; set; }
public string TestName { get; set; }
public int OtherTest { get; set; }
public int TestValue2 { get; set; }
public TestClass2()
{
}
}";
// parse input
var tree = CSharpSyntaxTree.ParseText(input);
// find class declarations and look up properties
var classes = tree.GetCompilationUnitRoot().ChildNodes()
.OfType<ClassDeclarationSyntax>()
.Select(cls => (declaration: cls, properties: cls.ChildNodes().OfType<PropertyDeclarationSyntax>().ToDictionary(pd => pd.Identifier.ValueText)))
.ToList();
// find common property names
var propertySets = classes.Select(x => new HashSet<string>(x.properties.Keys));
var commonPropertyNames = propertySets.First();
foreach (var propertySet in propertySets.Skip(1))
{
commonPropertyNames.IntersectWith(propertySet);
}
// verify that the property declarations are equivalent
var commonProperties = commonPropertyNames
.Select(name => (name, prop: classes[0].properties[name]))
.Where(cp =>
{
foreach (var cls in classes)
{
// this is not really a good way since this just syntactically compares the values
if (!cls.properties[cp.name].IsEquivalentTo(cp.prop))
return false;
}
return true;
}).ToList();
// start code generation
var workspace = new AdhocWorkspace();
var syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.CSharp);
// create base class with common properties
var baseClassDeclaration = syntaxGenerator.ClassDeclaration("BaseClass",
accessibility: Accessibility.Public,
modifiers: DeclarationModifiers.Abstract,
members: commonProperties.Select(cp => cp.prop));
var declarations = new List<SyntaxNode> { baseClassDeclaration };
// adjust input class declarations
commonPropertyNames = new HashSet<string>(commonProperties.Select(cp => cp.name));
foreach (var cls in classes)
{
var propertiesToRemove = cls.properties.Where(prop => commonPropertyNames.Contains(prop.Key)).Select(prop => prop.Value);
var declaration = cls.declaration.RemoveNodes(propertiesToRemove, SyntaxRemoveOptions.KeepNoTrivia);
declarations.Add(syntaxGenerator.AddBaseType(declaration, syntaxGenerator.IdentifierName("BaseClass")));
}
// create output
var compilationUnit = syntaxGenerator.CompilationUnit(declarations);
using (var writer = new StringWriter())
{
compilationUnit.NormalizeWhitespace().WriteTo(writer);
Console.WriteLine(writer.ToString());
}
This would generate the following output:
public abstract class BaseClass
{
public string TestID
{
get;
set;
}
public string TestName
{
get;
set;
}
}
public class TestClass1 : BaseClass
{
public string OtherTest
{
get;
set;
}
public int TestValue1
{
get;
set;
}
public TestClass1()
{
}
}
public class TestClass2 : BaseClass
{
public int OtherTest
{
get;
set;
}
public int TestValue2
{
get;
set;
}
public TestClass2()
{
}
}

AutoMapper throwing StackOverflowException when calling ProjectTo<T>() on IQueryable

I have created classes using EF Code First that have collections of each other.
Entities:
public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<AppUser> Teachers { get; set; }
public Field()
{
Teachers = new List<AppUser>();
}
}
public class AppUser
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
public virtual List<Field> Fields { get; set; }
public AppUser()
{
Fields = new List<FieldDTO>();
}
}
DTOs:
public class FieldDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<AppUserDTO> Teachers { get; set; }
public FieldDTO()
{
Teachers = new List<AppUserDTO>();
}
}
public class AppUserDTO
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
public List<FieldDTO> Fields { get; set; }
public AppUserDTO()
{
Fields = new List<FieldDTO>();
}
}
Mappings:
Mapper.CreateMap<Field, FieldDTO>();
Mapper.CreateMap<FieldDTO, Field>();
Mapper.CreateMap<AppUserDTO, AppUser>();
Mapper.CreateMap<AppUser, AppUserDTO>();
And I am getting StackOverflowException when calling this code (Context is my dbContext):
protected override IQueryable<FieldDTO> GetQueryable()
{
IQueryable<Field> query = Context.Fields;
return query.ProjectTo<FieldDTO>();//exception thrown here
}
I guess this happens because it loops in Lists calling each other endlessly. But I do not understand why this happens. Are my mappings wrong?
You have self-referencing entities AND self-referencing DTOs. Generally speaking self-referencing DTOs are a bad idea. Especially when doing a projection - EF does not know how to join together and join together and join together a hierarchy of items.
You have two choices.
First, you can force a specific depth of hierarchy by explicitly modeling your DTOs with a hierarchy in mind:
public class FieldDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<TeacherDTO> Teachers { get; set; }
public FieldDTO()
{
Teachers = new List<TeacherDTO>();
}
}
public class TeacherDTO
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
}
public class AppUserDTO : TeacherDTO
{
public List<FieldDTO> Fields { get; set; }
public AppUserDTO()
{
Fields = new List<FieldDTO>();
}
}
This is the preferred way, as it's the most obvious and explicit.
The less obvious, less explicit way is to configure AutoMapper to have a maximum depth it will go to traverse hierarchical relationships:
CreateMap<AppUser, AppUserDTO>().MaxDepth(3);
I prefer to go #1 because it's the most easily understood, but #2 works as well.
Other option is using PreserveReferences() method.
CreateMap<AppUser, AppUserDTO>().PreserveReferences();
I use this generic method:
public static TTarget Convert<TSource, TTarget>(TSource sourceItem)
{
if (null == sourceItem)
{
return default(TTarget);
}
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var serializedObject = JsonConvert.SerializeObject(sourceItem, deserializeSettings);
return JsonConvert.DeserializeObject<TTarget>(serializedObject);
}
...
MapperConfiguration(cfg =>
{
cfg.ForAllMaps((map, exp) => exp.MaxDepth(1));
...
When you giving 1 navigation_property to 2nd entity and visa-versa it go in an infinite loop state. So, the compiler automatically throws a Stackoverflow exception.
So, to avoid that, you just need to remove one navigation_property from any of the entities.

Trying to work out these interfaces

I'm trying to create some interfaces. The IReportSection object will have one string and a collection of items, which could be different depending on what we're working with. Do I need to make it generic?
The IReport will have one string and a collection of IReportSection.
Here's how I'm trying to define it now.
public interface IReport
{
string ReportName { get; set; }
ICollection<IReportSection> ReportSections { get; }
}
public interface IReportSection
{
string ReportSectionName { get; set; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection ReportItems { get; set; }
}
And my models:
pulic class ProjectSubmissionViewModel
{
public int ProjectSubmissionId { get; set; }
public string SubmissionTitle { get; set; }
}
pulic class AffiliateViewModel
{
public int AffiliateId { get; set; }
public string AffiliateName { get; set; }
}
This is how I'm trying to use it in code:
public class ChapterAffiliates : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Affiliates"; } }
public ICollection<AffiliateViewModel> ReportItems { get; set; }
}
public class ChapterTitles : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Titles"; } }
public ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }
}
public class SubmissionListViewModel : IReport
{
public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }
public ICollection<AffiliateViewModel> Affiliates{ get; set; }
public string ReportName { get; set; }
public ICollection<IReportSection> ReportSections
{
get
{
var affiliateSection = new ChapterAffiliates
{
ReportItems = Affiliates
};
var titleSection = new ChapterTitles
{
ReportItems = Submissions.Where(s => s.SubmissionTitle.Contains("SomePhrase")).ToList()
};
var sections = new List<IReportSection> { {subSection}, {titleSection} };
return sections;
}
}
}
I'm not sure how to best define this. I'm pretty sure I've done it before, but it's not coming to me.
Are the type parameters for TRType all the same within a certain report? E.g. will you have report sections with different report types in them?
If all types within a report are the same, the solution is relatively simple:
public interface IReport<T> { ... }
If this is not the case - you'll have to do something different, e.g:
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase<TRType> : IReportSection {
...
}
This allows you to put different underlying types in the ReportSections collection related to the report. You'll have to do some more work to get the exact information that you need out of each report section.

Readonly nested object properties

I'm having a problem defining these 2 classes:
public class Article
{
public Article(long ID, string Name, ArticleFamily Family)
{
//...Initializer...
}
public ArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
I have a collection of Article and each one belongs to a family.
Now, given that I have a certain ArticleFamily object I should be able to change its Description and it gets eventually persisted to a DataBase. (I left out that part for simplicity)
But I should not be able to do this:
Article art = SomeMethodReturningArticle();
art.Family.Description = "SomeOtherValue";
I should be able to change the Family of an Article entirely, replacing it with a new ArticleFamily object, but I shouldn't be able to change just the description.
Should I create a copy of the ArticleFamily class with readonly properties like this:
public class ArticleFamilyReadonly
{
ArticleFamily _family;
public ArticleFamilyReadonly(ArticleFamily Family)
{
_family = Family;
}
public int ID { get { return _family.ID; } }
//etc...
}
How can I do this in a clean way?
Here's what I threw together in LinqPad:
void Main()
{
var art = new Article(1,"2", new ArticleFamily(1, "Test"));
art.Family.Description = "What?"; // Won't work
var fam = art.Family as ArticleFamily;
fam.Description = "This works"; // This works...
}
public class Article
{
public Article(long ID, string Name, IArticleFamily Family)
{
//...Initializer...
}
public IArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily : IArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
public interface IArticleFamily
{
int ID { get; }
string Description { get;}
}
Cannot edit directly from the Article object unless cast to ArticleFamily object.

Categories

Resources