Automapper will not ignore property - automapper

I have a mapping between two classes:
CreateMap<A, B>()
.ForMember(b => b.Foo, cfg => cfg.MapFrom(a => a.Aoo.Foo))
.ReverseMap()
.IgnoreAllPropertiesWithAnInaccessibleSetter()
.IgnoreAllSourcePropertiesWithAnInaccessibleSetter()
.ForMember(a => a.Aoo, opts => opts.Ignore());
I would expect, from the last Ignore() alone, that when mapping a B to an A, Automapper would not try to assign a value to A. However, I do such a thing here:
var a = _mapper.Map<A>(b);
And I get the following exception:
System.NullReferenceException : typeMapDestination.Aoo cannot be null because it's used by ForPath.
Why is it trying to assign a value here? I even looked at the source code and this exception only gets thrown when the setter for that property is null!

Related

Call to a member function createView() on null

I am using symfony 5, within my Controller I have this :
$devisFrais = $devisRepository->getDevisPosteFDFrais($idDevis);
$formFrais = $this->createForm(DevisDisciplineQualifType::class, $devisFrais, [
'AT' => $AtNotAt,
'type' => 'FRAIS'
]);
return $this->render('devis.html.twig', [
'formFrais' => $formFrais->createView(),
]);
As $devisFrais is Null so formFrais is Null.
I can't create a form because I have this error : "Call to a member function createView() on null".
Is it possible to create a blank form, in this case how to manage it within the Twig
You are getting an error that your variable $formFrais is null.
What you need to do is to simply check your value for being null / empty,
with a ternary operator, and if it is give it is, execute the method, and if not, implement whatever logic you need after the ":".
You can do it in the Controller, no need to do any manipulation at the level of twig.
The basic logic is:
//...
return $this->render('devis.html.twig', [
'formFrais' => $formFrais ? $formFrais->createView() : $formFrais = "some_value",
]);

Converting a NULL instance of a class to a new empty class during mapping

I have the following automapper code:
CreateMap<JeffreysOnline.Data.BoothMaster, JeffreysOnline.Entities.BoothMaster>()
.ForMember(s => s.RentClass, t => t.MapFrom(m => m.RentClass));
The BoothMaster class contains a class named RentClass. When the mapping occurs I'd like a new instance of RentClass assigned to BoothMaster when RentClass is NULL, instead of a NULL value assigned, as is occurring now when RentClass is NULL. Can this be done?
I haven't tested the code but you should be able to do something like this:
CreateMap<JeffreysOnline.Data.BoothMaster, JeffreysOnline.Entities.BoothMaster>().BeforeMap((source, dest) =>
{
dest.RentClass = (source.RentClass == null) ? new RentClass(): source.RentClass;
});

Linq Invalid Cast Exception Same Object Type

I wrote this query and as my understanding of the business rules has improved I have modified it.
In this most recent iteration I was testing to see if indeed I had some redundancy that could be removed. Let me first give you the query then the error.
public List<ExternalForums> GetAllExternalForums(int extforumBoardId)
{
List<ExternalForums> xtrnlfrm = new List<ExternalForums>();
var query = _forumExternalBoardsRepository.Table
.Where(id => id.Id == extforumBoardId)
.Select(ExtForum => ExtForum.ExternalForums);
foreach (ExternalForums item in query)
{
xtrnlfrm.Add(new ExternalForums { Id = item.Id , ForumName = item.ForumName, ForumUrl = item.ForumUrl });
}
return xtrnlfrm;
}
Now in case it isn't obvious the query select is returning List of ExternalForums. I then loop through said list and add the items to another List of ExternalForums object. This is the redundancy I was expecting to remove.
Precompiler was gtg so I ran through it one time to very everything was kosher before refactoring and ran into a strange error as I began the loop.
Unable to cast object of System.Collections.Generic.HashSet
NamSpcA.NamSpcB.ExternalForums to type NamSpcA.NamSpcB.ExternalForums.
Huh? They are the same object types.
So am I doing something wrong in the way I am projecting my select?
TIA
var query = _forumExternalBoardsRepository.Table
.Where(id => id.Id == extforumBoardId)
.Select(ExtForum => ExtForum.ExternalForums);
This query returns IEnumerable<T> where T is type of ExtForum.ExternalForums property, which I would expect to be another collection, this time of ExternalForum. And the error message matches that, saying you have IEnumerable<HashSet<ExternalForums>>.
If you need that collection of collections to be flattened into one big collection of ExternalForums use SelectMany instead:
var query = _forumExternalBoardsRepository.Table
.Where(id => id.Id == extforumBoardId)
.SelectMany(ExtForum => ExtForum.ExternalForums);

