您的位置:首页 > 数据库 > Mongodb

C# mongoDB.net driver 2.4.0实现上传下载文件及文件列表的多条件查询

2017-01-21 09:45 941 查看
本人也是初学mongodb,本文记录的是自己在项目中实践出来的,觉得有用的可以参考下,不对的或者有更好的欢迎大家给我留言指正,谢谢!

mongoDB.net driver 2.4.0对C# winform中的文件的操作我主要用到了MongoDB.Driver.GridFS Namespace这个命名空间下的类,为了展示方便,我在这里了整理了一个小例子:

本例子中实现了将本地的文件上传到mongodb,及下载mongodb中的文件到本地,并能对mongodb中的文件进行检索和修改。

首先看一下界面:



首先要将用到的mongodb的驱动类引用到代码中

using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using MongoDB.Bson.Serialization.Attributes;





//初始化mongo客户端实体对象,数据库,文件操作对象
string mongoConn =code.DBHelper.mongoConn; //"mongodb://localhost:27017/edm";
MongoClient client;
IMongoDatabase db;
GridFSBucket bucket;
//实例化
client = new MongoClient(mongoConn);
//选择名称为edm的数据库,如果没有则在mongodb中自动创建,并指向它
db = client.GetDatabase("edm");
//实例化用于文件上传下载操作的GridFSBucket对象
bucket = new GridFSBucket(db, new GridFSBucketOptions
{
BucketName = "packingfs"//此处是命名上传到mongodb中的文件集合,默认mongodb中的名称为fs
});





1、上传功能

/// <summary>
/// 上传
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void uploadFileBtn_Click(object sender, EventArgs e)
{
string uploadfile = txt_File.Text.Trim();//本地文件路径

try
{
using (FileStream fileStream = File.Open(uploadfile, FileMode.Open))
{

string fileName = Path.GetFileName(uploadfile);
string fileExtension = Path.GetExtension(uploadfile);
//这里用到的是异步上传文件方法UploadFromStreamAsync
var objectId = await bucket.UploadFromStreamAsync(fileName, fileStream, new GridFSUploadOptions
{
//此处可以加自定义属性,新的驱动版本中已经不在使用Aliases,也不可以直接将别的属性加载该对象中,必须将额外的属性加载Metadata中
Metadata = new BsonDocument { { "filebelong", fileBelong.包装资料 }, { "fileExtension", fileExtension }, { "isdelete", 0 } }

});
ListViewItem item = new ListViewItem(fileName);//此处是界面UI上的赋值
item.Tag = objectId;
item.SubItems.Add(fileExtension);
item.SubItems.Add(fileStream.Length.ToString());
listView1.Items.Add(item);

}

}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}


上传后在mongodb中的内容如下:



其中红线部分的是自己自定义的额外属性,比如我这里加了文件所属模块值、文件扩展名、逻辑删除标记值。

2、下载

/// <summary>
/// 下载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btnDownLoad_Click(object sender, EventArgs e)
{
if (listView1.Items.Count > 0)
{
int count = listView1.CheckedItems.Count;
if (count > 0)
{

string downLoadRootPath =Path.Combine( AppDomain.CurrentDomain.BaseDirectory,"download");
for (int i = 0; i < listView1.CheckedItems.Count; i++)
{
ObjectId objectId = (ObjectId)listView1.CheckedItems[i].Tag;
string fileName = listView1.CheckedItems[i].SubItems[0].Text;
string downLoadPath = Path.Combine(downLoadRootPath, fileName);
if (!Directory.Exists(downLoadRootPath)){

Directory.CreateDirectory(downLoadRootPath);

}
using (FileStream stream = new FileStream(downLoadPath, FileMode.OpenOrCreate))
{
//这里用到的是Stream方式的异步下载方法
await bucket.DownloadToStreamAsync(objectId, stream);

};
}
}
else
{
MessageBox.Show("请选择下载项");
}
}
}
这里的objectId是mongodb中的文件的_id值,绑定到界面listview的代码如下:

