Giter Site home page Giter Site logo

expressmapper's People

Contributors

anisimovyuriy avatar bo-stig-christensen avatar bogatykh avatar jaredrsowers avatar jonpsmith avatar petertiedemann avatar tormodfj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

expressmapper's Issues

Mapping engine interface

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.

Target nested objects not getting initialized?

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?

Exception raised when mapping to different types on After in 1.6

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.

Thread safety issue

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

Dictionary mapping support

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.

Error when viewmodel extends model

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".

Array member to List mapping - exception

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

Nullable to NonNullable mappings and vice versa - throws exception

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.

Can't map to Destination Object (v1.5.0)

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; } } 
}

Problem with simple mapping (recursion)

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 Dependants{get;set;}
}

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.

Multiple .After handlers

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.

Make thread safe

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

AssertConfigurationIsValid() equivilent

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

Unit Testing and Type Registration Error

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?

Mapping to object of the same type doesn't work

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

I would really like to be able to ignore case on the mapping

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

Ability to use EM without Register

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?

Add support for mapping by convention

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 :)

Nullable nested properties throws NullReferenceException

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...

Force Explicit Mapping

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 & interfaces mappings

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>();
}

How to configure mapping for objects with bidirectional reference?

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 ๐Ÿ˜ƒ.

I can't install the package in my PCL

Hello.

I want to install this dependency in my PCL project, but I am getting this error:

d

I want to use this library in my Xamarin project, in a Portable Class Library.

Thanks.

Support for mapping ObservableCollection

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.ObservableCollection1[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();

Custom member mapping - bug

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; }
}

How to map to destination of array?

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?

Add Inject value and runtime custom map

While I want to update a ViewModel to an Model/Entity and save back to Database.

  1. I must keep the Entity's reference and update new value into it without create new Entity. So with current ExpressMapper function, I don't see I can update and exist object with new value from another object. Just only return new object.
  2. Some of its properties can not be update base on some others value. Like with ModelStatus = 10 && CurrentUser = "spyhunter88", the field CustomerName will be updated and saved to database, otherwise is not.
    Like the sample in homepage, I don't think I can check like that because Context some time don't have enough information like CurrentUser = "spyhunter88".
    It will be dynamic if you have some mapper like:
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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.