Automapper: mapping properties outside source entity - entity-framework

I have a legacy ASP.NET Web forms application which uses ASP.NET GridView.
There's [User] class, which represents an entity from EF model, and then there's [UserDto]. All properties in the UserDto maps to the User class, except for one - which is RowCount. This is actually not a property related to the user itself, but in a legacy implementation, we have the total rowcount attached to each User object in the User list to show the correct page number in the Gridview.
So here's how my mapping goes:
config.CreateMap<User, UserDto>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(u => u.UserId))
.ForMember(dest => dest.Username, opt => opt.MapFrom(u => u.UserName))
.ForMember(dest => dest.Usercode, opt => opt.MapFrom(u => u.UserCode))
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(u => u.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(u => u.LastName))
.ForMember(dest => dest.Branch, opt => opt.MapFrom(u => u.Branch))
.ForMember(dest => dest.Groups, opt => opt.MapFrom(u => u.UserGroups))
.ForMember(dest => dest.AssignedUsers, opt => opt.MapFrom(u => u.User12.Select(s => s.FirstName + " " + s.LastName)));
Then I retrieve the users and map it to the DTO as follows:
var users = (from u in context.Users.Include("Branch")
where (u.FkBranchId == branchId || branchId == -1)
select u).ToList();
// get the total row count to support paging
var rowCount = users.Count;
var orderedList = CustomSort.GetSortedList(users, sortInfo.SortColumn, sortInfo.SortDirection).Skip(pageInfo.Skip).Take(pageInfo.PageSize).ToList();
return mapper.Map<List<EFModel.ClientData.User>, List<UserDto>>(orderedList);
Here I'm thrown an error, obviously, because the RowCount property in my DTO is not mapped. Notice that I want to map it to a property outside of the user object, i.e. the list count.
How do I do this?

Related

EF Core GroupBy query throws: could not be translated

