ProjectTo error with nested LINQ Select #4010
-
Source/destination types#region DTOs
public partial class CircuitosDTO
{
public int IdCircuito { get; set; }
public string Nombre { get; set; }
public string Codigo { get; set; }
public decimal? Version { get; set; }
public string Descripcion { get; set; }
public int? Prioridad { get; set; }
public int IdEstado { get; set; }
public int IdInstancia { get; set; }
public EstadosDTO EstadoDTO { get; set; }
public ICollection<TareasDTO> TareasDTO { get; set; }
}
public class TareasDTO
{
public int IdTarea { get; set; }
public int IdCircuito { get; set; }
public int Codigo { get; set; }
public string Nombre { get; set; }
public string FuncionEntrar { get; set; }
public string FuncionSalir { get; set; }
public bool Asignable { get; set; }
public string FormularioAsociado { get; set; }
public bool? Reasignable { get; set; }
public int IdEstado { get; set; }
public DateTime CreateDate { get; set; }
public string CreateUser { get; set; }
public DateTime? UpdateDate { get; set; }
public string UpdateUser { get; set; }
public CircuitosDTO CircuitosDTO { get; set; }
public ICollection<TransicionesTareasDestinoDTO> TransicionesTareasDestinoDTO { get; set; }
public ICollection<TransicionesDTO> TransicionesDTO { get; set; }
public ICollection<RelResultadosTareasDTO> RelResultadosTareasDTO { get; set; }
}
public class RelResultadosTareasDTO
{
public int IdResultadoTarea { get; set; }
public int IdTarea { get; set; }
public int IdResultado { get; set; }
public int NroOrden { get; set; }
public StaticClass.Enums.Action Action { get; set; } = StaticClass.Enums.Action.None;
public TareasDTO IdTareaDTO { get; set; }
public ResultadosDTO IdResultadoDTO { get; set; }
public ICollection<RelResultadosTareasTransicionesDTO> RelResultadosTareasTransicionesDTO { get; set; }
}
public class RelResultadosTareasTransicionesDTO
{
public int IdResultadoTareaTransicion { get; set; }
public int IdResultadoTarea { get; set; }
public int IdTransicion { get; set; }
public int NroOrden { get; set; }
public StaticClass.Enums.Action Action { get; set; } = StaticClass.Enums.Action.None;
public RelResultadosTareasDTO ResultadoTareaDTO { get; set; }
public TransicionesDTO TransicionDTO { get; set; }
}
public partial class TransicionesDTO
{
public int IdTransicion { get; set; }
public int IdTareaOrigen { get; set; }
public int IdEstado { get; set; }
public TareasDTO TareaOrigenDTO { get; set; }
public EstadosDTO EstadoDTO { get; set; }
public ICollection<RelResultadosTareasTransicionesDTO> RelResultadosTareasTransicionesDTO { get; set; }
public ICollection<TransicionesTareasDestinoDTO> TransicionesTareasDestinoDTO { get; set; }
}
public class TransicionesTareasDestinoDTO
{
public int IdTransicionTareaDestino { get; set; }
public int IdTransicion { get; set; }
public int IdTareaDestino { get; set; }
public string Condiciones { get; set; }
public string FuncionesPostTransicion { get; set; }
public TransicionesDTO TransicionDTO { get; set; }
public TareasDTO TareaDestinoDTO { get; set; }
}
#endregion DTOs
#region Entities
public partial class Circuitos
{
public Circuitos()
{
Tareas = new HashSet<Tareas>();
}
public int IdCircuito { get; set; }
public string Nombre { get; set; }
public string Codigo { get; set; }
public decimal? Version { get; set; }
public string Descripcion { get; set; }
public int? Prioridad { get; set; }
public int IdEstado { get; set; }
public DateTime CreateDate { get; set; }
public string CreateUser { get; set; }
public DateTime? UpdateDate { get; set; }
public string UpdateUser { get; set; }
public int IdInstancia { get; set; }
public virtual AspNetUsers CreateUserNavigation { get; set; }
public virtual Estados IdEstadoNavigation { get; set; }
public virtual Instancias IdInstanciaNavigation { get; set; }
public virtual AspNetUsers UpdateUserNavigation { get; set; }
public virtual ICollection<Tareas> Tareas { get; set; }
}
public partial class Tareas
{
public Tareas()
{
RelEquipoDeTrabajoTareas = new HashSet<RelEquipoDeTrabajoTareas>();
RelPerfilesTareas = new HashSet<RelPerfilesTareas>();
RelResultadosTareas = new HashSet<RelResultadosTareas>();
RelTiposDeDocumentosTareas = new HashSet<RelTiposDeDocumentosTareas>();
Transiciones = new HashSet<Transiciones>();
TransicionesTareasDestino = new HashSet<TransicionesTareasDestino>();
TrazasTareasIdProximaTareaNavigation = new HashSet<TrazasTareas>();
TrazasTareasIdTareaNavigation = new HashSet<TrazasTareas>();
}
public int IdTarea { get; set; }
public int IdCircuito { get; set; }
public int Codigo { get; set; }
public string Nombre { get; set; }
public string FuncionEntrar { get; set; }
public string FuncionSalir { get; set; }
public bool Asignable { get; set; }
public string FormularioAsociado { get; set; }
public bool? Reasignable { get; set; }
public int IdEstado { get; set; }
public DateTime CreateDate { get; set; }
public string CreateUser { get; set; }
public DateTime? UpdateDate { get; set; }
public string UpdateUser { get; set; }
public virtual AspNetUsers CreateUserNavigation { get; set; }
public virtual Circuitos IdCircuitoNavigation { get; set; }
public virtual Estados IdEstadoNavigation { get; set; }
public virtual AspNetUsers UpdateUserNavigation { get; set; }
public virtual ICollection<RelEquipoDeTrabajoTareas> RelEquipoDeTrabajoTareas { get; set; }
public virtual ICollection<RelPerfilesTareas> RelPerfilesTareas { get; set; }
public virtual ICollection<RelResultadosTareas> RelResultadosTareas { get; set; }
public virtual ICollection<RelTiposDeDocumentosTareas> RelTiposDeDocumentosTareas { get; set; }
public virtual ICollection<Transiciones> Transiciones { get; set; }
public virtual ICollection<TransicionesTareasDestino> TransicionesTareasDestino { get; set; }
public virtual ICollection<TrazasTareas> TrazasTareasIdProximaTareaNavigation { get; set; }
public virtual ICollection<TrazasTareas> TrazasTareasIdTareaNavigation { get; set; }
}
public partial class RelResultadosTareas
{
public RelResultadosTareas()
{
RelResultadosTareasTransiciones = new HashSet<RelResultadosTareasTransiciones>();
}
public int IdResultadoTarea { get; set; }
public int IdTarea { get; set; }
public int IdResultado { get; set; }
public int NroOrden { get; set; }
public virtual Resultados IdResultadoNavigation { get; set; }
public virtual Tareas IdTareaNavigation { get; set; }
public virtual ICollection<RelResultadosTareasTransiciones> RelResultadosTareasTransiciones { get; set; }
}
public partial class RelResultadosTareasTransiciones
{
public int IdResultadoTareaTransicion { get; set; }
public int IdResultadoTarea { get; set; }
public int IdTransicion { get; set; }
public int NroOrden { get; set; }
public virtual RelResultadosTareas IdResultadoTareaNavigation { get; set; }
public virtual Transiciones IdTransicionNavigation { get; set; }
}
public partial class Transiciones
{
public Transiciones()
{
RelResultadosTareasTransiciones = new HashSet<RelResultadosTareasTransiciones>();
TransicionesTareasDestino = new HashSet<TransicionesTareasDestino>();
}
public int IdTransicion { get; set; }
public int IdTareaOrigen { get; set; }
public int IdEstado { get; set; }
public DateTime CreateDate { get; set; }
public string CreateUser { get; set; }
public DateTime? UpdateDate { get; set; }
public string UpdateUser { get; set; }
public virtual AspNetUsers CreateUserNavigation { get; set; }
public virtual Estados IdEstadoNavigation { get; set; }
public virtual Tareas IdTareaOrigenNavigation { get; set; }
public virtual AspNetUsers UpdateUserNavigation { get; set; }
public virtual ICollection<RelResultadosTareasTransiciones> RelResultadosTareasTransiciones { get; set; }
public virtual ICollection<TransicionesTareasDestino> TransicionesTareasDestino { get; set; }
}
public partial class TransicionesTareasDestino
{
public int IdTransicionTareaDestino { get; set; }
public int IdTransicion { get; set; }
public int IdTareaDestino { get; set; }
public string Condiciones { get; set; }
public string FuncionesPostTransicion { get; set; }
public int IdEstado { get; set; }
public DateTime CreateDate { get; set; }
public string CreateUser { get; set; }
public DateTime? UpdateDate { get; set; }
public string UpdateUser { get; set; }
public virtual AspNetUsers CreateUserNavigation { get; set; }
public virtual Estados IdEstadoNavigation { get; set; }
public virtual Tareas IdTareaDestinoNavigation { get; set; }
public virtual Transiciones IdTransicionNavigation { get; set; }
public virtual AspNetUsers UpdateUserNavigation { get; set; }
}
#endregion Entities
#region GraficarCircuitos.razor
//This is the injected service
[Inject] public ICircuitosBL<CircuitosDTO> CircuitosBL { get; set; }
private CircuitosDTO GetCircuito(int idCircuito)
{
return CircuitosBL.Get(
predicate: x => x.IdCircuito == Id,
selector: GetCircuitoSelector()
).FirstOrDefault();
}
private Expression<Func<CircuitosDTO, CircuitosDTO>> GetCircuitoSelector()
{
return x => new CircuitosDTO
{
IdCircuito = x.IdCircuito,
Nombre = x.Nombre,
Descripcion = x.Descripcion,
Codigo = x.Codigo,
Version = x.Version,
Prioridad = x.Prioridad,
IdEstado = x.IdEstado,
TareasDTO = x.TareasDTO.Select(x => new TareasDTO
{
IdTarea = x.IdTarea,
Nombre = x.Nombre,
Codigo = x.Codigo,
Asignable = x.Asignable,
IdEstado = x.IdEstado,
IdCircuito = x.IdCircuito,
RelResultadosTareasDTO = x.RelResultadosTareasDTO.Select(x => new RelResultadosTareasDTO
{
IdResultadoTarea = x.IdResultadoTarea,
IdTarea = x.IdTarea,
IdResultado = x.IdResultado,
IdResultadoDTO = new ResultadosDTO
{
IdResultado = x.IdResultadoDTO.IdResultado,
Nombre = x.IdResultadoDTO.Nombre,
IdEstado = x.IdResultadoDTO.IdEstado,
},
IdTareaDTO = x.IdTareaDTO == null ? null : new TareasDTO
{
IdTarea = x.IdTareaDTO.IdTarea,
Nombre = x.IdTareaDTO.Nombre,
IdEstado = x.IdTareaDTO.IdEstado,
},
RelResultadosTareasTransicionesDTO = x.RelResultadosTareasTransicionesDTO.Select(rrtt => new RelResultadosTareasTransicionesDTO
{
IdResultadoTareaTransicion = rrtt.IdResultadoTareaTransicion,
IdResultadoTarea = rrtt.IdResultadoTarea,
IdTransicion = rrtt.IdTransicion,
TransicionDTO = new TransicionesDTO
{
IdTransicion = rrtt.TransicionDTO.IdTransicion,
IdEstado = rrtt.TransicionDTO.IdEstado,
TransicionesTareasDestinoDTO = rrtt.TransicionDTO.TransicionesTareasDestinoDTO.Select(ttd => new TransicionesTareasDestinoDTO
{
IdTransicionTareaDestino = ttd.IdTransicionTareaDestino,
TareaDestinoDTO = new TareasDTO
{
IdTarea = ttd.TareaDestinoDTO.IdTarea,
},
TransicionDTO = new TransicionesDTO
{
IdTransicion = ttd.TransicionDTO.IdTransicion
},
IdTareaDestino = ttd.IdTareaDestino,
IdTransicion = ttd.IdTransicion,
}).ToList()
}
}).ToList()
}).ToList()
}).ToList()
};
}
protected override void OnInitialized()
{
base.OnInitialized();
Circuito = GetCircuito(Id);
}
#endregion GraficarCircuitos.razor
#region CircuitosBL.cs
//This is the implementation of ICircuitosBL<CircuitosDTO>.Get(predicate, selector) - TSource is CircuitosDTO and TEntity is Circuitos
public IEnumerable<TSource> Get(
Expression<Func<TSource, bool>>? predicate,
Expression<Func<TSource, TSource>> selector)
{
using var unitOfWork = unitOfWorkFactory.GetReadOnly();
using ExtendedBaseRepository<TEntity> repository = new(unitOfWork , mapper);
return repository.Get(
selector: selector,
predicates: new[] { predicate });
}
#endregion CircuitosBL.cs Mapping configurationpublic class AutoMapperProfiles : Profile
{
public AutoMapperProfiles()
{
CreateMap<AppUserDTO, AppUser>().ReverseMap();
CreateMap<AppUserDTO, AspNetUsers>()
.ForMember(x => x.UserId, x => x.MapFrom(x => x.Id))
.ReverseMap();
CreateMap<Circuitos, CircuitosDTO>()
.ForMember(x => x.TareasDTO, x => x.MapFrom(x => x.Tareas))
.ReverseMap();
CreateMap<PerfilesDTO, Perfiles>().ReverseMap();
CreateMap<RelResultadosTareas, RelResultadosTareasDTO>()
.ForMember(x => x.IdResultadoDTO, x => x.MapFrom(x => x.IdResultadoNavigation))
.ForMember(x => x.IdTareaDTO, x => x.MapFrom(x => x.IdTareaNavigation))
.ForMember(x => x.RelResultadosTareasTransicionesDTO, x => x.MapFrom(x => x.RelResultadosTareasTransiciones))
.ReverseMap();
CreateMap<RelResultadosTareasTransiciones, RelResultadosTareasTransicionesDTO>()
.ForMember(x => x.TransicionDTO, x => x.MapFrom(x => x.IdTransicionNavigation))
.ForMember(x => x.ResultadoTareaDTO, x => x.MapFrom(x => x.IdResultadoTareaNavigation))
.ReverseMap();
CreateMap<Resultados, ResultadosDTO>()
//.ForMember(x => x.IdResultadoDTO, x => x.MapFrom(x => x.IdResultadoNavigation))
.ReverseMap();
CreateMap<Tareas, TareasDTO>()
.ForMember(x => x.RelResultadosTareasDTO, x => x.MapFrom(x => x.RelResultadosTareas))
.ForMember(x => x.TransicionesDTO, x => x.MapFrom(x => x.Transiciones))
.ForMember(x => x.TransicionesTareasDestinoDTO, x => x.MapFrom(x => x.TransicionesTareasDestino))
.ForMember(x => x.CircuitosDTO, x => x.MapFrom(x => x.IdCircuitoNavigation))
.ReverseMap();
CreateMap<Transiciones, TransicionesDTO>()
.ForMember(x => x.RelResultadosTareasTransicionesDTO, x => x.MapFrom(x => x.RelResultadosTareasTransiciones))
.ForMember(x => x.TransicionesTareasDestinoDTO, x => x.MapFrom(x => x.TransicionesTareasDestino))
.ForMember(x => x.TareaOrigenDTO, x => x.MapFrom(x => x.IdTareaOrigenNavigation))
.ReverseMap();
CreateMap<TransicionesTareasDestino, TransicionesTareasDestinoDTO>()
.ForMember(x => x.TareaDestinoDTO, x => x.MapFrom(x => x.IdTareaDestinoNavigation))
.ForMember(x => x.TransicionDTO, x => x.MapFrom(x => x.IdTransicionNavigation))
.ReverseMap();
CreateMap<TrazasTareas, TrazasTareasDTO>()
.ForMember(x => x.UsuarioAsignadoDTO, x => x.MapFrom(x => x.UsuarioAsignadoNavigation))
.ForMember(x => x.TareasDTO, x => x.MapFrom(x => x.IdTareaNavigation))
.ReverseMap();
}
}
//In Program.cs
services.AddAutoMapper(typeof(AutoMapperProfiles)); Version: 11.0.1Project: Nugets: Expected behaviorThe fully mapped object Actual behaviorError: System.InvalidOperationException: The LINQ expression 'ttd => new TransicionesTareasDestinoDTO{ Steps to reproduce#region ExtendedBaseRepository.cs
//This is the implementation of ExtendedBaseRepository.Get(selector, predicates) - TResult is CircuitosDTO
public IReadOnlyList<TResult> Get<TResult>(
Expression<Func<TResult, TResult>> selector,
params Expression<Func<TResult, bool>>?[] predicates)
{
try
{
var queryable = Context.Set<TEntity>()
.ProjectTo<TResult>(mapper.ConfigurationProvider);
foreach (var predicate in predicates)
{
queryable = queryable.SmartWhere(predicate);
}
queryable = queryable.Select(selector);
return queryable.ToList();
}
catch (Exception)
{
throw;
}
}
static internal class IQueryableExtensions
{
public static IQueryable<TResult> SmartWhere<TResult>(this IQueryable<TResult> queryable, Expression<Func<TResult, bool>>? predicate)
{
if (predicate is not null)
{
queryable = queryable.Where(predicate);
return queryable;
}
return queryable;
}
}
#endregion ExtendedBaseRepository.cs The problem is in this nested select: ...
TransicionesTareasDestinoDTO = rrtt.TransicionDTO.TransicionesTareasDestinoDTO.Select(ttd => new TransicionesTareasDestinoDTO
{
IdTransicionTareaDestino = ttd.IdTransicionTareaDestino,
TareaDestinoDTO = new TareasDTO
{
IdTarea = ttd.TareaDestinoDTO.IdTarea,
},
TransicionDTO = new TransicionesDTO
{
IdTransicion = ttd.TransicionDTO.IdTransicion
},
IdTareaDestino = ttd.IdTareaDestino,
IdTransicion = ttd.IdTransicion,
}).ToList()
... If I remove that nested Select() all works fine and the behavior is as I expected, if not then it throws the above error |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
That looks like an EF Core issue. Check the execution plan. Run that as a LINQ statement, without AM. You should get the same result. |
Beta Was this translation helpful? Give feedback.
That looks like an EF Core issue. Check the execution plan. Run that as a LINQ statement, without AM. You should get the same result.