我有一个实体,它既有存储在数据库表中的常规属性,也有对系统磁盘上本地文件的引用。我希望将此文件的create / replace / delete方法封装在数据访问层中,让应用程序的其他部分不关心应该如何以及在何处存储它,只需发送一个字节流perform" clear&# 34;操作。与此同时,我喜欢在web.config中定义的文件目录,如数据库访问参数 我是我的网络应用程序我使用EF 5 Code First并定义了实体,如下例所示:
// EF entity
public class UserImage{
public string Description { get; set; }
[NotMapped]
public LocalFile File { get; set; }
}
// not EF entity
public class LocalFile{
public string Name { get; set; }
public string LocalPath { // should return full path as dir path + file name }
public string Url { // should return LocalPath mapped to Url }
public void Set(FileStream fs) { // saves file to disk }
public void Clear() { // deletes file }
}
在我的方法中,我可以说我的DbContext不仅是数据库上下文,而且是数据库和文件系统存储的上下文,我可以在创建时提供数据库连接字符串和本地目录路径。我认为这应该是一个很好的做法,如果我错了,请告诉我 现在问题是:如何从LocalFile或UserImage对象内部了解本地目录路径,以便它们可以实现LocalPath和Url属性?换句话说,应用程序的其他部分如何知道LocalFile或UserImage实例的实际Path / Url是什么?或者有没有办法为这些对象提供LocalDir,因为它们是在DbContext中创建的?最后,在UserImage中封装本地存储操作的替代方法是什么,这样任何代码都不关心文件的存储方式和位置?
答案 0 :(得分:1)
您应该为文件操作创建接口,该接口将包含两个方法:Stream GetFile(string fileName)
和void PutFile(Stream fileStream, string fileName)
,并使用具有参数locationPath
的构造函数的具体类来实现它:
public interface IFileRepository
{
Stream GetFile(string fileName);
void PutFile(Stream fileStream, string fileName);
}
public class FileRepository
{
private readonly string localPath;
public FileRepository(string localPath)
{
_localPath = localPath;
}
public Stream GetFile(string fileName)
{
var file = //get filestram from harddrive using fileName and localPath
return file;
}
...
public void PutFile(Stream fileStream, string fileName)
{
//save input stream to disk file using fileName and localPath
}
}
在DbContext类中,您应该创建IFileRepository类型的私有字段,并在构造函数中从参数初始化它:
public class SomeDbContext:DbContext
{
private readonly IFileRepository _fileRepository;
public SomeDbContext(IFileRepository fileRepository)
{
_fileRepository = fileRepository;
}
...
}
并使用此_fileRepository在DbContext方法中放置和获取文件。
接口类型参数的具体类应该由Inversion of Control容器(或其他实现的Inversion of Control原理)传递。
<强>更新强>
public class UserImage
{
public string Description { get; set; }
[NotMapped]
public LocalFile File { get; set; }
}
// not EF entity
public class LocalFile
{
private readonly string _filePath;
public LocalFile(string filePath)
{
_filePath=filePath;
}
public string Name { get; set; }
public string LocalPath { // aggregate Name and filePath }
public string Url { // should return LocalPath mapped to Url } If i where you, i would write helper for this
}
答案 1 :(得分:0)
我认为我的错误是我正在尝试从实体内部访问上下文属性(即目录路径)。 EF数据库上下文体系结构没有实现它,实体也不知道它们是如何存储的。我不想发布这个经典
用于存储文件的目录可以被视为上下文属性(如连接字符串)和实体属性(如路径)。为了实现第一种情况,我可以为myDbContext
提供Directory
属性,然后通过调用myContext.GetUrl(userImage.FileName)
通过上下文实例解析所有路径。但myDbContext
并非始终可以从演示文稿级别直接访问,我将无法提取userImage
的{{1}}将其设置在网页上,直到我向所有人宣传Url
上层。
如果我将myDbContext
视为Directory
的属性,那么我需要以某种方式在构造函数中注入其值:
LocalFile
或使用之前设置的静态目录(比如在global.asax中):
public class LocalFile{
// Constructor
public LocalFile(string dir){ // set current dir }
private string _dir;
public GetUrl(){ // return _dir + filename }
}
// cons: parameterless constructor that will be called by DbContext on getting
// data from DB won't set `_dir` and GetUrl won't return correct result
甚至直接访问web.config以获取路径:
public class LocalFile{
// Constructor
public LocalFile(){ // empty }
public static Dir;
public GetUrl(){ // return Dir + filename }
}
或在可访问web.config的上层创建扩展方法:
public class LocalFile{
// Constructor
public LocalFileType(){ // empty }
public GetUrl(){ // read dir from web.config + filename }
}
// not good idea to access web-specific assemblies from EF data classes
因此,有许多可能的解决方案,每个解决方案都有其自身的缺点。我的情况有点复杂,因为我的目录路径还取决于public static class MyExtensions
{
public static string GetUrl(LocalFile localFile)
{
// dir from web.config + localFile.Name
}
}
的父用户ID,所以我在LocalFile
而不是简单路径中有dir模板users/{0}/image.jpg
。
我为实现目标所做的工作:
web.config
类型的url模板(0 - 父UserId,1 -
fileName)到web.config
在我的EF实体附近创建了类设置
users/{0}/{1}
在应用程序启动时填充其值
public static class Shared
{
public static Func<string, int, string> LocalFileUrlResolver;
}
让我的用户在创建时使用Url解析器提供自己的图像 时间
protected void Application_Start()
{
Shared.LocalFileUrlResolver =
(fileName, userId) =>
String.Format(ConfigurationManager.AppSettings["LocalFileUrl"], userId, fileName);
}
使我的LocalFile构造函数接受public User()
{
// ...
Image = new LocalFile(
"userpic.css",
fileName => Shared.LocalFileUrlResolver(fileName, userId)
);
}
param
它解析了给定文件名的完整Url
Func<string, string>
是的,这么多行。我从public class LocalFile
{
public LocalFile(
string fileName,
Func<string, string> fnUrlResolver
)
{
FileName = fileName;
_fnUrlResolver = fnUrlResolver;
}
private readonly Func<string, string> _fnUrlResolver;
public string FileName { get; private set; }
public string Url { get { return _fnUrlResolver(FileName); } }
}
获取dir模板,将其注入数据访问层的静态成员,并在web.config
创建点上为用户的本地图像更具体。
我绝对不确定它是否值得花费。也许将来我会选择直接访问User
:)