C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架
如题,在github上找了一圈想找一个mongodb的的orm框架,未偿所愿,就去翻了翻官网()
看了看文档发现官方的驱动功能已经相当强大了并且更新速度很快
2.3之后得驱动版本已经支持 .net 5,而且方法都已支持task ,可以配合async , await.使用 ,同时也支持lambda表达式及表达式树 官方是这么说的()
官方得驱动如此强大了,还找什么orm框架,我们自己基于官方驱动手撸一个简易版的,首先简单讲一下设计思路
要求1:首先要有一个对象实体基类,为什么要创建实体对象基类?是因为官方驱动支持的实体类与collection得映射 必须要有id字段,对应数据库中得"_id",并且这个字段是objectidl类型,像这样
public class person { [bsonid] [bsonelement("_id")] public objectid id { get; set; } }
所以创建实体基类是为了免去每个实体类都要创建这个id的冗余代码.
要求2:实现实体类与collection得自动映射 自动创建数据库连接.这一部分实现就稍微复杂一些,首先我们需要自定义一个attribute,用于获取获取集合名称,然后创建一个管理器实现一些自动映射的初始化操作
要求3:实现repository仓储类.提供简单得crud方法. 这一部分就比较简单了,通过封装直接调用官方的驱动提供的api,实现curd操作
开始实现之前记得添加一下官方的驱动包直接在nuget搜索mongodb.driver 安装就可以了 ,我这里使用的是2.12.3版本
第一步:创建对象实体基类
[datacontract] [serializable] [bsonignoreextraelements(inherited = true)] //当bson文档被反序列化时,每个元素的名称用于在类映射中查找匹配的成员。通常,如果没有找到匹配的成员,将抛出异常。如果要在反序列化期间忽略其他元素 使用这个特性 public abstract class mongoentitybase : imongoentitybase<string> { protected mongoentitybase() { db_id = objectid.generatenewid().tostring(); //对id进行初始化 } [datamember] [bsonelement("_id")] [bsonrepresentation(bsontype.objectid)] //因为 objectid 这个结构体是不能序列化的,所以使用 [bsonrepresentation(bsontype.objectid)] 标记为这个字符串id在mongo中代表objectid public virtual string db_id { get; set; } } public interface imongoentitybase<tkey> { [bsonid] tkey db_id { get; set; } } public interface imongoentitybase : imongoentitybase<string> { }
第二步:实现实体类与collection的自动映射;
我们需要先创建一个attribute类,用于标记实体类来获取实体类对应的集合名称,如下:
[attributeusage(attributetargets.class, inherited = true)] public class collectionnameattribute : attribute { public collectionnameattribute(string name) { if (string.isnullorempty(name)) throw new argumentexception("empty collectionname not allowed", "name"); this.name = name; } public string name { get; private set; } //定义一个属性 用于获取collection名称 }
接下来实现一个管理器,用于自动映射,数据库连接的自动映射,官方驱动其实已经提供了实体类的自动映射,我们只需要接着稍微封装一下,官方自动映射demo如下:
有一部分准备工作要做,那就是需要在配置文件添加一个数据库连接的配置,用于连接数据库;
接下实现我们的管理器,这一部分是核心,实现了类与数据库collection的自动映射,并自动创建出了mongo连接
internal static class globlemanage<t> { private static string _tablename; private static string _datebasename; private static string _mongoserversettings; private static imongocollection<t> _mongocollection; public static imongocollection<t> mongocollection { get => _mongocollection; } public static string datebasename { get => _datebasename; } public static string mongoserversettings { get => _mongoserversettings; } public static string tablename { get => _tablename; } static globlemanage() { init(); } private static void init() { //初始化连接字符串 string[] parm = configurationmanager.connectionstrings["mongoserversettings"].connectionstring.split('/'); _datebasename = parm.last(); _mongoserversettings = configurationmanager.connectionstrings["mongoserversettings"].connectionstring.replace(@"/" + _datebasename, ":27017"); //根据实体类标注好的attribute获取表名 var entitytype = typeof(t); var attr = attribute.getcustomattribute(entitytype, typeof(collectionnameattribute)); //若attribute不为空 获取标注的表名 if (attr != null) { _tablename = ((collectionnameattribute)attr).name; } else { //否则 如果类型是mongoentitybase的派生类 获取类名作为表名 if (typeof(mongoentitybase).isassignablefrom(entitytype)) { // no attribute found, get the basetype while (!entitytype.basetype.equals(typeof(mongoentitybase))) { entitytype = entitytype.basetype; } } _tablename = entitytype.name; } //添加实体类映射 bsonclassmap.registerclassmap<t>(cm => cm.automap()); _mongocollection = new mongoclient(_mongoserversettings).getdatabase(_datebasename).getcollection<t>(_tablename); } }
第三步:实现repository仓储类.提供简单的crud方法
首先,先创建仓储类的泛型接口
public interface irepository<t> where t : imongoentitybase<string> { imongocollection<t> collection { get; } bool add(t entity); bool delete(t delete, expression<func<t, bool>> conditions = null); bool update(t update, expression<func<t, bool>> conditions = null); list<t> find(expression<func<t, bool>> conditions = null);
泛型仓储类实现接口,通过管理器获取自动映射得到的 imongocollection
public class repository<t> : irepository<t> where t : imongoentitybase<string> { private imongocollection<t> _mongocollection = globlemanage<t>.mongocollection; public imongocollection<t> collection => _mongocollection; public bool add(t entity) { try { _mongocollection.insertone(entity); return true; } catch (exception) { throw; } } public bool delete(t delete, expression<func<t, bool>> conditions = null) { try { string _id = string.empty; if (conditions == null) { foreach (var item in delete.gettype().getproperties()) { if (item.name == "db_id" && item.getvalue(delete) != null) { _id = item.getvalue(delete).tostring(); var result = _mongocollection.deleteone(new bsondocument("_id", bsonvalue.create(new objectid(_id)))); return result.isacknowledged; } } } var res = _mongocollection.deleteone(conditions); return res.isacknowledged; } catch (exception) { throw; } } public bool update(t update, expression<func<t, bool>> conditions = null) { try { objectid _id; var options = new replaceoptions() { isupsert = true }; if (conditions == null) { foreach (var item in update.gettype().getproperties()) { if (item.name == "db_id" && item.getvalue(update) != null) { _id = new objectid(item.getvalue(update).tostring()); var result = _mongocollection.replaceone(new bsondocument("_id", bsonvalue.create(_id)), update, options); return result.isacknowledged; } } } var res = _mongocollection.replaceone(conditions, update, options); return res.isacknowledged; } catch (exception) { throw; } } public list<t> find(expression<func<t, bool>> conditions = null) { try { if (conditions == null) { conditions = t => true; } return _mongocollection.find(conditions).tolist() ?? new list<t>(); } catch (exception) { throw; } } }
简易版的orm框架就算是基本完成,接下来使用这个框架完成一些crud操作
首先,创建一个实体类,并且继承 mongoentitybase
[serializable] public class person : mongoentitybase { [bsonconstructor] public person(string name, int age, string guid, enumgender gender) { name = name; age = age; guid = guid; gender = gender; } public string name { get; set; } public int age { get; set; } public string guid { get; set; } public enumgender gender { get; set; } public list<person> students { get => students; set => students = value; } public pet pet { get => pet; set => pet = value; } private pet pet; public override string tostring() { return "db_id:" + this.db_id + " " + "user:" + name + " " + "age:" + age + " " + "guid:" + guid + " " + "gender:" + gender.tostring() + " " + "宠物叫" + pet.name + "," + pet.age + "岁了"; } private list<person> students; } public enum enumgender { 男, 女 } public class pet { private string name; private int age; public string name { get => name; set => name = value; } public int age { get => age; set => age = value; } }
然后创建一个窗体 测试一下我们的crud功能,调用很简单 只需要一句 irepository<person> _irepository = new repository<person>();
public partial class form1 : form { private irepository<person> _irepository = new repository<person>(); private random random = new random(); public form1() { initializecomponent(); } //add private void button1_click(object sender, eventargs e) { person person = new person("张三", 8, guid.newguid().tostring(), enumgender.男); person.students = new list<person>() { new person("张小三1", 8, guid.newguid().tostring(), enumgender.男), new person("张小三2", 8, guid.newguid().tostring(), enumgender.男) ,new person("张小三3", 8, guid.newguid().tostring(), enumgender.男) ,new person("张小三4", 8, guid.newguid().tostring(), enumgender.男)}; person.pet = new pet() { name = "旺财", age = 3 }; _irepository.add(person); richtextbox1.text += "添加成功!\r\n"; } //find private void button2_click(object sender, eventargs e) { var id = textbox1.text.trim(); var list = _irepository.find(t => t.db_id.equals(id)); richtextbox1.text += "find成功:" + "\r\n "; foreach (var item in list) { richtextbox1.text += item.tostring() + "\r\n "; } } //delete private void button3_click(object sender, eventargs e) { var id = textbox1.text.trim(); //var res = _irepository.delete(t => t.db_id.equals(id)); var rese = _irepository.find(t => t.db_id.equals(id)).firstordefault(); var res = _irepository.delete(rese); richtextbox1.text += id + "删除:" + res;/*res.isacknowledged + res.deletedcount;*/ } //update private void button4_click(object sender, eventargs e) { var guid = textbox1.text.trim(); person person = _irepository.find(t => t.db_id.equals(guid)).firstordefault(); person.name = "改过之后的名字" + random.next(1, 10); var res = _irepository.update(person); richtextbox1.text += guid + "更新:" + res; } //clear private void button5_click(object sender, eventargs e) { textbox1.clear(); richtextbox1.clear(); } //findall private void button6_click(object sender, eventargs e) { var list = _irepository.find(); richtextbox1.text += "findall成功:" + "\r\n "; foreach (var item in list) { richtextbox1.text += item.tostring() + "\r\n"; } } }
简易版本的功能基本都实现,实际上,一个成熟的orm框架还有好多工作要做
链接: https://pan.baidu.com/s/1t9xbfqxhb6iz5qjec0wloq
提取码: y9d2
以上就是c#基于mongo的官方驱动手撸一个super简易版mongodb-orm框架的详细内容,更多关于c# mongodb-orm框架的资料请关注其它相关文章!