Is ThenInclude unnecessary? - entity-framework-core

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?

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

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.

InvalidOperationException: The LINQ expression '' could not be translated

var baseQuery = Context.Questions.AsNoTracking().Where(x => x.Active && x.QuestionFoils.Any());
// Gets 30
baseQuery = baseQuery.Where(x => x.QuestionReferences.Any());
//Gets 2
baseQuery = baseQuery.Where(
x => x.QuestionReferences.Any(qr =>
listNames.Any(name =>
name.FirstName == qr.Reference.ReferenceProfessors.Professor.FirstName &&
name.LastName == qr.Reference.ReferenceProfessors.Professor.LastName
)));
countCount = baseQuery.Count();
When I try to do any operation on the query, it gives a InvalidOperationException: The LINQ expression '' could not be translated.
InvalidOperationException: The LINQ expression
'Any, ReferenceProfessor>, Professor>>( source:
LeftJoin, ReferenceProfessor>, Professor, Nullable,
TransparentIdentifier, ReferenceProfessor>, Professor>>( outer:
LeftJoin,
ReferenceProfessor, Nullable,
TransparentIdentifier, ReferenceProfessor>>( outer: Join, TransparentIdentifier>( outer: Where( source:
DbSet, predicate: (q2) =>
Property>(EntityShaperExpression: EntityType: Question
ValueBufferExpression: ProjectionBindingExpression:
EmptyProjectionMember IsNullable: False , "QuestionId") ==
Property>(q2, "QuestionId")), inner: DbSet,
outerKeySelector: (q2) => Property>(q2, "ReferenceId"),
innerKeySelector: (r) => Property>(r, "ReferenceId"),
resultSelector: (o, i) => new TransparentIdentifier( Outer = o, Inner = i )), inner: DbSet,
outerKeySelector: (q2) => Property>(q2.Inner,
"ReferenceId"), innerKeySelector: (r0) => Property>(r0,
"ReferenceId"), resultSelector: (o, i) => new
TransparentIdentifier, ReferenceProfessor>( Outer = o, Inner = i )), inner:
DbSet, outerKeySelector: (q2) =>
Property>(q2.Inner, "ProfessorId"), innerKeySelector:
(p) => Property>(p, "ProfessorId"), resultSelector: (o,
i) => new
TransparentIdentifier, ReferenceProfessor>, Professor>( Outer = o, Inner = i )),
predicate: (q2) => Any( source: (Unhandled parameter:
__listNames_0), predicate: (name) => name.FirstName == q2.Inner.FirstName && name.LastName == q2.Inner.LastName))' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or
ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for
more information.
Anything with a single table works just fine:
baseQuery = baseQuery.Where(x => x.QuestionCourses.Any(qc => courses.Any(name => name == qc.Course.Name)));
How would I rewrite the following to not throw this error?
x => x.QuestionReferences.Any(qr =>
listNames.Any(name =>
name.FirstName == qr.Reference.ReferenceProfessors.Professor.FirstName &&
name.LastName == qr.Reference.ReferenceProfessors.Professor.LastName
))
I believe the issue will be that you are trying to filter the Linq expression with an object with 2 fields (name.FirstName & name.LastName) which won't translate down to SQL. EF can translate list contains/any into IN clauses, but against a singular field/expression.
What should work:
Combine your names into a single list of strings. For instance "FirstName LastName" or "LastName, FirstName" then combine the professor name when comparing:
x => x.QuestionReferences.Any(qr =>
listNames.Any(name => name == qr.Reference.ReferenceProfessors.Professor.FirstName
+ " " + qr.Reference.ReferenceProfessors.Professor.LastName ))
Where listNames = "FirstName LastName";

Automapper, mapping to a complex object

I have 2 classes i'm trying to map namely
1) Entity
2) DTO
I'm trying to map Entity.Foo to DTO.Child.Foo
Obviously the below will not work, how do I achieve this. I need to create a new instance of Child and then attach that to the Mapper and then set the Foo property but my AutoMapper skills are not that good!
Mapper.CreateMap<Entity, DTO>()
.ForMember("Child.Foo", m => m.MapFrom(entity => entity.Foo))
Mapper.CreateMap<Entity, DTO>()
.ForMember(d => d.Foo,
o => o.ResolveUsing(s => new DTO.Child { Foo = s.Foo }))
// comment

Mongoid syntax for querying based on several sets of attributes

Assuming I want to get 3 documents which fit one of these attributes
Class Question:
name=>a, topic=>b
name=>c, topic=>d
name=>e, topic=>f
What is the appropriate syntax for mongoid to get these?
According to mongoid query syntax:
Model.any_of({:name => a, :topic => b},
{:name => c, :topic => d},
{:name => e, :topic => f})