Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to remove null checks in source mappings? #225

Open
C-Wal opened this issue Apr 8, 2022 · 4 comments
Open

How to remove null checks in source mappings? #225

C-Wal opened this issue Apr 8, 2022 · 4 comments

Comments

@C-Wal
Copy link

C-Wal commented Apr 8, 2022

If I map properties then the compiled plan says every source property value referenced in the Map() must not be null. How do I remove this null check?

In this instance I'm mapping an addressline1 from multiple source properties, but the plan is forcing all source properties to be non-null, which I clearly don't want as in the mapping I'm ignoring the null lines and concating the non-null.

@SteveWilkes
Copy link
Member

Hello!

Sounds like you've got a custom source->target member configuration where you're handling null-checking yourself and the built-in null-checking is getting in the way? Could you give me an example of what you're trying to map?

Cheers,
Steve

@C-Wal
Copy link
Author

C-Wal commented Apr 11, 2022

The mapping is between two classes named Address with mostly different properties. The target.AddressLine1 is populated with a lot of string.IsNullOrEmpty checks on the source properties.

I don't have the code right now but here is the map that is produced:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Map Address -> Address
// Rule Set: CreateNew
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

aToAData =>
{
    Address sourceAddress;
    try
    {
        sourceAddress = aToAData.Source;

        var address = new Address();
        // No data sources for ID
        // No data sources for Country_ID
        // No data sources for Country or any of its child members

        if (((((sourceAddress.Thoroughfare != null) && (sourceAddress.DependentThoroughfare != null)) &&
            (sourceAddress.BuildingNumber != null)) &&
            (sourceAddress.Building != null)) &&
            (sourceAddress.SubBuilding != null))
        {
            address.AddressLine1 = new[]
            {
                string.IsNullOrWhiteSpace(sourceAddress.SubBuilding)
                    ? string.Empty
                    : sourceAddress.SubBuilding.Trim() + ", ",
                string.IsNullOrWhiteSpace(sourceAddress.Building)
                    ? string.Empty
                    : sourceAddress.Building.Trim() + ", ",
                string.IsNullOrWhiteSpace(sourceAddress.BuildingNumber)
                    ? string.Empty
                    : sourceAddress.BuildingNumber.Trim() + ", ",
                string.IsNullOrWhiteSpace(sourceAddress.DependentThoroughfare)
                    ? string.Empty
                    : sourceAddress.DependentThoroughfare.Trim() + ", ",
                string.IsNullOrWhiteSpace(sourceAddress.Thoroughfare)
                    ? string.Empty
                    : sourceAddress.Thoroughfare.Trim()
            }.Trim();
        }

        if ((sourceAddress.DependentLocality != null) && (sourceAddress.DoubleDependentLocality != null))
        {
            address.AddressLine2 = (string.IsNullOrWhiteSpace(sourceAddress.DoubleDependentLocality)
                ? string.Empty
                : sourceAddress.DoubleDependentLocality.Trim() + ", ") + (string.IsNullOrWhiteSpace(sourceAddress.DependentLocality)
                ? string.Empty
                : sourceAddress.DependentLocality.Trim());
        }

        if (sourceAddress.Town != null)
        {
            address.PostalTown = string.IsNullOrWhiteSpace(sourceAddress.Town) ? string.Empty : sourceAddress.Town.Trim();
        }

        if (sourceAddress.County != null)
        {
            address.County = string.IsNullOrWhiteSpace(sourceAddress.County) ? string.Empty : sourceAddress.County.Trim();
        }
        else
        {
            address.County = sourceAddress.County;
        }

        // No way to populate FullAddress (readonly string)

        if (sourceAddress.PostCode != null)
        {
            address.PostCode = string.IsNullOrWhiteSpace(sourceAddress.PostCode)
                ? string.Empty
                : sourceAddress.PostCode.Trim();
        }
        else
        {
            address.PostCode = sourceAddress.PostCode;
        }

        return address;
    }
    catch (Exception ex)
    {
        throw MappingException.For(
            "CreateNew",
            "Address",
            "Address",
            ex);
    }
}

As you can see, target.AddressLine1 is only composed if all the source properties are non-null.

Also I notice that the if gains an else only if the properties have matching names. For example, County > County has an if-else but Town > PostalTown only has an if. Is that intentional?

@C-Wal
Copy link
Author

C-Wal commented Apr 11, 2022

We have worked around it for now by using Before.CreatingTargetInstances.Call() to ensure each source property has a value but suspect there's a nicer way to deal with it.

@SteveWilkes
Copy link
Member

Hello!

The null checks are the mapper protecting against null strings in the Trim() calls - it isn't smart enough to figure out you've already handled it, unfortunately.

I suppose the proper solution would be a configuration option to indicate you're going to handle null-checking yourself, but (if I've understood the mapping correctly) - maybe this would be neater:

Mapper.WhenMapping
    .From<Source.Address>()
    .To<Target.Address>()
    .Map((sourceAddress, _) => string.Join(", ", new[]
        {
            sourceAddress.SubBuilding,
            sourceAddress.Building,
            sourceAddress.BuildingNumber,
            sourceAddress.DependentThoroughfare,
            sourceAddress.Thoroughfare
        }.Where(addressPart => !string.IsNullOrWhiteSpace(addressPart))
         .Select(addressPart => addressPart.Trim())))
    .To(targetAddress => targetAddress.AddressLine1);

Again unfortunately, testing this turned up a bug where the mapper falls over trying to figure out a null-check for addressPart.Trim() - there's a fix that in the latest master branch.

Cheers,

Steve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants