I've created SQL View in SQL Server database which returns rows with list of columns:
Id, SupplierName, EmailAddress, PhoneNumber, CsatRating, CsatRatingCount,
Latitude, Longitude, AddressLine1, AddressLine2, AddressLine3,
City, CountryIsoNumber, StateProvinceCounty, PostCode,
PartnersOnHoldIds, BusinessClientId, Status, ServiceTypeId,
StartDT, EndDT, MaxCapacityExceeded, CapabilityId, NetworkId, PartnerI
Now I want to read these data to my object result in this method:
public async Task<IEnumerable<AllocationSupplierViewDto>> GetAllocationSuppliersByIdAsync(Guid id)
{
var query = $@"
SELECT *
FROM vw_SupplierInformation
WHERE Id = '{id}'";
var result = await dbContext.SupplierInformation
.FromSqlRaw(query)
.ToListAsync();
return result;
}
I'm able to see list of rows returned from view but without nested objects. I'm attaching below how my DTOs looks like:
public class AllocationSupplierViewDto
{
public Guid Id { get; set; }
public string? SupplierName { get; set; }
public string? EmailAddress { get; set; }
public string? PhoneNumber { get; set; }
public double? CsatRating { get; set; }
public int? CsatRatingCount { get; set; }
public double? Latitude { get; set; }
public double? Longitude { get; set; }
public string? AddressLine1 { get; set; }
public string? AddressLine2 { get; set; }
public string? AddressLine3 { get; set; }
public string? City { get; set; }
public string? CountryIsoNumber { get; set; }
public string? StateProvinceCounty { get; set; }
public string? Postcode { get; set; }
public List<Guid>? PartnersOnHoldIds { get; set; }
public required List<BusinessClientConfigurationViewDto> BusinessClientConfiguration { get; set; }
}
public class BusinessClientConfigurationViewDto
{
public Guid BusinessClientId { get; set; }
public int Status { get; set; }
public List<ServiceViewDto>? Services { get; set; }
public required AllocationSupplierViewDto AllocationSupplierViewDto { get; set; }
public Guid AllocationSupplierViewDtoId { get; set; }
}
public class ServiceViewDto
{
public Guid ServiceTypeId { get; set; }
public DateTime? StartDT { get; set; }
public DateTime? EndDT { get; set; }
public bool MaxCapacityExceeded { get; set; } = false;
public List<Guid>? CapabilityIds { get; set; }
public List<NetworkViewDto>? Networks { get; set; }
}
public class NetworkViewDto
{
public Guid NetworkId { get; set; }
public List<Guid>? PartnerIds { get; set; }
}
My OnModelCreating method is shown here:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
builder.Entity<AllocationSupplierViewDto>().HasKey(e => e.Id);
builder.Entity<AllocationSupplierViewDto>().ToView("vw_SupplierInformation");
builder.Entity<AllocationSupplierViewDto>()
.HasMany(e => e.BusinessClientConfiguration)
.WithOne(e => e.AllocationSupplierViewDto)
.HasForeignKey(e => e.AllocationSupplierViewDtoId)
.IsRequired();
builder.Entity<BusinessClientConfigurationViewDto>().HasKey(e => e.BusinessClientId);
builder.Entity<ServiceViewDto>(eb =>
{
eb.HasKey(e => e.ServiceTypeId);
});
builder.Entity<NetworkViewDto>(eb =>
{
eb.HasKey(e => e.NetworkId);
});
base.OnModelCreating(builder);
}
I thought that my OnModelCreating will do everything and at the end all nested objects like BusinessClientConfiguration will have populated data from SQL view base on relationship from there. Where am I making a mistake?
At this moment, BusinessClientConfiguration is null and I do not know why.
I tried to follow documentation: https://learn.microsoft.com/en-us/ef/core/modeling/relationships/one-to-many#required-one-to-many
UPDATE: My DbSet is shown below:
public DbSet<AllocationSupplierViewDto> SupplierInformation { get; set; }
In general BusinessClientConfiguration doesn't exist in database as a table. It's just DTO to which I would like to add part of data returned from SQL view.
FromSqlInterpolatedand aFormattableStringSupplierInformationto the view? There should be aToViewsomewhere in the configuration. Either way, the problem with the current method is that it returnsIEnumerable, so there's no way to compose upon it, or to addInclude.builder.Entity<AllocationSupplierViewDto>().HasNoKey().ToView("vw_SupplierInformation");Right now it's not important that myGetAllocationSuppliersByIdAsyncreturn IEnumerable because first I need to have proper data inside of this method.