Can anyone point me at the faux pas in this EF Core query?
var employers = await iqDbContext.Payrolls
.GroupBy(p => p.PayeScheme.Employer, p => p)
.Select(group => new EmployerViewModel
{
Id = group.Key.Id,
Name = group.Key.Name
})
.ToListAsync();
throws:
System.InvalidOperationException: The LINQ expression 'DbSet<Payroll>()
.Join(
inner: DbSet<PayeScheme>(),
outerKeySelector: p => EF.Property<Nullable<int>>(p, "PAYR_fk1_PAYE_SCHEME"),
innerKeySelector: p0 => EF.Property<Nullable<int>>(p0, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<Payroll, PayeScheme>(
Outer = o,
Inner = i
))
.Join(
inner: DbSet<Employer>(),
outerKeySelector: p => EF.Property<Nullable<int>>(p.Inner, "PychFk1Employer"),
innerKeySelector: e => EF.Property<Nullable<int>>(e, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<Payroll, PayeScheme>, Employer>(
Outer = o,
Inner = i
))
.Where(p => p.Inner != null && __accessiblePayrollIds_0.Contains(p.Outer.Outer.Id))
.GroupBy(
keySelector: p => p.Inner,
elementSelector: p => p.Outer.Outer)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?
If you need correct grouping, you have to specify which columns to group, not whole object.
var employers = await iqDbContext.Payrolls
.GroupBy(p => new { p.PayeScheme.Employer.Id, p.PayeScheme.Employer.Name })
.Select(group => new EmployerViewModel
{
Id = group.Key.Id,
Name = group.Key.Name,
})
.ToListAsync();

Is ThenInclude unnecessary?

I have just done the following (EF Core 3.1):
var aaa = context
.Table1
.Include(t => t.Table2.Table3.Table4);
.Include(t => t.Table2.Table3.Table5);
and I have in my variabe aaa the elements of Table1 and the ones in all subsequent child tables. I thought a .ThenInclude was necessary in these cases. I thought this had to be done the following way:
var aaa = context
.Table1
.Include(t => t.Table2);
.ThenInclude(t2 => t2.Table3)
.ThenInclude(t3 => t3.Table4)
.Include(t => t.Table2);
.ThenInclude(t2 => t2.Table3)
.ThenInclude(t3 => t3.Table5)
Is ThenInclude not necessary? What is it for, then?

Using Mapster to map from flat model to a model with nested properties in TypeAdapterConfig

Using EF Core 3 and Mapster I would like to map from a flat dto object to an object with a related sub-object.
i.e.
_ = TypeAdapterConfig<NoteVM, Note>.NewConfig()
.Map(d => d.Detail, s => s.Description)
.Map(d => d.Id, s => s.NoteId)
.Map(d => d.NoteTypeObject, s => s.NoteTypeString)
.IgnoreNullValues(true);
Where NoteTypeObject is an existing record on a table.
So in the mapping the NoteType object has to be retrieved from the db and attached to the Note record before the Note record is saved.
Can this be done in the config section or does this need to be done after the mapping but before the Note object is saved to the DB?
_ = TypeAdapterConfig<NoteVM, Note>.NewConfig()
.Map(d => d.Detail, s => s.Description)
.Map(d => d.Id, s => s.NoteId)
//get existing Id
.Map(d => d.NoteTypeObjectId, s => GetNoteTypeId(s.NoteTypeString))//lookup
.IgnoreNullValues(true);
If you are able to add a reference ID instead of object reference you can do something like the above.

EF code first and two way relationships

this.HasRequired(t => t.Parent)
.WithMany(t => t.Children)
.HasForeignKey(d => d.ParentId);
Here I defined a basic 1-to-many relationship. What if I do not want to have Children property exposed at all in Model, but still want to have synchronization of values between Parent and ParentId. How would I go defining such "relationship"?
You will call WithMany without any parameter:
this.HasRequired(t => t.Parent)
.WithMany()
.HasForeignKey(d => d.ParentId);

Fatal error on omitted fields in SOAP-request

I'm building a SOAP client for sending information to a SOAP service defined with a WSDL. When posting data to the service in SoapUI, I'm able to omit the fields I don't have values for, but in PHP I'm getting a fatal error.
Is there a way to have SOAPClient in PHP omit fields? The object I'm passing to SOAPClient looks like this:
Kunde Object
(
[kundenr] => 1008911
[contact_id] => 10941
[kundenavn] =>
[organisasjonsnr] =>
[addresse] => Addresse Object
(
[postadresse1] =>
[postadresse2] =>
[postadresse3] =>
[postadresse] =>
[gateadresse1] =>
[gateadresse2] =>
[gateadresse3] =>
[gateadresse] =>
[county] =>
[kommunenr] =>
[stat] =>
[postnr] =>
[poststed] =>
[landkode] =>
[land] =>
[adresslayout] =>
)
[kontakt] => Kontakt Object
(
[tlfnr] =>
[tlfbeskrivelse] =>
[faxnr] =>
[faxbeskrivelse] =>
[mailadresse] =>
[webadresse] =>
)
[person] => Person Object
(
[customerId] =>
[personId] =>
[contact_id] =>
[fornavn] =>
[etternavn] =>
[brukernavn] =>
[epost] =>
[tlf] =>
[kundetype] => 40
[addresse] => Addresse Object
(
[postadresse1] =>
[postadresse2] =>
[postadresse3] =>
[postadresse] =>
[gateadresse1] =>
[gateadresse2] =>
[gateadresse3] =>
[gateadresse] =>
[county] =>
[kommunenr] =>
[stat] =>
[postnr] =>
[poststed] =>
[landkode] =>
[land] =>
[adresslayout] =>
)
)
[faultmsg] => Faultmsg Object
(
[Type] =>
[Melding] =>
[Detalj] =>
)
[avdeling] =>
[kundetype] => 40
[informasjon] =>
[aktiv] =>
[stopputsendelse] =>
[aco_kunde] =>
[uf_kunde] =>
[gan_kunde] =>
[kunde] => 10941
)
I would like to for instance omit the Kunde->kundenavn property from the object, but that gives me this fatal error:
[13-Aug-2012 07:01:50] PHP Fatal error: SOAP-ERROR: Encoding: object
has no 'kundenavn' property in...
You may be suffering from PHP Bug #50997: SOAP Error when trying to submit 2nd Element of a choice
Or it may be required field in the WSDL so you're stuck with it either way most likely. Sorry!