stroibot
stroibot

Reputation: 868

Store files in database using Entity Framework Core

How to store files in a SQL Server database using Entity Framework Core (Code-First) in an ASP.NET Core app?

I have tried using Filestream but unfortunately I get this error:

Cannot call Property for the property 'Avatar' on entity type 'UserProfile' because it is configured as a navigation property. Property can only be used to configure scalar properties

Here's the code:

public class UserProfile : BaseEntity {
    public FileStream Avatar { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public Sex Sex { get; set; }
    public string Address { get; set; }
    public string PhoneNumber { get; set; }

    public virtual IEnumerable<Email> Emails { get; set; }
    public virtual User User { get; set; }
    public int UserID { get; set; }
}

And mapping:

public class UserProfileMap {
    public UserProfileMap(EntityTypeBuilder<UserProfile> entityBuilder) {
        entityBuilder.HasKey(e => e.ID);
        entityBuilder.Property(e => e.Avatar);
        entityBuilder.Property(e => e.FirstName);
        entityBuilder.Property(e => e.LastName);
        entityBuilder.Property(e => e.DateOfBirth);
        entityBuilder.Property(e => e.Sex);
        entityBuilder.Property(e => e.Address);
        entityBuilder.Property(e => e.PhoneNumber);
        entityBuilder.HasMany(e => e.Emails).WithOne(u => u.UserProfile).HasForeignKey(x => x.UserProfileID);
    }
}

What do I do? Thanks!

Upvotes: 19

Views: 32050

Answers (4)

sitholewb
sitholewb

Reputation: 329

There is a much better way of storing files with EntityFrameworkCore, this library make it much easier https://www.nuget.org/packages/Files.EntityFrameworkCore.Extensions

Its stores files in small chunks so you don't have to worry about using too much memory during file upload or downloading.

Examples are also available on Github repopsitory

public class UserImage : IFileEntity
{
    public Guid Id { get; set; }
    public Guid FileId { get; set; }
    public string Name { get; set; }
    public string MimeType { get; set; }
    public DateTimeOffset TimeStamp { get; set; }
    public Guid? NextId { get; set; }
    public int ChunkBytesLength { get; set; }
    public long TotalBytesLength { get; set; }
    public byte[] Data { get; set; }
}

[HttpPost]
public async Task<ActionResult<FilesExtensionsResponse>> UploadFile([FromForm] IFormFile file)
{
     if (file.Length > 0)
     {
         var fileDetails = await _context.SaveFileAsync<UserImage>(file.OpenReadStream(), file.FileName, file.ContentType);
         return Ok(fileDetails);
     }
     else
     {
         return BadRequest("File is required.");
     }
}
[HttpGet("{id}/download")]
public async Task<IActionResult> DownLoadFile(Guid id)
{
    var fileDetails = await _context.GetFileInfoAsync<UserImage>(id);
    var stream = new MemoryStream();
    await _context.DownloadFileToStreamAsync<UserImage>(id, stream);
    return File(stream, fileDetails.MimeType, fileDetails.Name);
}
// And more methods are available

Upvotes: 1

farid salehi
farid salehi

Reputation: 99

By Ef core, you can't store file in your database until now, so you can:

  1. store the result of reading files as byte[] like this :
public byte[] Avatar { get; set; }
var avatar =  File.ReadAllBytes(filePath);

2.use your machine as a file server and store the path of your file in database :

public string Avatar { get; set; }

In my Opinion the second way is better and i always use this pattern but it depends on your machine's H.D.D and the amount of files you want to store.

Upvotes: 3

alsami
alsami

Reputation: 9815

I am assuming that you are trying to use the windows filestream for sql server, which is not yet supported by .NET Core. You have to store the file as a byte array as already said (which will convert to varbinary(max) in sql server) and copy the file content over when uploading using a memory-stream for instance.

Upvotes: 3

Roman Bartke
Roman Bartke

Reputation: 376

You can convert the file bytes to a byte array.

public byte[] Avatar { get; set; }

Examine the accepted answer in the analogous approach for EF6: Save and retrieve image (binary) from SQL Server using Entity Framework 6

Upvotes: 24

Related Questions