I am using EF Core 7.0.
This is my entity:
public class ComponentDTO
{
public long Id { get; set; }
public long _idProveedor { get; set; }
public ProviderDTO Provider { get; set; }
public string Reference { get; set; }
public string Description { get; set; }
public ComponentDTO? CompatibleReferenceComponent { get; set; }
public List<ComponentDTO> CompatibleComponents = new List<ComponentDTO>();
}
I would like to know which components are compatible with others. For that, I have a reference component, CompatibleReferenceComponent
, that has a collection with all the compatible components.
In this way, if a component is not the reference component, the CompatibleComponents
is empty.
CompatibleReferenceComponent
can be null if the component has not compatible components. So if it is not null, it means that it has compatible components and if it is null, it has not compatible components.
So to know the compatible components of a component I have to go through CompatibleReferenceComponent.CompatibleComponents
.
I would like to get a component with all the compatible components with EF Core, so my first try was this:
public async Task<ComponentDTO?> GetComponentWithCompatibleComponents(long paramIdComponent)
{
return await _context.Components
.AsNoTracking()
.Include(x => x.CompatibleReferenceComponent).ThenInclude(x => x.CompatibleComponents)
.FirstOrDefaultAsync(x => x.Id == paramIdComponent);
}
The problem is that I get an exception because of a cycle, because I am using AsNoTracking()
.
I could solve the problem if I use entity resolution, but then I would have problems in the serialization when I will send the data to the client because of cycles.
If I am not wrong, the problem is because I am populate the property CompatibleReferenceComponent
in the items of the collection CompatibleComponents
. I don't need this property really, so I would like to use projection to don't populate this property.
I was trying something like that:
await _context.Components
.AsNoTracking()
.Select(x => new ComponentDTO
{
Id = x.Id,
IdProvider = x.IdProvider,
Reference = x.Reference,
Description = x.Description,
CompatibleReferenceComponent = x.CompatibleReferenceComponent,
CompatibleComponents = new List<ComponentDTO>()
{
new ComponentDTO
{
Provider = x.Provider,
Reference = x.Reference,
Description = x.Description,
}
}
})
.FirstOrDefaultAsync(x => x.Id == paramIdComponent);
But I don't get expect result because I am populate the collection in the result entity. I need to populate the collection of the CompatibleReferenceComponent
property, I need to nested another select. But I don't know how to do that.
It would be something like that:
await _context.Components
.AsNoTracking()
.Select(x => new ComponentDTO
{
Id = x.Id,
IdProvider = x.IdProvider,
Reference = x.Reference,
Description = x.Description,
CompatibleReferenceComponent = new ComponentDTO
{
CompatibleComponents = new List<ComponentDTO> { new ComponentDTO { Id = x.Id } }
}
})
.FirstOrDefaultAsync(x => x.Id == paramIdComponent);
It works partially, because now the collection that is populate is CompatibleReferenceComponent.CompatibleComponents
instead of this.CompatibleComponents
. The problem is the collections has only one item, it doesn't include all the compatible components.
So how could I do this query? How to avoid to include the CompatibleReferenceComponent
property in the items of the collection?
Thanks.