private async void loadFileData()
{
listView1.Items.Clear();
client = new MongoClient(mongoConn);
db = client.GetDatabase("edm");
bucket = new GridFSBucket(db, new GridFSBucketOptions
{
BucketName = "packingfs"
});
//全部查询
var filter = Builders<GridFSFileInfo>.Filter.And(Builders<GridFSFileInfo>.Filter.Empty);
using (var cursor = await bucket.FindAsync(filter))
{
var fileInfos = (await cursor.ToListAsync());
foreach (var fileInfo in fileInfos)
{
var id = fileInfo.Id;
var filename = fileInfo.Filename;
var filesize = fileInfo.Length;
var uploadDate = fileInfo.UploadDateTime.AddHours(8).ToString("yyyy-MM-dd hh:mm:ss");//mongo上面的时间为UTC类型,转换到本地须加8个时区
var metadata = fileInfo.Metadata;

ListViewItem item = new ListViewItem(filename);
item.Tag = id;
if (metadata != null)
{
foreach (var aa in metadata)
{
var name = aa.Name;
var value = aa.Value;
if (aa.Name == "fileExtension")
{
item.SubItems.Add(aa.Value.ToString());
}

}

}
else
{
item.SubItems.Add("");
}
item.SubItems.Add(filesize.ToString());
item.SubItems.Add(uploadDate);
listView1.Items.Add(item);
}
};
}


这里是使用GridFSFileInfo类对象进行过滤检索,针对其他属性作为检索条件的查询我尝试了下没能很好的实现,所有在下面的4、多条件查询中会将集合对象换映射成自定义的 实体类来实现,其中实现了模糊查询、上传时间范围及其他自定义属性的匹配查询等。

3、删除

删除我做了物理删除和逻辑删除两种,所谓物理删除就是将mongodb中的文件真实的删除了,逻辑删除只是将mongodb中的自定义的metadata中的isdelete属性值设为1,界面查询文件的时候过滤为1的。

/// <summary>
/// 物理删除文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btn_delete_Click(object sender, EventArgs e)
{
if (listView1.Items.Count > 0)
{

int count = listView1.CheckedItems.Count;
if (count > 0)
{
for (int i = 0; i < listView1.CheckedItems.Count; i++)
{
ObjectId objectId = (ObjectId)listView1.CheckedItems[i].Tag;
await bucket.DeleteAsync(objectId);

}
}
else
{
MessageBox.Show("请选择删除项");
}
}
}
/// <summary>
/// 逻辑删除文件,将文件中的isdelete属性值1
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btn_luo_del_Click(object sender, EventArgs e)
{
if (listView1.Items.Count > 0)
{
//int j = 0;
int count = listView1.CheckedItems.Count;
if (count > 0)
{
for (int i = 0; i < listView1.CheckedItems.Count; i++)
{
ObjectId objectId = (ObjectId)listView1.CheckedItems[i].Tag;
var filter = new BsonDocument("_id", objectId);
var update = new BsonDocument("$set", new BsonDocument("metadata.isdelete", 1));
var result = await db.GetCollection<BsonDocument>("packingfs.files").UpdateOneAsync(filter, update);
}
}
else
{
MessageBox.Show("请选择删除项");
}
}
}


4、多条件查询