Conditionally overwrite destination if no destination object is used

I would like to setup an Automapper mapping that follows the following rules.
If the "in place" destination syntax is not used, map a particular member to a value
If an object is passed in, then use the destination value
I've tried this every way I can think of. Something like this:
Mapper.CreateMap<A, B>()
.ForMember(dest => dest.RowCreatedDateTime, opt => {
opt.Condition(dest => dest.DestinationValue == null);
opt.UseValue(DateTime.Now);
});
This always maps the value. Essentially what I want is this:
c = Mapper.Map<A, B>(a, b); // does not overwrite the existing b.RowCreatedDateTime
c = Mapper.Map<B>(a); // uses DateTime.Now for c.RowCreatedDateTime
Note: A does not contain a RowCreatedDateTime.
What are my options here? It's very frustrating since there appears to be no documentation on the Condition method, and all the google results seem to be focused around where the source value is null, rather than the destination.
EDIT:
Thanks to Patrick, he got me on the right track..
I figured out a solution. If anyone has a better way of doing this, please let me know. Note I had to reference dest.Parent.DestinationValue rather than dest.DestinationValue. For some reason, dest.DestinationValue is always null.
.ForMember(d => d.RowCreatedDateTime, o => o.Condition(d => dest.Parent.DestinationValue != null))
.ForMember(d => d.RowCreatedDateTime, o => o.UseValue(DateTime.Now))
I believe you need to set up two mappings: one with the Condition (which determines IF a mapping should be performed) and one which defines what to do if the Condition returns true. Something like this:
.ForMember(d => d.RowCreatedDateTime, o => o.Condition(d => d.DestinationValue == null);
.ForMember(d => d.RowCreatedDateTime, o => o.UseValue(DateTime.Now));

PredicateBuilder where clause issue

I am using PredicateBuilder to generate where clause
var locationFilter = PredicateBuilder.True<dbCompanyLocation>();
locationFilter = locationFilter.And(s => s.IsPrimary == true && s.State == practiceState);
var companyPredicate = PredicateBuilder.True<dbCompany>();
companyPredicate = companyPredicate.And(c => c.dbCompanyLocations.Where(locationFilter));
I am getting following error, Any one can help for this or am i doing something wrong.
Instance argument: cannot convert from 'System.Data.Linq.EntitySet' to 'System.Linq.IQueryable'
The immediate problem seems to be that dbCompany.dbCompanyLocations is an EntitySet, which implements IEnumerable<T> rather than IQueryable<T>. This means its Where extension method expects a Func<dbCompanyLocation, bool>, however the locationFilter variable you are providing is an Expression<Func<dbCompanyLocation, bool>>.
You can create a Func<dbCompanyLocation, bool> from locationFilter by calling the Compile method.
Another problem however is that even if it did type check, c => c.dbCompanyLocations.Where(locationFilter) is not a predicate, since Where returns an IEnumerable<T> instead of a bool. You probably meant to use Any instead of Where i.e.
companyPredicate = companyPredicate.And(c => c.dbCompanyLocations.Any(locationFilter.Compile()));

Resources