In ASP.NET Core-6 Web API, I have these models:
public class LeaveApplication
{
public Guid Id { get; set; }
public Guid EmployeeId { get; set; }
public string ReferenceNumber { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual Employee Employee { get; set; }
public virtual LeaveApproval LeaveApproval { get; set; }
}
public class LeaveApproval
{
public Guid Id { get; set; }
public bool? IsApproved { get; set; }
public DateTime? ApprovedDate { get; set; } = null;
public virtual ICollection<LeaveApprovalAttachment> LeaveApprovalAttachments { get; set; }
}
public class LeaveApprovalAttachment
{
public Guid Id { get; set; }
public Guid LeaveApprovalId { get; set; }
public string FileType { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public long? FileSize { get; set; }
public virtual LeaveApproval LeaveApproval { get; set; }
}
A LeaveApplication has one LeaveApproval, while a LeaveApproval can have many LeaveApprovalAttachments.
Based on parameter id, I want to get a filepath of a LeaveApprovalAttachment and download the document. So, I have this code:
public async Task<LeaveApplication> GetLeaveDocumentByIdAsync(Guid id)
{
var leave = await _dbContext.LeaveApplications
.Where(m => (bool)m.IsApproved)
.Include(x => x.LeaveApproval)
.ThenInclude(x => x.LeaveApprovalAttachments)
.FirstOrDefaultAsync(x => x.LeaveApproval.LeaveApprovalAttachments.Any(x => x.Id == id));
var path = Path.Combine(Directory.GetCurrentDirectory(), leave.LeaveApproval.LeaveApprovalAttachments.FilePath);
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.position = 0;
var contentType = "APPLICATION/octet-stream";
var fileName = Path.GetFileName(path);
return File(memory, contentType, fileName);
}
But I got this error:
Error CS1061 'ICollection' does not contain a definition for 'FilePath' and no accessible extension method 'FilePath' accepting a first argument of type 'ICollection' could be found (are you missing a using directive or an assembly reference?)
and it highlights FilePath in leave.LeaveApproval.LeaveApprovalAttachments.FilePath
How do I resolve this?
Thanks
CodePudding user response:
From here:
public virtual ICollection<LeaveApprovalAttachment> LeaveApprovalAttachments { get; set; }
LeaveApprovalAttachments
property is a collection. You can't direct access via leave.LeaveApproval.LeaveApprovalAttachments.FilePath
.
Instead, you need to provide the index to LeaveApprovalAttachments
as:
leave.LeaveApproval.LeaveApprovalAttachments[0].FilePath
Or to get the first item of LeaveApprovalAttachments
:
using System.Linq;
var leaveApprovalAttachment = leave.LeaveApproval.LeaveApprovalAttachments.FirstOrDefault();
if (leaveApprovalAttachment != null)
{
var path = Path.Combine(Directory.GetCurrentDirectory(), leaveApprovalAttachment.FilePath);
...
}
CodePudding user response:
You're getting that error because LeaveApprovalAttachments
is of type ICollection<LeaveApprovalAttachment>
and not LeaveApprovalAttachment
. You can see from the documentation of ICollection<T>
that there is no FilePath
property. You also can't just access a property of the element type, which is LeaveApprovalAttachment
in this case, from the ICollection<T>
because you have multiple LeaveApprovalAttachment
s. How can it know which one you want to access?
Looking at your code, it seems like you only need a single LeaveApprovalAttachment
, so the best way to resolve it in this particular case is probably just to select the one LeaveApprovalAttachment
that you need, rather than the entire LeaveApplication
.
Maybe something like this...
var leaveAttachment = _dbContext
.LeaveApplications
.Include(la => la.LeaveApproval)
.ThenInclude(la => la.LeaveApprovalAttachments)
.Where(la => (bool)la.IsApproved)
.SelectMany(la => la.LeaveApproval.LeaveApprovalAttachments)
.FirstOrDefault(laa => laa.Id == id);
Note that you're querying on LeaveApplication.IsApproved
which doesn't seem to exist on your model, but I tried to replicate your query as much as possible.