欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

程序员文章站 2022-04-03 20:39:40
如题,在github上找了一圈想找一个mongodb的的orm框架,未偿所愿,就去翻了翻官网()看了看文档发现官方的驱动功能已经相当强大了并且更新速度很快      2.3之后得驱动版本已经支持 .n...

  如题,在github上找了一圈想找一个mongodb的的orm框架,未偿所愿,就去翻了翻官网()

看了看文档发现官方的驱动功能已经相当强大了并且更新速度很快

  C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    2.3之后得驱动版本已经支持 .net 5,而且方法都已支持task ,可以配合async , await.使用 ,同时也支持lambda表达式及表达式树 官方是这么说的()

  C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    官方得驱动如此强大了,还找什么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如下:

   C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

  有一部分准备工作要做,那就是需要在配置文件添加一个数据库连接的配置,用于连接数据库;

   C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

  接下实现我们的管理器,这一部分是核心,实现了类与数据库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";
            }
        }
    }

C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

简易版本的功能基本都实现,实际上,一个成熟的orm框架还有好多工作要做

链接: https://pan.baidu.com/s/1t9xbfqxhb6iz5qjec0wloq

提取码: y9d2

以上就是c#基于mongo的官方驱动手撸一个super简易版mongodb-orm框架的详细内容,更多关于c# mongodb-orm框架的资料请关注其它相关文章!