fluentsprings / expressmapper Goto Github PK
View Code? Open in Web Editor NEWMapping .Net types
Home Page: http://www.expressmapper.org
License: Other
Mapping .Net types
Home Page: http://www.expressmapper.org
License: Other
Mapper Interface is required to be used in unit tests. IMapper (or similar name) with all Mapper static class functionality. Mapper static class should stay static, but instance of IMapper Interface implementation created as a private static variable.
I can't compile the following code (c# console application with ExpressMappre 1.1.2 nuget package.
https://gist.github.com/frost555/bf17d07191816b810e04
I get the the following error: Cannot resolve symbol "MapTo"
What am i doing wrong?
Updating benchmarks for hand-written mappings like this:
dst.Products = src.Products.Select(Map).ToList();
to creating of List(Specifying source count).
Hi there :)
Please consider the following model:
public class Target
{
public TargetNestedClass TargetNested;
}
And mapping:
var mapper = Mapper.Register<Source, Target>()
.Member(p => p.TargetNested.TargetNestedInt,
p => p.SourceNested.SourceNestedInt)
A call to Mapper.Map(source, target);
would result in an null reference exception, since target.TargetNested
is null when target
is internally passed to the generated BinaryExpression. Am I missing something here? Or should the client make sure that all possible paths are initialized? I saw that the destination expression is added an initialization node (GetDestionationVariable()
) when declaring it's mapping, but from what I understand (and experiencing) it's applied only to the root parameter. Am I wrong about that?
0c90227 added a feature that throws an exception when After event is already registered, but now an exception is raised even where it should not be, i.e.:
Mapper.Register<A,B>()
.Member(dest => dest.b, src => src.a)
.Ignore(dest=>dest.c)
.After((src, dest) => dest,d => src.c * 2)
Mapper.Register<A,C>()
.After((src, dest) => dest,b => src.c)
throws an exception where there should be none.
Dear Yuriy,
thank you for a great job with the mapper, I like it very much.
However I just stumpled upon a problem with thread safety (the problem might be elsewhere but at least a quick look at the mapper source codes gave me the impression it is about thread safety).
I am using the mapper version 1.1.2 and I get the exception "An item with the same key has already been added." randomly when I call
Mapper.Map<IEnumerable<ItemA>, List<ItemB>>(someItems)
I believe the issue lies in the fact that Mapper.Map is not enclosed in a lock statement (which is fine of course), but in this case the call to Map method at the end results in calling MappingService.PrecompileCollection method which definetely should be thread safe.
Here is the stack trace:
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at ExpressMapper.MappingServiceProvider.PrecompileCollection[T,TN]() in C:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingServiceProvider.cs:line 86
at ExpressMapper.MappingServiceProvider.Map[T,TN](T src, TN dest) in C:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingServiceProvider.cs:line 192
at ExpressMapper.Mapper.Map[T,TN](T src) in C:\SourceCode\ExpressMapper\ExpressMapper NET40\Mapper.cs:line 35
Feel free to let me know if you need more details.
Thank you in advance, Tony
Currently mapping from Dictionary<TK, TV> to Dictionary<TK, TV> (e.g. Dictionary<string, string>) which cause an error:
Can't cast collection of KeyValuePair<TK, TV> to Dictionary<TK, TV>. Expressmapper needs to handle dictionary mapping directly instead of converting them to collections. It's a very common type and not having it is quite limiting.
Current workaround is to define custom mapper that maps above and copies data directly.
Ability to map to existing destination:
Map<TSrc,TDest>(TSrc src, TDest dest)
Hi,
I just stumbled upon the following issue: I have an object A, with some properties. One of the properties is an IEnumerable<C>. For my viewmodel, I have object B extends A.
When I register my mapping .Register<A, B>() and then run a .Compile(), EM throws the following exception: There is no mapping has bee found. Source Type: C, Destination Type: C.
I don't think I have to register a mapping from C to C...
PD: Nitpick text correction. The text should read "No mapping has been found between Source Type: A and Destination Type: B".
Hello,
It would be great to add ServiceStack's auto-mapping to the benchmarks.
thank you
mappingService.Register<AccountModel, AccountType>().
Value(x => x.IdSpecified, false).
Member(x => x.BankId, x => x.Bank.Id).
Member(x => x.Currency, x => x.Currencies);
Currency - string[]
Currencies - IList
Exception:
There is no mapping has bee found. Source Type: System.String, Destination Type: System.String
I am using Unity3d, it use a old mono .net which only support to 3.5.
Nullable to NonNullable mappings and vice versa - throws exception
e.g. - product.weight - decimal? and productViewModel.weight - decimal
Register<Product, ProductViewModel>()
.Member(dest => dest.Weight, src => src.Weight);
Member specification just for illustration purposes.
Here's a unit test for you:
[TestFixture]
public class Tests
{
[Test]
public void Should_map_Thing()
{
Mapper.Register<Thing, Thing>();
var src = new Thing { Name = "Name" };
var dest = new Thing();
var result = Mapper.Map(src, dest, src.GetType(), dest.GetType())
as Thing;
Assert.That(result.Name, Is.EqualTo(src.Name));
}
internal class Thing { public string Name { get; set; } }
}
I have a problem with define mapping between following classes:
public class Source{
public string Name{get;set;}
public string Value{get;set;}
public IList
public class Destination{
public string Name{get;set;}
public string Value{get;set;}
public IList Dependants{get;set;}
}
During compilation I get stack overflow. If I try to map instance of Source to instance of Destination without compiling the registered mappings the stack overflow is also signaled.
Create Expressmapper extensions' methods for Map and Projection
source collection property is null - throws NullReferenceException
I am trying to use multiple .After
handlers and they don't seem to work correctly. Only one of the handlers gets called (not sure what decides which one).
Mapper.Register<Foo, Bar>()
.After((src, dest) => afterHandler1(src, dest))
.After((src, dest) => afterHandler2(src, dest))
.After((src, dest) => afterHandler3(src, dest));
When I change the code this way, it works:
Mapper.Register<Foo, Bar>()
.After((src, dest) =>
{
afterHandler1(src, dest);
afterHandler2(src, dest);
afterHandler3(src, dest);
});
This is counter-intuitive and I think that the first sample should either work as well, or at least throw exception to avoid bugs.
ExpressMapper is not thread safe.
Example:
An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at ExpressMapper.MappingService.CompileCollection[T,TN]() in c:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingService.cs:line 504
at ExpressMapper.MappingService.PreCompileCollection[T,TN]() in c:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingService.cs:line 493
at ExpressMapper.MappingService.Map[T,TN](T src) in c:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingService.cs:line 156
Hello,
Do you have or plan to implement an AssertConfigurationIsValid() equivilent, found in automapper? This basically checks all maps are valid during build.
Woudl be a great feature.
Thanks
Hi,
i am using xUnit2.
In my constructor i do my registrations (test setup) and Mapper.Complile() and my tests throw exceptions like the following:
Result StackTrace:
at ExpressMapper.MappingService.RegisterT,TN in c:\SourceCode\ExpressMapper\ExpressMapper NET40\MappingService.cs:line 34
at ExpressMapper.Mapper.RegisterT,TN in c:\SourceCode\ExpressMapper\ExpressMapper NET40\Mapper.cs:line 49
at Bitusion.Overlook.Repository.RepositoryMapperConfig.Configure() in D:\dev\projects\Overlook\src\overlook\Bitusion.Overlook.Repository\RepositoryMapperConfig.cs:line 12
at Bitusion.Overlook.Web.ModelMappingConfig.Configure() in D:\dev\projects\Overlook\src\overlook\Bitusion.Overlook.Web\App_Start\ModelMappingConfig.cs:line 12
at Bitusion.Overlook.Web.Tests.Unit.Controllers.ApplicationControllerTests..ctor() in D:\dev\projects\Overlook\src\overlook\Bitusion.Overlook.Web.Tests.Unit\Controllers\ApplicationControllerTests.cs:line 30
Result Message: System.InvalidOperationException : Mapping from Bitusion.Overlook.Data.Models.ApplicationUserDbModel to Bitusion.Overlook.Business.Contracts.Models.ApplicationUserModel is already registered
Probable the way the tests run the setup is called multiple times and the lib does not allow multiple registrations of mappings.
Maybe it should check whether the registration exists in order to avoid double registration and exception, or the new one should replace the old one.
Maybe a UnregisterAll? Along with a Reset?
if you use that Mapper.Map<List, TDest[]> the collection mapping (not TSrc-to-TDest) are compiled, but collection-to-collection mappings are compiled at a runtime (of course only once). Making CollectionPrecompile<T,TN>() where T,TN are collection types - public.
Real support for IQueryable without casting to IEnumerable
I have some complex entities that I need to copy but exclude several Object-type properties. However, it wasn't working for me. Then I tried this simple example and found it doesn't work. It appears I get back the default(DestinationType)
var mapper = new MappingService();
mapper.Register<PartType, PartType>();
mapper.Compile();
// The only property is "Type"
var partType = new PartType()
{
Type = "Test"
};
var partTypeCopy = mapper.Map<PartType, PartType>(partType);
Assert.AreEqual(partTypeCopy.Type, partType.Type); // Fails here
Implement .Value() configuration method.
A common convention when generating ViewModel data that will be used as part of an api generating JSON is to use camelCasing. It would be great if there was a config setting to ignore case so firstName would automatically map to FirstName
System.IndexOutOfRangeException : Index was outside the bounds of the array.
Hi,
Right now I'm using ValueInjector as it simply let me do myObject.InjectFrom(otherObject). Having to register every mapping I have is simply impossible, as I usually have several mappings for different classes that follows some interface definitions.
Is there a way I can simply run something similar and EM do the registration on the fly?
As our previous discussion on codeproject,
you need to add support for mapping by convention as it's a very important feature and already implemented in other frameworks.
It would be great also if you made convention rules extendable somehow :)
Mapper.Register<ObjectItem, ObjectItemDetailsViewModel>()
.Member(dest => dest.AddressName, src => src.Address.Name)
.Member(dest => dest.SellerFirstName, src => src.Seller.FirstName)
If src.Address equals is null or src.Seller is null - throws NullReferenceException...
If destination is not a property but just a field - exception
.Member(dest => dest.Field, src => .......)
Null object cannot be converted to a value type
When mapping from a Database object - it's common to want to map the object to a viewModel ; and most of the time every single field in the view model should be mapped. Please provide functionality to enforce all fields are mapped ( so we don't make the mistake of typing a field incorrectly by accident ) . I moved from Mapster because I had bugs with Null values not being updated - but it has that feature and it's very useful. Thanks - great plugin.
Support for hierarchies mappings + EF dynamic generated proxies support:
public void MappingsRegistration()
{
Mapper.Register<Product,ProductViewModel>()
.Member(dest => dest.ProductName,
src = > src.Name);
Mapper.Register<FashionProduct,
FashionProductViewModel>()
.Base<Product,ProductViewModel>();
}
public void MappingsRegistration()
{
Mapper.Register<Product,ProductViewModel>()
.Mepper(dest => dest.ProductName,
src = > src.Name)
.Include<FashionProduct,
FashionProductViewModel>()
.Include<TechProduct,
techProductViewModel>();
}
Thank you guys - you are doing great job. I like ExpressMapper a lot :).
I have following problem:
public class A{
public IList<B> InstancesB {get;set;}
//.. other properties
}
public class B{
public A InstanceA {get;set;}
//.. other properties
}
public class AView{
public IList<BView> InstancesB {get;set;}
//.. other properties
}
public class BView{
public AView InstanceA {get;set;}
//.. other properties
}
How can I map such classes sets? With regular registration:
Mapper.Register<A, ViewA>()
Mapper.Register<B, ViewB>()
I receive stack overflow when I try to perform mapping. I suspect this is due to the fact that ExpressMapper doesn't track mapped objects and when it maps subobject it always creates new instance and as it is bidirectional reference it runs in infinite loop creating new instances untill receiving stack overflow.
I've got the advice from @anisimovyuriy to use .Before or .After to make the assignment manually.
The idea about using .Before or .After is tempting but it will only work if I one would like to provide mapping in one direction. I mean if you use .Before or .After for mapping A instances you will have to add .Ignore(src=>src.InstancesB) and make it manually in .Before/After. And it's fine - it will work great, but how in such case configure B to map its InstanceA to correct ViewA instance. Please remember that there are multiple instances of B in A.InstancesB collection and it would be perfect (at least from my point of view) if all of their mapped ViewB has assigned the same instance of ViewA. If I use the .Before/.After for B mapping registration then I will need some helper map of references between A and ViewA to get the correct ViewA assigned. Maybe in a way the ExpressMapper could handle it by me ๐.
This is not working for me, and I have the last stable version. I am gettnig this error:
"Expression of type 'System.Collections.Generic.List1[WCF.WcfService.SaleLineItem]' cannot be used for assignment to type 'System.Collections.ObjectModel.ObservableCollection
1[WCF.WcfService.SaleLineItem]'"
I only want to map this element:
public class Sale
{
public IEnumerable<SaleLine> SaleLines { get; set; }
}
To this one:
public class SaleHeaderItem
{
public ObservableCollection<SaleLineItem> SaleLineList { get; set; }
}
I am doing something like this:
Mapper.Register<Sale, SaleHeaderItem>()
.Member(dest => dest.SalesLineList, src => src.SaleLines);
Mapper.Register<SaleLine, SaleLineItem>();
Mapper.Compile();
class Program
{
static void Main(string[] args)
{
Mapper.Register<ContactData, ContactData>(); // Dont know why EM is asking for mapping of same type
Mapper.Register<ContactTable, ContactData>();
Mapper.Register<MailTable, MailData>().
Function(x => x.Contact, x => ResolveContact(x.Contact));
Mapper.Compile();
MailTable mailTable = new MailTable()
{
Contact = new ContactTable()
{
Key = "test",
IsPerson = true
}
};
MailData mail = Mapper.Map<MailTable, MailData>(mailTable);
Console.WriteLine(mail.Contact.GetType().ToString());
Console.ReadKey();
}
static ContactData ResolveContact(ContactTable contact)
{
ContactData destination = null;
if (contact.IsOrganization)
{
destination = new OrganizationData();
Mapper.Map<ContactTable, ContactData>(contact, destination);
}
else if (contact.IsPerson)
{
destination = new PersonData();
Mapper.Map<ContactTable, ContactData>(contact, destination);
}
else
{
destination = new ContactData();
Mapper.Map<ContactTable, ContactData>(contact, destination);
}
return destination;
}
}
class MailTable
{
public ContactTable Contact { get; set; }
}
class ContactTable
{
public string Key { get; set; }
public bool IsPerson { get; set; }
public bool IsOrganization { get; set; }
}
class MailData
{
public ContactData Contact { get; set; }
}
class ContactData
{
public string Key { get; set; }
}
class OrganizationData : ContactData
{
public string RegNr { get; set; }
}
class PersonData : ContactData
{
public string Surname { get; set; }
}
Consider this code.
Mapper.Register<Type1ReportPermissions[], Permission[]>()
.Member(dst => dst, src => src.GroupBy(p => p.ClientId)
.Select(g => new Permission
{
ClientId = g.Key,
RoleIds = g.Select(r => r.RoleId)
.ToArray()
}).ToArray());
On Compile, the error is thrown
"MemberExpression should return one of the properties of destination class"
How does one go about mapping from a collection of one type to a collection of another?
The order of mapping registrations is important - bug
Support of nongeneric mappings Map(object src, Type scrType, Type dest)
While I want to update a ViewModel to an Model/Entity and save back to Database.
ModelStatus = 10 && CurrentUser = "spyhunter88"
, the field CustomerName will be updated and saved to database, otherwise is not.public class MyCustomMapper : ICustomMapper<ViewModel, Model>
{
private MyConfig config;
public MyCustomMapper(MyConfig config) { this.config = config; }
public Model Map
(IMappingContext<ViewModel,Model> context)
{
// base on config variable, I can restrict what properties will be mapped or not
context.Destination.CustomerName = context.Source.CustName;
return context.Destination;
}
}
And use like that:
MyCustomMapper mapper = new MyCustomMapper(config);
Mapper.Map<ViewModel, Model>(TSrc src, TDest dest, ICustomMapper mapper);
This'll make my work so easy than before and may have your performance.
Also with my current project, this has some others function I have hand-code. I'll post in another issue.
This feature come with CustomMap for ICollection, what behavior when Source have new object, or missing object compare with Destination list.
IMappingServiceProvider removing named optional parameters
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.