查询我使用了mongo驱动中转换为可linq的方式,并且使用了将BsonDocument中的元素序列化映射成自定义的实体对象

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace Model
{
/// <summary>
/// 文件在mongo中的相关信息实体类
/// </summary>
public class mongoFileInfo
{
/// <summary>
/// 文件ID,默认将string类型转换成ObjectId类型
/// </summary>
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
/// <summary>
/// 文件文档大小
/// </summary>
[BsonElement("length")]
public long Length { get; set; }
/// <summary>
/// 文档容量大小
/// </summary>
[BsonElement("chunkSize")]
public long ChunkSize { get; set; }
/// <summary>
/// 文件名
/// </summary>
[BsonElement("filename")]
public string Filename { get; set; }
/// <summary>
/// 上传时间
/// </summary>
[BsonElement("uploadDate")]
public DateTime UploadDate { get; set; }
/// <summary>
/// 在mongo中的加密字符串
/// </summary>
[BsonElement("md5")]
public string Md5 { get; set; }
/// <summary>
/// 文件文档的自定义内容
/// </summary>
[BsonElement("metadata")]
public fileMetadataInfo MetadataInfo { get; set; }
}
/// <summary>
/// 文件自定义文档信息实体类,后期对文件的自定义属性都可在这里扩展
/// </summary>
public class fileMetadataInfo
{
/// <summary>
/// 文件所属模块
/// </summary>
[BsonElement("filebelong")]
public belongModule Filebelong { get; set; }
/// <summary>
/// 文件的扩展名
/// </summary>
[BsonElement("fileExtension")]
public string FileExtension { get; set; }
/// <summary>
/// 逻辑删除字段;0:不删除;1:删除,默认0
/// </summary>
[BsonElement("isdelete")]
public int Isdelete { get; set; }

}
///// <summary>
///// 文件所属模块枚举
///// </summary>
public enum belongModule{
公共=0,
包装资料=1
}
/// <summary>
/// 文件查询条件类,使用时,不需要的条件可不赋值或给null
/// </summary>
public class mongoFileSearch
{
/// <summary>
/// 文件在mongo中的objectId
/// </summary>
public string Id { get; set; }
/// <summary>
/// 文件名,支持模糊匹配
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 文件扩展名数组,如:查图片new string[]{".JPG",".PNG",".GIF"}等
/// </summary>
public string[] FileExtension { get; set; }
/// <summary>
/// 逻辑删除字段 0:不删除;1:删除
/// </summary>
public int? Isdelete { get; set; }
/// <summary>
/// 上传时间范围最小时间值
/// </summary>
public DateTime? UploadStime { get; set; }
/// <summary>
/// 上传时间范围最大时间值
/// </summary>
public DateTime? UploadEtime { get; set; }
/// <summary>
/// 文件所属模块
/// </summary>
public belongModule? Filebelong { get; set; }
}
}
有了这些准备工作,下面来实现查询了

/// <summary>
/// 分页查询mongo文件列表
/// </summary>
/// <param name="search">查询条件对象</param>
/// <param name="pageindex">当前索引,从1开始</param>
/// <param name="pagesize">每页显示数量</param>
/// <param name="totalCount">总条数</param>
/// <returns></returns>
public List<mongoFileInfo> MongoFileQuery(mongoFileSearch search, int pageindex, int pagesize, out int totalCount)
{
//获取mongo上文件的集合
var _fileColl = db.GetCollection<mongoFileInfo>(string.Format("{0}{1}", DbCommon.MongoFileCollectName, ".files"));
//逻辑删除字段
int _isdelete = 0;
if (search.Isdelete.HasValue)
{
_isdelete = search.Isdelete.Value;
}
//将mongo集合映射成linq查询
var _queryable = _fileColl.AsQueryable();

var _query = _queryable.Where(e => e.MetadataInfo.Isdelete == _isdelete).ToList();
//文件名模糊查询
if (search.FileName != string.Empty)
{
_query = _query.Where(e => e.Filename.Contains(search.FileName)).ToList();
}
//文件扩展名
else if (search.FileExtension != null && search.FileExtension.Length > 0)
{
_query = _query.Where(e => search.FileExtension.Contains(e.MetadataInfo.FileExtension.ToUpper())).ToList();
}
//文件所属模块
else if (search.Filebelong.HasValue)
{
_query = _query.Where(e => e.MetadataInfo.Filebelong == search.Filebelong.Value).ToList();
}
//上传时间范围最小值
else if (search.UploadStime.HasValue)
{
_query = _query.Where(e => e.UploadDate.AddHours(8) >= search.UploadStime).ToList();//mongo上面的时间是UTC时间,比我们小八个时区,所有需要加上8个小时进行比较
}
//上传时间范围最大值
else if (search.UploadEtime.HasValue)
{
_query = _query.Where(e => e.UploadDate.AddHours(8) <= search.UploadEtime).ToList();
}
totalCount = _query.Count();
return _query.OrderByDescending(e => e.UploadDate).Skip(pagesize * (pageindex - 1)).Take(pagesize).ToList();//按上传时间倒序
}


好了,到这里基本的文件上传、下载、删除及查询的主要代码都展示完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息