在 asp.net 核心 2.0 MVC 中注册用户后,我希望能够上传一个 pdf 文件并将其名称或 Id 保存在该用户的表行中,以便以后下载。我已经完成了所有操作,但出现此错误:
The property 'ApplicationUser.contract' is of an interface type ('IFormFile'). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type
我不明白"将其转换为映射实体类型"是什么意思,我错过了什么吗?这是我的方法:
首先,上传文件:
var path = Path.Combine(Directory.GetCurrentDirectory(), "Uploads",model.FileToUpload.GetFilename());
using (var stream = new FileStream(path, FileMode.Create))
{
await model.FileToUpload.CopyToAsync(stream);
}
然后,将其添加到用户的属性中var user = new ApplicationUser { UserName = model.username, Email = model.Email, contract = model.FileToUpload };
应用程序用户在模型中具有以下内容:public IFormFile contract {get; set;}
注册视图模型有这个:public IFormFile FileToUpload { get; set; }
任何帮助将不胜感激。
您的错误消息来自实体框架。您可以在此处阅读有关此内容的完整详细信息:https://learn.microsoft.com/en-us/ef/core/modeling/relationships
简而言之,ApplicationUser
在实体框架中的DbContext
中作为实体分配。EF Core 通常尝试将实体类的每个属性映射到数据库中的值。EF Core 无法将IFormFile
直接映射到数据类型以在数据库中创建列(在这种情况下也不需要这样做(。
因此,第一步是告诉 EF Core"不要为此属性烦恼"。这是通过在IFormFile
属性顶部添加NotMapped
注释来完成的。下一步是将文件名保存到数据库中以供参考。我注意到您正在使用上传的文件名来执行此操作。为了避免名称冲突,您可以使用类似Guid.NewGuid().ToString()
的内容来生成唯一的字符串(不要忘记添加扩展(。为了将此文件名保存到数据库中,您需要在ApplicationUser
类中创建一个字符串属性并仅保存文件名。文件本身不需要进入user
对象。
为了补充 Neville 的回答,我建议您创建一个ApplicationUserViewModel
,以便您可以将前端逻辑和输入/验证与您用于数据库的模型域分开,更具体地说,在您获取文件协定ApplicationUserViewModel
中IFormFile
,在前一个ApplicationUser
类中创建一个属性 Id,如下所示:
public class ApplicationUser : ...
{
//... other properties
[ForeignKey("Contracts")]
public string ContractId { get; set; }
}
并创建另一个域模型类,如Contracts
:
public class Contracts
{
public Guid Id { get; set; }
public byte[] FileBlob { get; set; }
public string FileExtension { get; set; }
}
因此,在实际ApplicationUser
中,您不会存储整个文件 Blob,而是具有对它的引用,这比每次实例化 Blob 时都必须下载 Blob 的性能更高ApplicationUser
。