用c#操作Mongodb(附demo) - 保安保安 - 博客园

mikel阅读(600)

来源: 用c#操作Mongodb(附demo) – 保安保安 – 博客园

因为需要,写了一个基于泛型的helper,这样要使用起来方便一点。

为了大家也不重复造轮子,所以发出来希望能帮到谁。

复杂的查询最好用linq,这也是mongodb官方建议的。

mongodb的C#配置

这部分很多文章都提到了,需要注意的是用的驱动与你的mongodb版本还有你.Net好像有点关系

我是mongodb-2.x,.NET4,driver我用的是1.x系列

2.x系列好像我这种配置用不起,大家可以试一试,貌似要.NET要4.5才行

驱动下载地址:

https://github.com/mongodb/mongo-csharp-driver

 

这里有个小坑,mongodb的数据库连接字符串和mySQL是不一样的,很多文章没有提到完整的连接字符串,花半天在官网上看到了

mongodb://username:password@myserver:port/databaseName

 

Model的编写

其他没什么,但请注意ID、时间的类型,用的是mongdoDB自己的数据类型

这里用了一个虚函数,是为了方便helper里面用泛型获取id

 

以下是Model的源码

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Bson;
namespace WindowsFormsApplication1.Model
{
    public abstract class MongoModel
    { 
        public ObjectId id { get; set; } 
        public BsonDateTime created_at { get; set; }
        public BsonDateTime updated_at { get; set; } 
    }

 public class AccountModel : MongoModel
    {
     //例子
        public AccountModel()
        { 
        }
         
        public string name { get; set; }
        
    }
}
复制代码

 

Helper的编写

因为mongodb的操作语句必须大量用到你的Model,因此考虑用泛型来做Helper

用Builder模式的原因无非是觉得好玩,你可以修改代码用构造函数直接初始化

我也没有用静态方法,你有需要可以自己修改

 

以下是helper的源码

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Driver.Builders;

namespace FrameWork
{
    public class MongoHelper<T> where T : WindowsFormsApplication1.Model.MongoModel
    {
        public string conn;
        public string dbName;
        public string collectionName;

        private MongoCollection<T> collection;

        private MongoHelper()
        {

        }

        /// <summary>
        /// 设置你的collection
        /// </summary>
        public void SetCollection()
        {
            MongoClient client = new MongoClient(conn);
            var server = client.GetServer();
            var database = server.GetDatabase(dbName);
            collection = database.GetCollection<T>(collectionName);
        }

        /// <summary>
        /// 你用linq的时候会用到
        /// </summary>
        public void getCollection()
        {
            MongoClient client = new MongoClient(conn);
            var server = client.GetServer();
            var database = server.GetDatabase(dbName);
            collection = database.GetCollection<T>(collectionName);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public T Find(IMongoQuery query)
        {
            return this.collection.FindOne(query);
        }

        /**
         * 条件查询用linq
         * http://mongodb.github.io/mongo-csharp-driver/1.11/linq/
         * */
        public List<T> FindAll()
        {
            return this.collection.FindAll().ToList();
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public long Update(T model)
        {
            BsonDocument doc = BsonExtensionMethods.ToBsonDocument(model);
            WriteConcernResult res = this.collection.Update(Query.EQ("_id", model.id), new UpdateDocument(doc));
            return res.DocumentsAffected;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool Insert(T model)
        {
            WriteConcernResult res = this.collection.Insert(model);
            return res.Ok;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool Delete(T model)
        {
            WriteConcernResult res = this.collection.Remove(Query.EQ("_id", model.id));
            return res.Ok;
        }

        /// <summary>
        /// 构造器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class Builder<T> where T : WindowsFormsApplication1.Model.MongoModel
        {
            private MongoHelper<T> client;

            public Builder()
            {
                client = new MongoHelper<T>();
            }

            public void setConn(string conn)
            {
                client.conn = conn;
            }

            public void setDbName(string dbName)
            {
                client.dbName = dbName;
            }

            public void setCollectionName(string collectionName)
            {
                client.collectionName = collectionName;
            }

            public MongoHelper<T> build()
            {
                client.SetCollection();
                return client;
            }
        }
    }
}
复制代码

 

Helper的使用

很简单,我写在demo的form代码里了,注释也写的很清楚什么流程

1.设计好你的model

2.初始化数据库配置

3.build一个helper

4.调用方法

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DevComponents.DotNetBar;
using System.IO;
using FrameWork;

namespace WindowsFormsApplication1
{
    /**
     * 
     * MongoDB数据库增删改查DEMO
     * 任意拷贝、修改
     * 仅供学习
     * 曾维周 16/2/25
     * 
     * App独立开发群 533838427
     * 
     * */
    public partial class MainForm : DevComponents.DotNetBar.Metro.MetroForm
    {
        public Model.ConfModel conf = new Model.ConfModel();
        private bool isFirst = true;
        private string filePath;
        private List<Model.AccountModel> accounts = new List<Model.AccountModel>();
        private FrameWork.MongoHelper<Model.AccountModel> client;
        public MainForm()
        {
            InitializeComponent();
            this.Activated += new EventHandler(Form2_Activated);
        }

        void Form2_Activated(object sender, EventArgs e)
        {
            if (isFirst)
            {
                init();
                isFirst = false;
            }
        }

        void init()
        {
            /**
             * 
             * step-1
             * 配置你的mongodb链接
             * 请配置完
             * 
             * */
            conf.mongodb_dbAddr = "localhost";
        }

        private void buttonX2_Click(object sender, EventArgs e)
        {
            /**
             * 
             * step-2
             * 请操作前修改好你的model
             * 
             * step-3
             * 用builder初始化一个helper
             * 当然你也完全可以修改代码直接在构造函数里面初始化
             * 我是觉得好玩
             * 
             * */
            FrameWork.MongoHelper<Model.AccountModel>.Builder<Model.AccountModel> builder = new FrameWork.MongoHelper<Model.AccountModel>.Builder<Model.AccountModel>();
            builder.setCollectionName("你的collection名字");
            builder.setConn(conf.mongodb_conn);
            builder.setDbName(conf.mongodb_dbName);
            client = builder.build();
        }

        private void buttonX1_Click(object sender, EventArgs e)
        {
            //增
            Model.AccountModel account = new Model.AccountModel();
            account.name = "love";
            client.Insert(account);

            //删
            client.Delete(account);

            //改
            account.name = "not love";
            client.Update(account);

            //查
            Model.AccountModel res = client.Find(MongoDB.Driver.Builders.Query<Model.AccountModel>.EQ(xx => xx.id, account.id));

            //强烈建议用linq进行查询操作
            //http://mongodb.github.io/mongo-csharp-driver/1.11/linq/ 
            //var query = collection.AsQueryable<Model.AccountModel>().Where(e => e.FirstName == "John");

        }

    }
}
复制代码

 

 

参考资料

http://mongodb.github.io/mongo-csharp-driver/1.11/linq/

http://blog.csdn.net/haukwong/article/details/7840158

http://www.cnblogs.com/viprx/archive/2012/09/07/2674637.html

demo下载

链接: http://pan.baidu.com/s/1qX3vfdE 密码: buh2

轻量级ORM框架 Bankinate - 7tiny - 博客园

mikel阅读(569)

来源: 轻量级ORM框架 Bankinate – 7tiny – 博客园

【前言】

前面讲过ORM的前世今生,对ORM框架不了解的朋友可以参考博文:https://www.cnblogs.com/7tiny/p/9551754.html

今天,我们主要通过设计一款轻量级的ORM框架来介绍:如何实现一个ORM框架”

  文末给出了GitHub源码地址~

【基本要素】

既然是ORM框架,那么必不可或缺的三点:

  1.SQL语句的自动生成

  2.数据结果集自动映射到类型实体

  3.多数据库的支持

甚至可以在此三点的基础上扩展出更多的:

  1.缓存处理

  2.Api的封装

  3.日志系统

基于以上几点,那么我们逐步开始我们的设计:

为了功能抽象和细化的职责划分,我们将各个功能点拆分成为各个组件,灵活进行装配。

数据存储核心:调用底层数据库驱动执行SQL语句,将数据持久化

表映射描述器:描述表和实体的映射关系

SQL语句转化器:将封装的数据操作Api转化成对应数据库的Sql语句

数据操作上下文:用户数据操作信息传递,包装,数据库连接管理等,缓存核心配置信息的承载

缓存核心:用户ORM框架的缓存支持(一级缓存/二级缓存)

【实现细节】

我们抽象出核心功能组件后,对各个功能组件进行详细设计:

  数据存储核心:

数据存储核心主要包括对多种数据库驱动的封装调用,读写分离的简单策略,查询数据集合与强类型实体的映射(性能优化点,目前采用Expression 表达式树缓存委托方式)。

这里以封装的支持多种关系型数据库的DbHelper形式呈现

复制代码
  1 /*********************************************************
  2  * CopyRight: 7TINY CODE BUILDER. 
  3  * Version: 5.0.0
  4  * Author: 7tiny
  5  * Address: Earth
  6  * Create: 2018-04-19 21:34:01
  7  * Modify: 2018-04-19 21:34:01
  8  * E-mail: dong@7tiny.com | sevenTiny@foxmail.com 
  9  * GitHub: https://github.com/sevenTiny 
 10  * Personal web site: http://www.7tiny.com 
 11  * Technical WebSit: http://www.cnblogs.com/7tiny/ 
 12  * Description: 
 13  * Thx , Best Regards ~
 14  *********************************************************/
 15 using MySql.Data.MySqlClient;
 16 using System;
 17 using System.Collections.Generic;
 18 using System.ComponentModel;
 19 using System.Data;
 20 using System.Data.Common;
 21 using System.Data.SqlClient;
 22 using System.Linq;
 23 using System.Linq.Expressions;
 24 using System.Reflection;
 25 using System.Threading.Tasks;
 26 
 27 namespace SevenTiny.Bantina.Bankinate
 28 {
 29     public enum DataBaseType
 30     {
 31         SqlServer,
 32         MySql,
 33         Oracle,
 34         MongoDB
 35     }
 36     public abstract class DbHelper
 37     {
 38         #region ConnString 链接字符串声明
 39 
 40         /// <summary>
 41         /// 连接字符串 ConnString_Default 默认,且赋值时会直接覆盖掉读写
 42         /// </summary>
 43         private static string _connString;
 44         public static string ConnString_Default
 45         {
 46             get { return _connString; }
 47             set
 48             {
 49                 _connString = value;
 50                 ConnString_RW = _connString;
 51                 ConnString_R = _connString;
 52             }
 53         }
 54         /// <summary>
 55         /// 连接字符串 ConnString_RW 读写数据库使用
 56         /// </summary>
 57         public static string ConnString_RW { get; set; } = _connString;
 58         /// <summary>
 59         /// 连接字符串 ConnString_R 读数据库使用
 60         /// </summary>
 61         public static string ConnString_R { get; set; } = _connString;
 62         /// <summary>
 63         /// DataBaseType Select default:mysql
 64         /// </summary>
 65         public static DataBaseType DbType { get; set; } = DataBaseType.MySql;
 66 
 67         #endregion
 68 
 69         #region ExcuteNonQuery 执行sql语句或者存储过程,返回影响的行数---ExcuteNonQuery
 70         public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType = CommandType.Text)
 71         {
 72             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
 73             {
 74                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
 75                 {
 76                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
 77                     return cmd.DbCommand.ExecuteNonQuery();
 78                 }
 79             }
 80         }
 81         public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
 82         {
 83             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
 84             {
 85                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
 86                 {
 87                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);//参数增加了commandType 可以自己编辑执行方式
 88                     return cmd.DbCommand.ExecuteNonQuery();
 89                 }
 90             }
 91         }
 92         public static void BatchExecuteNonQuery(IEnumerable<BatchExecuteModel> batchExecuteModels)
 93         {
 94             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
 95             {
 96                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
 97                 {
 98                     foreach (var item in batchExecuteModels)
 99                     {
100                         PreparCommand(conn.DbConnection, cmd.DbCommand, item.CommandTextOrSpName, item.CommandType, item.ParamsDic);
101                         cmd.DbCommand.ExecuteNonQuery();
102                     }
103                 }
104             }
105         }
106         public static Task<int> ExecuteNonQueryAsync(string commandTextOrSpName, CommandType commandType = CommandType.Text)
107         {
108             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
109             {
110                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
111                 {
112                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
113                     return cmd.DbCommand.ExecuteNonQueryAsync();
114                 }
115             }
116         }
117         public static Task<int> ExecuteNonQueryAsync(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
118         {
119             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
120             {
121                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
122                 {
123                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);//参数增加了commandType 可以自己编辑执行方式
124                     return cmd.DbCommand.ExecuteNonQueryAsync();
125                 }
126             }
127         }
128         public static void BatchExecuteNonQueryAsync(IEnumerable<BatchExecuteModel> batchExecuteModels)
129         {
130             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_RW))
131             {
132                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
133                 {
134                     foreach (var item in batchExecuteModels)
135                     {
136                         PreparCommand(conn.DbConnection, cmd.DbCommand, item.CommandTextOrSpName, item.CommandType, item.ParamsDic);
137                         cmd.DbCommand.ExecuteNonQueryAsync();
138                     }
139                 }
140             }
141         }
142         #endregion
143 
144         #region ExecuteScalar 执行sql语句或者存储过程,执行单条语句,返回单个结果---ScalarExecuteScalar
145         public static object ExecuteScalar(string commandTextOrSpName, CommandType commandType = CommandType.Text)
146         {
147             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
148             {
149                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
150                 {
151                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
152                     return cmd.DbCommand.ExecuteScalar();
153                 }
154             }
155         }
156         public static object ExecuteScalar(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
157         {
158             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
159             {
160                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
161                 {
162                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);
163                     return cmd.DbCommand.ExecuteScalar();
164                 }
165 
166             }
167         }
168         public static Task<object> ExecuteScalarAsync(string commandTextOrSpName, CommandType commandType = CommandType.Text)
169         {
170             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
171             {
172                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
173                 {
174                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
175                     return cmd.DbCommand.ExecuteScalarAsync();
176                 }
177             }
178         }
179         public static Task<object> ExecuteScalarAsync(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
180         {
181             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
182             {
183                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
184                 {
185                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);
186                     return cmd.DbCommand.ExecuteScalarAsync();
187                 }
188 
189             }
190         }
191         #endregion
192 
193         #region ExecuteReader 执行sql语句或者存储过程,返回DataReader---DataReader
194         public static DbDataReader ExecuteReader(string commandTextOrSpName, CommandType commandType = CommandType.Text)
195         {
196             //sqlDataReader不能用using 会关闭conn 导致不能获取到返回值。注意:DataReader获取值时必须保持连接状态
197             SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW);
198             DbCommandCommon cmd = new DbCommandCommon(DbType);
199             PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
200             return cmd.DbCommand.ExecuteReader(CommandBehavior.CloseConnection);
201         }
202         public static DbDataReader ExecuteReader(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
203         {
204             //sqlDataReader不能用using 会关闭conn 导致不能获取到返回值。注意:DataReader获取值时必须保持连接状态
205             SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW);
206             DbCommandCommon cmd = new DbCommandCommon(DbType);
207             PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);
208             return cmd.DbCommand.ExecuteReader(CommandBehavior.CloseConnection);
209         }
210         #endregion
211 
212         #region ExecuteDataTable 执行sql语句或者存储过程,返回一个DataTable---DataTable
213 
214         /**
215          * Update At 2017-3-2 14:58:45
216          * Add the ExecuteDataTable Method into Sql_Helper_DG  
217          **/
218         public static DataTable ExecuteDataTable(string commandTextOrSpName, CommandType commandType = CommandType.Text)
219         {
220             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
221             {
222                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
223                 {
224                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
225                     using (DbDataAdapterCommon da = new DbDataAdapterCommon(DbType, cmd.DbCommand))
226                     {
227                         DataSet ds = new DataSet();
228                         da.Fill(ds);
229                         if (ds.Tables.Count > 0)
230                         {
231                             return ds.Tables[0];
232                         }
233                         return default(DataTable);
234                     }
235                 }
236             }
237         }
238         public static DataTable ExecuteDataTable(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
239         {
240             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
241             {
242                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
243                 {
244                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);
245                     using (DbDataAdapterCommon da = new DbDataAdapterCommon(DbType, cmd.DbCommand))
246                     {
247                         DataSet ds = new DataSet();
248                         da.Fill(ds);
249                         if (ds.Tables.Count > 0)
250                         {
251                             return ds.Tables[0];
252                         }
253                         return default(DataTable);
254                     }
255                 }
256             }
257         }
258         #endregion
259 
260         #region ExecuteDataSet 执行sql语句或者存储过程,返回一个DataSet---DataSet
261         public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType = CommandType.Text)
262         {
263             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
264             {
265                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
266                 {
267                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType);
268                     using (DbDataAdapterCommon da = new DbDataAdapterCommon(DbType, cmd.DbCommand))
269                     {
270                         DataSet ds = new DataSet();
271                         da.Fill(ds);
272                         return ds;
273                     }
274                 }
275             }
276         }
277         public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary)
278         {
279             using (SqlConnection_RW conn = new SqlConnection_RW(DbType, ConnString_R, ConnString_RW))
280             {
281                 using (DbCommandCommon cmd = new DbCommandCommon(DbType))
282                 {
283                     PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, dictionary);
284                     using (DbDataAdapterCommon da = new DbDataAdapterCommon(DbType, cmd.DbCommand))
285                     {
286                         DataSet ds = new DataSet();
287                         da.Fill(ds);
288                         return ds;
289                     }
290                 }
291             }
292         }
293         #endregion
294 
295         #region ExecuteList Entity 执行sql语句或者存储过程,返回一个List<T>---List<T>
296         public static List<Entity> ExecuteList<Entity>(string commandTextOrSpName, CommandType commandType = CommandType.Text) where Entity : class
297         {
298             return GetListFromDataSetV2<Entity>(ExecuteDataSet(commandTextOrSpName, commandType));
299         }
300         public static List<Entity> ExecuteList<Entity>(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary) where Entity : class
301         {
302             return GetListFromDataSetV2<Entity>(ExecuteDataSet(commandTextOrSpName, commandType, dictionary));
303         }
304         #endregion
305 
306         #region ExecuteEntity 执行sql语句或者存储过程,返回一个Entity---Entity
307         public static Entity ExecuteEntity<Entity>(string commandTextOrSpName, CommandType commandType = CommandType.Text) where Entity : class
308         {
309             return GetEntityFromDataSetV2<Entity>(ExecuteDataSet(commandTextOrSpName, commandType));
310         }
311         public static Entity ExecuteEntity<Entity>(string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary) where Entity : class
312         {
313             return GetEntityFromDataSetV2<Entity>(ExecuteDataSet(commandTextOrSpName, commandType, dictionary));
314         }
315         #endregion
316 
317         #region ---PreparCommand 构建一个通用的command对象供内部方法进行调用---
318         private static void PreparCommand(DbConnection conn, DbCommand cmd, string commandTextOrSpName, CommandType commandType, IDictionary<string, object> dictionary = null)
319         {
320             //打开连接
321             if (conn.State != ConnectionState.Open)
322             {
323                 conn.Open();
324             }
325 
326             //设置SqlCommand对象的属性值
327             cmd.Connection = conn;
328             cmd.CommandType = commandType;
329             cmd.CommandText = commandTextOrSpName;
330             cmd.CommandTimeout = 60;
331 
332             if (dictionary != null)
333             {
334                 cmd.Parameters.Clear();
335                 DbParameter[] parameters;
336                 switch (conn)
337                 {
338                     case SqlConnection s:
339                         parameters = new SqlParameter[dictionary.Count];
340                         break;
341                     case MySqlConnection m:
342                         parameters = new MySqlParameter[dictionary.Count];
343                         break;
344                     //case OracleConnection o:
345                     //parameters = new OracleParameter[dictionary.Count];
346                     //break;
347                     default:
348                         parameters = new SqlParameter[dictionary.Count];
349                         break;
350                 }
351 
352                 string[] keyArray = dictionary.Keys.ToArray();
353                 object[] valueArray = dictionary.Values.ToArray();
354 
355                 for (int i = 0; i < parameters.Length; i++)
356                 {
357                     switch (conn)
358                     {
359                         case SqlConnection s:
360                             parameters[i] = new SqlParameter(keyArray[i], valueArray[i]);
361                             break;
362                         case MySqlConnection m:
363                             parameters[i] = new MySqlParameter(keyArray[i], valueArray[i]);
364                             break;
365                         //case OracleConnection o:
366                         // parameters[i] = new OracleParameter(keyArray[i], valueArray[i]);
367                         // break;
368                         default:
369                             parameters[i] = new SqlParameter(keyArray[i], valueArray[i]);
370                             break;
371                     }
372                 }
373                 cmd.Parameters.AddRange(parameters);
374             }
375         }
376         #endregion
377 
378         #region 通过Model反射返回结果集 Model为 Entity 泛型变量的真实类型---反射返回结果集
379         public static List<Entity> GetListFromDataSet<Entity>(DataSet ds) where Entity : class
380         {
381             List<Entity> list = new List<Entity>();//实例化一个list对象
382             PropertyInfo[] propertyInfos = typeof(Entity).GetProperties();     //获取T对象的所有公共属性
383 
384             DataTable dt = ds.Tables[0];//获取到ds的dt
385             if (dt.Rows.Count > 0)
386             {
387                 //判断读取的行是否>0 即数据库数据已被读取
388                 foreach (DataRow row in dt.Rows)
389                 {
390                     Entity model1 = System.Activator.CreateInstance<Entity>();//实例化一个对象,便于往list里填充数据
391                     foreach (PropertyInfo propertyInfo in propertyInfos)
392                     {
393                         try
394                         {
395                             //遍历模型里所有的字段
396                             if (row[propertyInfo.Name] != System.DBNull.Value)
397                             {
398                                 //判断值是否为空,如果空赋值为null见else
399                                 if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
400                                 {
401                                     //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换
402                                     NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType);
403                                     //将convertsionType转换为nullable对的基础基元类型
404                                     propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], nullableConverter.UnderlyingType), null);
405                                 }
406                                 else
407                                 {
408                                     propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], propertyInfo.PropertyType), null);
409                                 }
410                             }
411                             else
412                             {
413                                 propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null
414                             }
415                         }
416                         catch (Exception)
417                         {
418                             propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null
419                         }
420                     }
421                     list.Add(model1);//将对象填充到list中
422                 }
423             }
424             return list;
425         }
426         public static List<Entity> GetListFromDataSetV2<Entity>(DataSet ds) where Entity : class
427         {
428             List<Entity> list = new List<Entity>();
429             DataTable dt = ds.Tables[0];
430             if (dt.Rows.Count > 0)
431             {
432                 foreach (DataRow row in dt.Rows)
433                 {
434                     Entity entity = FillAdapter<Entity>.AutoFill(row);
435                     list.Add(entity);
436                 }
437             }
438             return list;
439         }
440         public static Entity GetEntityFromDataReader<Entity>(DbDataReader reader) where Entity : class
441         {
442             Entity model = System.Activator.CreateInstance<Entity>();           //实例化一个T类型对象
443             PropertyInfo[] propertyInfos = model.GetType().GetProperties();     //获取T对象的所有公共属性
444             using (reader)
445             {
446                 if (reader.Read())
447                 {
448                     foreach (PropertyInfo propertyInfo in propertyInfos)
449                     {
450                         //遍历模型里所有的字段
451                         if (reader[propertyInfo.Name] != System.DBNull.Value)
452                         {
453                             //判断值是否为空,如果空赋值为null见else
454                             if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
455                             {
456                                 //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换
457                                 NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType);
458                                 //将convertsionType转换为nullable对的基础基元类型
459                                 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], nullableConverter.UnderlyingType), null);
460                             }
461                             else
462                             {
463                                 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], propertyInfo.PropertyType), null);
464                             }
465                         }
466                         else
467                         {
468                             propertyInfo.SetValue(model, null, null);//如果数据库的值为空,则赋值为null
469                         }
470                     }
471                     return model;//返回T类型的赋值后的对象 model
472                 }
473             }
474             return default(Entity);//返回引用类型和值类型的默认值0或null
475         }
476         public static Entity GetEntityFromDataSet<Entity>(DataSet ds) where Entity : class
477         {
478             return GetListFromDataSet<Entity>(ds).FirstOrDefault();
479         }
480         public static Entity GetEntityFromDataSetV2<Entity>(DataSet ds) where Entity : class
481         {
482             DataTable dt = ds.Tables[0];// 获取到ds的dt
483             if (dt.Rows.Count > 0)
484             {
485                 return FillAdapter<Entity>.AutoFill(dt.Rows[0]);
486             }
487             return default(Entity);
488         }
489         #endregion
490     }
491 
492     /// <summary>
493     /// Auto Fill Adapter
494     /// </summary>
495     /// <typeparam name="Entity"></typeparam>
496     internal class FillAdapter<Entity>
497     {
498         private static readonly Func<DataRow, Entity> funcCache = GetFactory();
499         public static Entity AutoFill(DataRow row)
500         {
501             return funcCache(row);
502         }
503         private static Func<DataRow, Entity> GetFactory()
504         {
505             var type = typeof(Entity);
506             var rowType = typeof(DataRow);
507             var rowDeclare = Expression.Parameter(rowType, "row");
508             var instanceDeclare = Expression.Parameter(type, "t");
509             //new Student()
510             var newExpression = Expression.New(type);
511             //(t = new Student())
512             var instanceExpression = Expression.Assign(instanceDeclare, newExpression);
513             //row == null
514             var nullEqualExpression = Expression.NotEqual(rowDeclare, Expression.Constant(null));
515             var containsMethod = typeof(DataColumnCollection).GetMethod("Contains");
516             var indexerMethod = rowType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, new[] { new ParameterModifier(1) });
517             var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
518             var setExpressions = new List<Expression>();
519             //row.Table.Columns
520             var columns = Expression.Property(Expression.Property(rowDeclare, "Table"), "Columns");
521             foreach (var propertyInfo in properties)
522             {
523                 if (propertyInfo.CanWrite)
524                 {
525                     //Id,Id is a property of Entity
526                     var propertyName = Expression.Constant(propertyInfo.Name, typeof(string));
527                     //row.Table.Columns.Contains("Id")
528                     var checkIfContainsColumn = Expression.Call(columns, containsMethod, propertyName);
529                     //t.Id
530                     var propertyExpression = Expression.Property(instanceDeclare, propertyInfo);
531                     //row.get_Item("Id")
532                     var value = Expression.Call(rowDeclare, indexerMethod, propertyName);
533                     //t.Id = Convert(row.get_Item("Id"), Int32)
534                     var propertyAssign = Expression.Assign(propertyExpression, Expression.Convert(value, propertyInfo.PropertyType));
535                     //t.Id = default(Int32)
536                     var propertyAssignDefault = Expression.Assign(propertyExpression, Expression.Default(propertyInfo.PropertyType));
537                     //if(row.Table.Columns.Contains("Id")&&!value.Equals(DBNull.Value<>)) {t.Id = Convert(row.get_Item("Id"), Int32)}else{t.Id = default(Int32)}
538                     var checkRowNull = Expression.IfThenElse(Expression.AndAlso(checkIfContainsColumn, Expression.NotEqual(value, Expression.Constant(System.DBNull.Value))), propertyAssign, propertyAssignDefault);
539                     //var checkContains = Expression.IfThen(checkIfContainsColumn, propertyAssign);
540                     setExpressions.Add(checkRowNull);
541                 }
542             }
543             var checkIfRowIsNull = Expression.IfThen(nullEqualExpression, Expression.Block(setExpressions));
544             var body = Expression.Block(new[] { instanceDeclare }, instanceExpression, checkIfRowIsNull, instanceDeclare);
545             return Expression.Lambda<Func<DataRow, Entity>>(body, rowDeclare).Compile();
546         }
547     }
548 
549     /**
550     * author:qixiao
551     * time:2017-9-18 18:02:23
552     * description:safe create sqlconnection support
553     * */
554     internal class SqlConnection_RW : IDisposable
555     {
556         /// <summary>
557         /// SqlConnection
558         /// </summary>
559         public DbConnection DbConnection { get; set; }
560 
561         public SqlConnection_RW(DataBaseType dataBaseType, string ConnString_RW)
562         {
563             this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW);
564         }
565         /**
566          * if read db disabled,switchover to read write db immediately
567          * */
568         public SqlConnection_RW(DataBaseType dataBaseType, string ConnString_R, string ConnString_RW)
569         {
570             try
571             {
572                 this.DbConnection = GetDbConnection(dataBaseType, ConnString_R);
573             }
574             catch (Exception)
575             {
576                 this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW);
577             }
578         }
579 
580         /// <summary>
581         /// GetDataBase ConnectionString by database type and connection string -- private use
582         /// </summary>
583         /// <param name="dataBaseType"></param>
584         /// <param name="ConnString"></param>
585         /// <returns></returns>
586         private DbConnection GetDbConnection(DataBaseType dataBaseType, string ConnString)
587         {
588             switch (dataBaseType)
589             {
590                 case DataBaseType.SqlServer:
591                     return new SqlConnection(ConnString);
592                 case DataBaseType.MySql:
593                     return new MySqlConnection(ConnString);
594                 case DataBaseType.Oracle:
595                 //return new OracleConnection(ConnString);
596                 default:
597                     return new SqlConnection(ConnString);
598             }
599         }
600         /// <summary>
601         /// Must Close Connection after use
602         /// </summary>
603         public void Dispose()
604         {
605             if (this.DbConnection != null)
606             {
607                 this.DbConnection.Dispose();
608             }
609         }
610     }
611     /// <summary>
612     /// Common sqlcommand
613     /// </summary>
614     internal class DbCommandCommon : IDisposable
615     {
616         /// <summary>
617         /// common dbcommand
618         /// </summary>
619         public DbCommand DbCommand { get; set; }
620         public DbCommandCommon(DataBaseType dataBaseType)
621         {
622             this.DbCommand = GetDbCommand(dataBaseType);
623         }
624 
625         /// <summary>
626         /// Get DbCommand select database type
627         /// </summary>
628         /// <param name="dataBaseType"></param>
629         /// <returns></returns>
630         private DbCommand GetDbCommand(DataBaseType dataBaseType)
631         {
632             switch (dataBaseType)
633             {
634                 case DataBaseType.SqlServer:
635                     return new SqlCommand();
636                 case DataBaseType.MySql:
637                     return new MySqlCommand();
638                 case DataBaseType.Oracle:
639                 //return new OracleCommand();
640                 default:
641                     return new SqlCommand();
642             }
643         }
644         /// <summary>
645         /// must dispose after use
646         /// </summary>
647         public void Dispose()
648         {
649             if (this.DbCommand != null)
650             {
651                 this.DbCommand.Dispose();
652             }
653         }
654     }
655     /// <summary>
656     /// DbDataAdapterCommon
657     /// </summary>
658     internal class DbDataAdapterCommon : DbDataAdapter, IDisposable
659     {
660         public DbDataAdapter DbDataAdapter { get; set; }
661         public DbDataAdapterCommon(DataBaseType dataBaseType, DbCommand dbCommand)
662         {
663             //get dbAdapter
664             this.DbDataAdapter = GetDbAdapter(dataBaseType, dbCommand);
665             //provid select command
666             this.SelectCommand = dbCommand;
667         }
668         private DbDataAdapter GetDbAdapter(DataBaseType dataBaseType, DbCommand dbCommand)
669         {
670             switch (dataBaseType)
671             {
672                 case DataBaseType.SqlServer:
673                     return new SqlDataAdapter();
674                 case DataBaseType.MySql:
675                     return new MySqlDataAdapter();
676                 case DataBaseType.Oracle:
677                 //return new OracleDataAdapter();
678                 default:
679                     return new SqlDataAdapter();
680             }
681         }
682         /// <summary>
683         /// must dispose after use
684         /// </summary>
685         public new void Dispose()
686         {
687             if (this.DbDataAdapter != null)
688             {
689                 this.DbDataAdapter.Dispose();
690             }
691         }
692     }
693 
694     /// <summary>
695     /// 用于批量操作的批量操作实体
696     /// </summary>
697     public class BatchExecuteModel
698     {
699         /// <summary>
700         /// 执行的语句或者存储过程名称
701         /// </summary>
702         public string CommandTextOrSpName { get; set; }
703         /// <summary>
704         /// 执行类别,默认执行sql语句
705         /// </summary>
706         public CommandType CommandType { get; set; } = CommandType.Text;
707         /// <summary>
708         /// 执行语句的参数字典
709         /// </summary>
710         public IDictionary<string, object> ParamsDic { get; set; }
711     }
712 }
复制代码

  表映射描述器:

 

表映射描述器定义了一系列对实体的标签,以描述该实体和数据库以及数据库表之间的映射关系。除此之外还扩展了对数据库表缓存的描述。

  Sql语句转化器:

实体类+条件 Sql语句转化过程:

Sql语句转化器的功能为将友好查询Api传递的Lambda表达式语句转化成对应功能的Sql条件语句,以及对应不同数据库生成针对数据库的Sql语句。

  数据操作上下文:

数据库操作上下文作为全部数据操作的载体,在DbContext的基础上分离出SqlDbContext和NoSqlDbContext,分别支持关系型数据库和非关系型数据库。在关系型数据库上下文基础上又可以衍生出各种类型的关系型数据库上下文。该设计保证了组件的水平扩容的能力。

上下文除了维系各种数据库操作的支持以外,还扩展出了缓存组件的强力支持,可以在上下文中设置当前会话的缓存配置项。

  缓存核心:

缓存核心拓扑:

缓存核心处理流程:

详细缓存策略:

缓存的处理逻辑比较细化,组件的缓存统一由缓存管理核心处理,缓存核心分别调用一级缓存和二级缓存处理对象缓存。缓存处理的步骤如下:

1.判断是否开启了二级缓存,如果未开启,跳过。

2.如果开启了二级缓存,检查是否存在二级缓存,如果不存在,则判断是否对实体开启表缓存,如果开启,则开启后台线程扫描表,存储表数据为二级缓存。

3.判断是否存在一级缓存,如果存在,直接返回一级缓存的结果集。

4.如果一级缓存不存在,则执行查询命令,并写入一级缓存。

当二级缓存存在时:

1.拿出二级缓存并对二级缓存执行增删改查操作,并执行对应的增删改操作持久化过程。

2.后续所有查询优先从二级缓存中获取。

如果二级缓存开启状态,执行增删改命令的同时,会同步维护持久化数据和二级缓存数据。

备注:

二级缓存是针对某表进行的策略,不是针对所有数据库表的,如果数据库表数量太大,则不建议对该表开启二级缓存,以免耗费大量的内存资源。

【SevenTiny.Bantina.Bankinate ORM框架的使用】

Nuget包源搜索 SevenTiny.Bantina.Bankinate 安装

 新建一个数据库上下文类(对应数据库名称,类似EntityFramework的上下文类)

如果和库名不一致,则使用DataBase标签进行特殊映射。并在上下文类传递链接字符串和一级缓存和二级缓存的开启配置(默认都关闭)。

这里测试使用SQLServer数据库,因此继承了SQLServerDbContext,如果是其他数据库,则继承对应的数据库。

根据数据库表创建实体类(实体类可以使用代码生成器自动生成,生成器迭代升级中,有需求可以联系博主)。

这里提供了一个Student类(表),并使用 TableCaching 标签指定了该表二级缓存的开启(重载可以配置该表二级缓存时间)。

Id为主键,并且是自增列。

Api列表:

SevenTiny.Bantina.Bankinate ORM框架提供了一系列标准的非标准的数据查询api,api基于Lambda Expression写法,以便习惯了.Net平台Linq的人群很快上手,无学习成本。

复制代码
 1 /*********************************************************
 2  * CopyRight: 7TINY CODE BUILDER. 
 3  * Version: 5.0.0
 4  * Author: 7tiny
 5  * Address: Earth
 6  * Create: 2018-04-19 23:58:08
 7  * Modify: 2018-04-19 23:58:08
 8  * E-mail: dong@7tiny.com | sevenTiny@foxmail.com 
 9  * GitHub: https://github.com/sevenTiny 
10  * Personal web site: http://www.7tiny.com 
11  * Technical WebSit: http://www.cnblogs.com/7tiny/ 
12  * Description: 
13  * Thx , Best Regards ~
14  *********************************************************/
15 using System;
16 using System.Collections.Generic;
17 using System.Data;
18 using System.Linq.Expressions;
19 
20 namespace SevenTiny.Bantina.Bankinate
21 {
22     /// <summary>
23     /// 通用的Api接口,具备基础的操作,缓存
24     /// </summary>
25     public interface IDbContext : IDisposable, IBaseOerate, ICacheable
26     {
27     }
28 
29     /// <summary>
30     /// 基础操作Api
31     /// </summary>
32     public interface IBaseOerate
33     {
34         void Add<TEntity>(TEntity entity) where TEntity : class;
35         void AddAsync<TEntity>(TEntity entity) where TEntity : class;
36         void Add<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
37         void AddAsync<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
38 
39         void Update<TEntity>(Expression<Func<TEntity, bool>> filter, TEntity entity) where TEntity : class;
40         void UpdateAsync<TEntity>(Expression<Func<TEntity, bool>> filter, TEntity entity) where TEntity : class;
41 
42         void Delete<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
43         void DeleteAsync<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
44 
45         bool QueryExist<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
46         int QueryCount<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
47         TEntity QueryOne<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
48         List<TEntity> QueryList<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class;
49     }
50 
51     /// <summary>
52     /// 执行sql语句扩展Api
53     /// </summary>
54     public interface IExecuteSqlOperate
55     {
56         void ExecuteSql(string sqlStatement, IDictionary<string, object> parms = null);
57         void ExecuteSqlAsync(string sqlStatement, IDictionary<string, object> parms = null);
58         DataSet ExecuteQueryDataSetSql(string sqlStatement, IDictionary<string, object> parms = null);
59         object ExecuteQueryOneDataSql(string sqlStatement, IDictionary<string, object> parms = null);
60         TEntity ExecuteQueryOneSql<TEntity>(string sqlStatement, IDictionary<string, object> parms = null) where TEntity : class;
61         List<TEntity> ExecuteQueryListSql<TEntity>(string sqlStatement, IDictionary<string, object> parms = null) where TEntity : class;
62     }
63 
64     /// <summary>
65     /// 分页查询扩展Api
66     /// </summary>
67     public interface IQueryPagingOperate
68     {
69         List<TEntity> QueryListPaging<TEntity>(int pageIndex, int pageSize, Expression<Func<TEntity, object>> orderBy, Expression<Func<TEntity, bool>> filter, bool isDESC = false) where TEntity : class;
70         List<TEntity> QueryListPaging<TEntity>(int pageIndex, int pageSize, Expression<Func<TEntity, object>> orderBy, Expression<Func<TEntity, bool>> filter, out int count, bool isDESC = false) where TEntity : class;
71     }
72 
73     /// <summary>
74     /// 缓存接口,实现该接口的类必须具备ORM缓存
75     /// </summary>
76     public interface ICacheable
77     {
78     }
79 }
复制代码

查询全部(可以根据使用场景组装lambda表达式):

新增一条数据:

修改数据:

删除数据:

【框架缓存性能测试】

缓存性能测试的单元测试代码:

 一级二级缓存测试代码

  不带缓存的查询:

 执行查询100次耗时:6576.8009 ms

  一级缓存开启,二级缓存未开启:

执行查询10000次耗时:1598.2349 ms

  一级缓存和二级缓存同时开启:

执行查询10000次耗时:5846.0249

实际上,二级缓存开启以后,最初的查询会走一级缓存。待二级缓存对表扫描结束以后,后续查询将维护二级缓存数据,不再访问数据库表。

【系统展望】

1.查询api对特定列查询列的支持(性能提升)

2.对一对多关系的主外键查询支持

3.更多种类数据库的支持

4.打点日志的支持

【总结】

通过本文的一系列分析,不知各位看官对ORM框架的设计思路有没有一个整体的认识。如果在分析结束还没有充分理解设计思路,那么简单粗暴直接上GitHub克隆源码看呗~

项目基于.NetStandard 2.0构建,因此支持.NetCore2.0以上以及.NetFramework4.6.1以上。对更低版本不兼容。

虽然原理分析比较冗长,但是代码结构还是非常清晰的,有任何建议,还望不吝赐教,对代码质量的指教非常期待 ^_^

附源码地址: https://github.com/sevenTiny/SevenTiny.Bantina.Bankinate

Docker本地镜像管理命令_Radioman-lhq的博客-CSDN博客

mikel阅读(685)

来源: Docker本地镜像管理命令_Radioman-lhq的博客-CSDN博客

一、Docker镜像操作——列出镜像

语法:docker images [OPTIONS] [REPOSITORY[:TAG]]
参数说明:
OPTIONS说明:
-a :列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);
--digests :显示镜像的摘要信息;
-f :显示满足条件的镜像;
--format :指定返回值的模板文件;
--no-trunc :显示完整的镜像信息;
-q :只显示镜像ID。
示例:
docker images
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

二、Docker镜像操作——查看镜像元数据

语法:docker inspect [OPTIONS] NAME|ID [NAME|ID...]
参数说明:
OPTIONS说明:
-f :指定返回值的模板文件。
-s :显示总的文件大小。
--type :为指定类型返回JSON。
示例:
docker inspect centos:latest
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

三、Docker镜像操作——删除镜像

语法:docker rmi [OPTIONS] IMAGE [IMAGE...]
参数说明:
OPTIONS说明:
-f :强制删除;
--no-prune :不移除该镜像的过程镜像,默认移除;
示例:
docker rmi -f runoob/ubuntu:v4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

四、Docker镜像操作——标记本地镜像

语法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
示例:
将镜像ubuntu:15.10标记为 runoob/ubuntu:v3 镜像。
docker tag ubuntu:15.10 runoob/ubuntu:v3
  • 1
  • 2
  • 3
  • 4

五、Docker镜像操作——创建镜像

语法:docker build [OPTIONS] PATH | URL | -
参数说明:
OPTIONS说明:
--build-arg=[] :设置镜像创建时的变量;
--cpu-shares :设置 cpu 使用权重;
--cpu-period :限制 CPU CFS周期;
--cpu-quota :限制 CPU CFS配额;
--cpuset-cpus :指定使用的CPU id;
--cpuset-mems :指定使用的内存 id;
--disable-content-trust :忽略校验,默认开启;
-f :指定要使用的Dockerfile路径;
--force-rm :设置镜像过程中删除中间容器;
--isolation :使用容器隔离技术;
--label=[] :设置镜像使用的元数据;
-m :设置内存最大值;
--memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;
--no-cache :创建镜像的过程不使用缓存;
--pull :尝试去更新镜像的新版本;
--quiet, -q :安静模式,成功后只输出镜像 ID;
--rm :设置镜像成功后删除中间容器;
--shm-size :设置/dev/shm的大小,默认值是64M;
--ulimit :Ulimit配置。
--tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
--network: 默认 default。在构建期间设置RUN指令的网络模式
示例:
1.使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1。
docker build -t runoob/ubuntu:v1 . 
2.使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像。
docker build github.com/creack/docker-firefox
3.也可以通过 -f Dockerfile 文件的位置:
$ docker build -f /path/to/a/Dockerfile .
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

六、Docker镜像操作——查看指定镜像的创建历史

语法:docker history [OPTIONS] IMAGE
参数说明:
OPTIONS说明:
-H :以可读的格式打印镜像大小和日期,默认为true;
--no-trunc :显示完整的提交记录;
-q :仅列出提交记录ID。
示例:
查看本地镜像runoob/ubuntu:v3的创建历史。
root@runoob:~# docker history runoob/ubuntu:v3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

七、Docker镜像操作——将指定镜像保存成 tar 归档文件

语法:docker save [OPTIONS] IMAGE [IMAGE...]
参数说明:
OPTIONS说明:
-o :输出到的文件。
示例:
将镜像runoob/ubuntu:v3 生成my_ubuntu_v3.tar文档
runoob@runoob:~$ docker save -o my_ubuntu_v3.tar runoob/ubuntu:v3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

八、Docker镜像操作——从归档文件中创建镜像。

语法:docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
OPTIONS说明:
-c :应用docker 指令创建镜像;
-m :提交时的说明文字;
示例:
从镜像归档文件my_ubuntu_v3.tar创建镜像,命名为runoob/ubuntu:v4
runoob@runoob:~$ docker import  my_ubuntu_v3.tar runoob/ubuntu:v4 

Docker 本地导入镜像/保存镜像/载入镜像/删除镜像 - Ruthless - 博客园

mikel阅读(652)

来源: Docker 本地导入镜像/保存镜像/载入镜像/删除镜像 – Ruthless – 博客园

1、Docker导入本地镜像

有时候我们自己在本地或者其它小伙伴电脑上拷贝了一份镜像,有了这个镜像之后,我们可以把本地的镜像导入,使用docker import 命令。

例如这里下载了一个 alibaba-rocketmq-3.2.6.tar.gz 镜像文件,使用下列命令导入:

复制代码
[root@rocketmq-nameserver4 dev]# cat alibaba-rocketmq-3.2.6.tar.gz | docker import - rocketmq:3.2.6(镜像名自己定义)
[root@rocketmq-nameserver4 dev]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
rocketmq                     3.2.6               53925d1cf9f0        23 seconds ago      14MB
my/python                    v1                  36b6e288656c        2 days ago          281MB
my/centos_width_python       v1.0.1              36b6e288656c        2 days ago          281MB
my/sinatra                   v2                  8ba1d6a3ce4e        2 days ago          453MB
hello-world                  latest              725dcfab7d63        4 months ago        1.84kB
复制代码

可以看到导入完成后,docker为我们生成了一个镜像ID,使用docker images也可以看到我们刚刚从本地导入的镜像。

注意镜像文件必须是tar.gz类型的文件。

[root@rocketmq-nameserver4 dev]# docker run -it rocketmq:3.2.6 /bin/bash ##启动导入本地镜像,会报如下异常
docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused “exec: \”/bin/bash\”: stat /bin/bash: no such file or directory”.

解决方案: 暂时无解,有知道的兄台请在下面留言,在此先谢了。

2、保存镜像
我们的镜像做好之后,我们要保存起来,以供备份使用,该怎么做?使用docker save命令,保存镜像到本地。

[root@rocketmq-nameserver4 dev]# docker save -o rocketmq.tar rocketmq ##-o:指定保存的镜像的名字;rocketmq.tar:保存到本地的镜像名称;rocketmq:镜像名字,通过"docker images"查看
[root@rocketmq-nameserver4 dev]# ll


rocketmq.tar为刚保存的镜像

3、载入镜像
我们有了本地的镜像文件,在需要的时候可以使用docker load将本地保存的镜像再次导入docker中。
docker load –input rocketmq.tar 或 docker load < rocketmq.tar

4、删除镜像
有些镜像过时了,我们需要删除。使用如下的命令:docker rmi -f image_id ##-f:表示强制删除镜像;image_id:镜像id

如何解决 image has dependent child images 错误 - 简书

mikel阅读(1008)

来源: 如何解决 image has dependent child images 错误 – 简书

问题

在 Docker 中删除 image 时有时会遇到类似

Error response from daemon: conflict: unable to delete 6ec9a5a0fc9f (cannot be forced) - image has dependent child images

这样的错误,原因是有另外的 image FROM 了这个 image,可以使用下面的命令列出所有在指定 image 之后创建的 image 的父 image

docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=xxxxxx)

其中 xxxxxx 是报错 image 的 id,在文章开头的例子中就是 6ec9a5a0fc9f。从列表中查找到之后就可以核对并删除这些 image。
示例

1、查看我的镜像列表。

~ docker images -a
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
<none>                           <none>              b707620d204c        8 hours ago         179MB
tingfeng/dockerfile_build_demo   latest              6586e000b464        8 hours ago         179MB
<none>                           <none>              54f305491871        10 hours ago        122MB
<none>                           <none>              97ea9f11c94f        10 hours ago        81.2MB
tingfeng/commit_test             latest              58fac7144497        31 hours ago        234MB
tomcat                           latest              61205f6444f9        2 weeks ago         467MB
ubuntu                           latest              113a43faa138        2 weeks ago         81.2MB
nginx                            latest              cd5239a0906a        2 weeks ago         109MB
hello-world                      latest              e38bc07ac18e        2 months ago        1.85kB

2、删除none的镜像(删不掉)

~ docker rmi b707620d204c
Error response from daemon: conflict: unable to delete b707620d204c (cannot be forced) - image has dependent child images
➜  ~ docker rmi 97ea9f11c94f
Error response from daemon: conflict: unable to delete 97ea9f11c94f (cannot be forced) - image has dependent child images
➜  ~ docker rmi -f 54f305491871
Error response from daemon: conflict: unable to delete 54f305491871 (cannot be forced) - image has dependent child images

3、查找出所有在指定 image 之后创建的 image 的父 image,本示例看得出是同一个依赖镜像 tingfeng/dockerfile_build_demo

~ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=b707620d204c)
[tingfeng/dockerfile_build_demo:latest] sha256:6586e000b464654f420b0aa9cf6c3c61cc29edfbbe7cc5cb5d6e0fe037efaf87 sha256:b707620d204ca475f13394b14614e1f2fde986931c925cd8cc8e8bb3de7debe3

➜  ~ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=54f305491871)
[tingfeng/dockerfile_build_demo:latest] sha256:6586e000b464654f420b0aa9cf6c3c61cc29edfbbe7cc5cb5d6e0fe037efaf87 sha256:b707620d204ca475f13394b14614e1f2fde986931c925cd8cc8e8bb3de7debe3

➜  ~ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=97ea9f11c94f)
[tingfeng/dockerfile_build_demo:latest] sha256:6586e000b464654f420b0aa9cf6c3c61cc29edfbbe7cc5cb5d6e0fe037efaf87 sha256:b707620d204ca475f13394b14614e1f2fde986931c925cd8cc8e8bb3de7debe3

4、删除关联的依赖镜像,关联的none镜像也会被删除

➜  ~ docker rmi 6586e000b464
Untagged: tingfeng/dockerfile_build_demo:latest
Deleted: sha256:6586e000b464654f420b0aa9cf6c3c61cc29edfbbe7cc5cb5d6e0fe037efaf87
Deleted: sha256:b707620d204ca475f13394b14614e1f2fde986931c925cd8cc8e8bb3de7debe3
Deleted: sha256:c241c7f781a3176d395b38a7e96eb2e0b7e031e622ad9d14eaa9098de1a063d1
Deleted: sha256:54f305491871f5609295cd6c59f304401761c7fa96bdda8a74968358c54ba402
Deleted: sha256:be4d80c4407bde1fe700983ad805a0237a148d7af04e8bf2197fc040ae654acb
Deleted: sha256:97ea9f11c94fb8f76288361e37f884d639c6ea918bc6142feee2409e7ff43791

5、再次查看镜像列表

➜  ~ docker images -a
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
tingfeng/commit_test   latest              58fac7144497        31 hours ago        234MB
tomcat                 latest              61205f6444f9        2 weeks ago         467MB
ubuntu                 latest              113a43faa138        2 weeks ago         81.2MB
nginx                  latest              cd5239a0906a        2 weeks ago         109MB
hello-world            latest              e38bc07ac18e        2 months ago        1.85kB

其他操作

# 停止所有容器~ docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker stop

# 删除所有容器~ docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker rm

# 删除所有none容器~ docker images|grep none|awk '{print $3 }'|xargs docker rmi

相关阅读

删除docker-register的镜像& none无效镜像讲解:https://segmentfault.com/a/1190000011153919

作者:Mr_Alfred
链接:https://www.jianshu.com/p/3c2e0a89d618
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

docker删除报错Error response from daemon: conflict: unable to deleteXXXXX解决方案_xiangxianghehe的博客-CSDN博客

mikel阅读(1473)

来源: docker删除报错Error response from daemon: conflict: unable to deleteXXXXX解决方案_xiangxianghehe的博客-CSDN博客

docker删除镜像报错,docker images后输出如下:

REPOSITORY                             TAG                        IMAGE ID            CREATED             SIZE
nvidia/cuda                            9.0-base                   74f5aea45cf6        6 weeks ago         134MB
paddlepaddle/paddle                    1.1.0-gpu-cuda8.0-cudnn7   b3cd25f64a2a        8 weeks ago         2.76GB
hub.baidubce.com/paddlepaddle/paddle   1.1.0-gpu-cuda8.0-cudnn7   b3cd25f64a2a        8 weeks ago         2.76GB
paddlepaddle/paddle                    1.1.0-gpu-cuda9.0-cudnn7   0df4fe3ecea3        8 weeks ago         2.89GB
hub.baidubce.com/paddlepaddle/paddle   1.1.0-gpu-cuda9.0-cudnn7   0df4fe3ecea3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第一个镜像直接docker rmi 74f5aea45cf6就删除成功了,然而后面两个镜像都是成对出现,直接docker rmi删除失败,报错信息如下:

Error response from daemon:
conflict: unable to delete b3cd25f64a2a (must be forced) - image 
is referenced in multiple repositories
  • 1
  • 2
  • 3

解决方案:

首先docker rmi时指定名称,而非image id,然后再执行docker rmi -f image idj即可:

docker rmi paddlepaddle/paddle:1.1.0-gpu-cuda8.0-cudnn7
docker rmi -f b3cd25f64a2a

Git error: hint: Updates were rejected because the remote contains work that you do hint: not have l_shizhenweiszw的博客-CSDN博客

mikel阅读(1596)

来源: Git error: hint: Updates were rejected because the remote contains work that you do hint: not have l_shizhenweiszw的博客-CSDN博客

hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., ‘git pull …’) before pushing again.
hint: See the ‘Note about fast-forwards’ in ‘git push –help’ for details.
在这里插入图片描述
解决办法:

$ git pull origin master
$ git push origin master

Please enter a commit message to explain why this merge is necessary.

请输入提交消息来解释为什么这种合并是必要的
在这里插入图片描述
git 在pull或者合并分支的时候有时会遇到这个界面。可以不管(直接下面3,4步),如果要输入解释的话就需要:

1.按键盘字母 i 进入insert模式

2.修改最上面那行黄色合并信息,可以不修改

3.按键盘左上角”Esc”

4.输入”:wq”,注意是冒号+wq,按回车键即可

Git Vim编辑器输入内容、保存和退出操作-蚂蚁部落

mikel阅读(862)

来源: Git Vim编辑器输入内容、保存和退出操作-蚂蚁部落

Git默认的编辑器是Vim,在很多情境下会遇到它,例如commit提交没有提供-m指令。

代码如下:

[Shell] 纯文本查看 复制代码
1
$ git commit -m "c1"

如果提供-m指令,直接在后面写上此次提交的说明信息,例如”c1″。

如果不提供-m指令,默认将会弹出Vim编辑器,截图如下:

a:3:{s:3:\"pic\";s:43:\"portal/201807/10/150342lckbb59bwfztfwut.jpg\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

问题出现了,很多用户不知道怎么输入,即便输入也不知道怎么保存,即便保存,也不知道怎么退出。

此编辑器和平时所用编辑器差距很大,Vim编辑器命令很多,下面介绍一下简单操作,以完成基本的Git操作。

Vim主要有如下两种模式:

(1).Normal 模式。

(2).Insert 模式。

Normal 模式:

(1).点击ESC键或者Ctrl + [组合键进入此模式。

(2).又称作为命令模式。

(3).此模式下无法输入内容,但是可以赋值黏贴,保存或者退出。

(4).此模式下,按下:w表示保存,:q表示离开(如果未保存会有提示),:wq表示保存并离开。

Insert 模式:

(1).点击i、a 或 o 键可以进入此模式。

(2).i表示在光标当前位置插入,a表示在光标下一个位置插入,o表示在新一行插入。

(3).I表示在行首插入,A表示在行尾插入。

git文件上传超过100M解决方案_ZeS的博客-CSDN博客

mikel阅读(1847)

来源: git文件上传超过100M解决方案_ZeS的博客-CSDN博客

error: File: xxx 102.15 MB, exceeds 100.00 MB.

有一次我写好项目想将项目上传到gitee上的时候,出现了这个错误。其实就是其中有一个文件太大,超过了100M导致的。
网上看了很多帖子,踩了很多坑弄了一下午都没有解决,最后还是直接求助官网解决了。贴出来避免其他人也犯了类似的错误

解决方案

1. 查看哪个文件超过了100M

有可能错误直接爆出是哪个文件,也有可能只是爆出了该文件的代号。如果是代号需要先使用该语句查询具体是哪个文件
$ git rev-list --objects --all | grep xxx

2. 从缓存中删除

$ git filter-branch --tree-filter 'rm -f xxx' --tag-name-filter cat -- --all
这里的XXX替换成报错文件的具体路径(例如我这里的xxx是target/travel-0.0.1-SNAPSHOT.jar

3.再次进行push操作

git push origin master
成功!

Orm框架开发之NewExpression合并问题 - 张家华 - 博客园

mikel阅读(608)

来源: Orm框架开发之NewExpression合并问题 – 张家华 – 博客园

之前都是看别人写博客,自己没有写博客的习惯.在工作的过程中,总是会碰到许多的技术问题.有很多时候想记录下来,后面一直有许多的问题等着解决.总想着等系统完成了,再回头总结下.往往结果就把这事抛到脑后了.

总觉得不能一直这样哈.今天简单记一下吧.有表达不清楚的地方,多多包涵.

最近在研究.net orm框架.想开发一套更好用的Orm框架.碰到一个Expression合并的问题.别嫌轮子多.

一.需求情况描述

需要更新部分数据的时候,可能前端传回的只有部分字段的数据.而更新的时候,需要设置更新人,更新日期等.

举个栗子来说:

现在有一个预约信息表

前端需要修改数据内容如下,我们暂且叫表达A

复制代码
var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
    a.Id,
    a.PatientName,
    a.PatientNamePy,
    a.IdentityCardNumber,
    a.Birthday,
    a.PatientAge,
    a.PatientSex,
    a.PatientPhone,
    a.Address
});
复制代码

 

而写入数据库的时候需要添加更新人,更新时间.LastUpdateUserId和UpdateTime.

于是我们便又多了一个lambda表达式,我们叫它表达式B

复制代码
var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
    a.Id,
    a.PatientName,
    a.PatientNamePy,
    a.IdentityCardNumber,
    a.Birthday,
    a.PatientAge,
    a.PatientSex,
    a.PatientPhone,
    a.Address,
    a.LastUpdateUserId,
    a.UpdateTime
});
复制代码

这里说下ExpressionHelper.CreateExpression<T>方法,只是一个为了缩减代码长度而写的方法.输入的lambda表达式原样返回了.

外面不用写好长的类型了.Expression这个类型平时不用.写外面看着眼晕.  Expression<Func<AppointmentDto, object>> exp1 = a => new {a.Id,a.PatientName}; 

复制代码
/// <summary>
/// 转换Expr
/// 在外面调用时可以使用var以减少代码长度
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public static Expression<Func<T, object>> CreateExpression<T>(Expression<Func<T, object>> expr)
{
    return expr;
}
复制代码

所以此处,使用var可以看起来更整洁.但并不推荐在正常情况下使用var.

个人觉得使用var让代码可维护性降低.读起来真的是头疼.之前在维护一个比较大的系统的时候,公司的主要项目,缺少项目文档,代码里面也基本上没啥注释.而且又清一色的var,每个方法返回的是啥类型?你得去方法那边看去.看着真是恼火,又不得不去一点一点的改.都改成相应的类型后,看着就清爽多了.看一眼,流程就基本上能明白大概.所以,var在C#这种强类型语言里,能不用就别用了.

上面就当是发牢骚了.我们回到正题.

我们看到表达式B比表达式A只多了两个字段.大多数代码都是重复的.而且,两个lambda表达式严重的加长了代码行数.几个这样的表达式下来,这个类就到了几百行了.

对于喜欢简洁,简单的我来说,类一大了我就头疼.那咋整?要是有办法将这两个表达式简化处理一下就好了.将表达式A加上一个短的表达式,来实现表达式B呢.

比如实现 var exprB = exprA.Add(a => new { a.PatientPhone }); 

So,开始捯饬…

二.解决方法

因为这个合并表达式的方法是在个人系统内部使用满足我定制的Orm的类名称需求

所以定义了一个新的Expression表达式类型NewObjectExpression来处理

复制代码
  1     /// <summary>
  2     /// New Object Expression
  3     /// 合并NewExpression使用.
  4     /// </summary>
  5     public class NewObjectExpression : Expression, IArgumentProvider
  6     {
  7         private IList<Expression> arguments;
  8 
  9         /// <summary>
 10         /// 构造方法
 11         /// </summary>
 12         /// <param name="constructor"></param>
 13         /// <param name="arguments"></param>
 14         /// <param name="members"></param>
 15         internal NewObjectExpression(ConstructorInfo constructor, IList<Expression> arguments, List<MemberInfo> members)
 16         {
 17             this.Constructor = constructor;
 18             this.arguments = arguments;
 19             this.Members = members;
 20 
 21             if (members != null)
 22             {
 23                 List<string> nameList = members.Select(member => member.Name).ToList();
 24                 for (int i = 0; i < nameList.Count; i++)
 25                 {
 26                     if (!string.IsNullOrEmpty(ExpressionString))
 27                     {
 28                         ExpressionString += "," + nameList[i];
 29                     }
 30                     else
 31                     {
 32                         ExpressionString = nameList[i];
 33                     }
 34                 }
 35             }
 36         }
 37 
 38         /// <summary>
 39         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
 40         /// </summary>
 41         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
 42         public override Type Type
 43         {
 44             get { return Constructor.DeclaringType; }
 45         }
 46 
 47         /// <summary>
 48         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
 49         /// </summary>
 50         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
 51         public sealed override ExpressionType NodeType
 52         {
 53             get { return ExpressionType.New; }
 54         }
 55 
 56         /// <summary>
 57         /// Gets the called constructor.
 58         /// </summary>
 59         public ConstructorInfo Constructor { get; }
 60 
 61         /// <summary>
 62         /// Gets the arguments to the constructor.
 63         /// </summary>
 64         public ReadOnlyCollection<Expression> Arguments
 65         {
 66             get { return (ReadOnlyCollection<Expression>)arguments; }
 67         }
 68 
 69         Expression IArgumentProvider.GetArgument(int index)
 70         {
 71             return arguments[index];
 72         }
 73 
 74         int IArgumentProvider.ArgumentCount
 75         {
 76             get
 77             {
 78                 return arguments.Count;
 79             }
 80         }
 81         
 82         /// <summary>
 83         /// ExpressionString
 84         /// </summary>
 85         public string ExpressionString { get; private set; } = "";
 86 
 87         public ConstructorInfo Constructor1 => Constructor;
 88 
 89         public List<MemberInfo> Members { get; set; }
 90 
 91         /// <summary>
 92         /// 更新members
 93         /// </summary>
 94         /// <param name="arguments"></param>
 95         /// <param name="members"></param>
 96         /// <returns></returns>
 97         public NewObjectExpression Update(IList<Expression> arguments, List<MemberInfo> members)
 98         {
 99             if (arguments != null)
100             {
101                 this.arguments = arguments;
102             }
103             if (Members != null)
104             {
105                 this.Members = members;
106                 ExpressionString = "";
107                 List<string> nameList = members.Select(member => member.Name).ToList();
108                 for (int i = 0; i < nameList.Count; i++)
109                 {
110                     if (!string.IsNullOrEmpty(ExpressionString))
111                     {
112                         ExpressionString += "," + nameList[i];
113                     }
114                     else
115                     {
116                         ExpressionString = nameList[i];
117                     }
118                 }                
119             }
120             return this;
121         }
122     }
复制代码

待处理的属性都放到了Members里面.后面解析使用的也是Members.其它方法Copy自NewExpression的源码,可以删了不用.

下面我们来扩展Expression<Func<T, object>>,让Expression<Func<T, object>>拥有Add和Remove属性的方法.

直接上代码,看前两个方法.后面两个方法是扩展Expression<Func<T, bool>>表达式的And和Or.等有回头有空再介绍.

复制代码
  1     /// <summary>
  2     /// Expression 扩展
  3     /// </summary>
  4     public static class ExpressionExpand
  5     {
  6         /// <summary>
  7         /// Expression And 
  8         /// NewExpression 合并
  9         /// </summary>
 10         /// <param name="expr"></param>
 11         /// <returns></returns>
 12         public static Expression<Func<T, object>> Add<T>(this Expression<Func<T, object>> expr, Expression<Func<T, object>> expandExpr)
 13         {
 14             Expression<Func<T, object>> result = null;
 15             ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
 16             List<MemberInfo> memberInfoList = new List<MemberInfo>();
 17             #region 处理原expr
 18             if (expr.Body is NewExpression)
 19             {   // t=>new{t.Id,t.Name}
 20                 NewExpression newExp = expr.Body as NewExpression;
 21                 if (newExp.Members != null)
 22                 {
 23                     memberInfoList = newExp.Members.ToList();
 24                 }
 25             }
 26             else if (expr.Body is NewObjectExpression)
 27             {
 28                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
 29                 if (newExp.Members != null)
 30                 {
 31                     memberInfoList = newExp.Members.ToList();
 32                 }
 33             }
 34             else if (expr.Body is UnaryExpression)
 35             {   //t=>t.Id
 36                 UnaryExpression unaryExpression = expr.Body as UnaryExpression;
 37                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
 38                 memberInfoList.Add(memberExp.Member);
 39             }
 40             #endregion
 41 
 42             #region 处理扩展expr
 43             if (expandExpr.Body is NewExpression)
 44             {   // t=>new{t.Id,t.Name}
 45                 NewExpression newExp = expandExpr.Body as NewExpression;
 46                 for (int i = 0; i < newExp.Members.Count; i++)
 47                 {
 48                     MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
 49                     if (!memberInfoList.Any(member => member.Name == newExp.Members[i].Name))
 50                     {
 51                         memberInfoList.Add(newExp.Members[i]);
 52                     }
 53                 }
 54             }
 55             else if (expr.Body is NewObjectExpression)
 56             {
 57                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
 58                 if (newExp.Members != null && newExp.Members.Count > 0)
 59                 {
 60                     for (int i = 0; i < newExp.Members.Count; i++)
 61                     {
 62                         MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
 63                         if (!memberInfoList.Any(member => member.Name == newExp.Members[i].Name))
 64                         {
 65                             memberInfoList.Add(newExp.Members[i]);
 66                         }
 67                     }
 68                 }
 69             }
 70             else if (expandExpr.Body is UnaryExpression)
 71             {   //t=>t.Id
 72                 UnaryExpression unaryExpression = expandExpr.Body as UnaryExpression;
 73                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
 74                 if (!memberInfoList.Any(exp => exp.Name == memberExp.Member.Name))
 75                 {
 76                     memberInfoList.Add(memberExp.Member);
 77                 }
 78             }
 79             #endregion
 80             NewObjectExpression newObjExpression = new NewObjectExpression(typeof(object).GetConstructors()[0], null, memberInfoList);
 81             result = Expression.Lambda<Func<T, object>>(newObjExpression, parameter);
 82             return result;
 83         }
 84 
 85         /// <summary>
 86         /// Expression Remove 
 87         /// NewExpression 合并
 88         /// </summary>
 89         /// <param name="expr"></param>
 90         /// <returns></returns>
 91         public static Expression<Func<T, object>> Remove<T>(this Expression<Func<T, object>> expr, Expression<Func<T, object>> expandExpr)
 92         {
 93             Expression<Func<T, object>> result = null;
 94             ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
 95             List<MemberInfo> memberInfoList = new List<MemberInfo>();
 96             List<MemberInfo> removeMemberInfoList = new List<MemberInfo>();
 97             #region 处理原expr
 98             if (expr.Body is NewExpression)
 99             {   // t=>new{t.Id,t.Name}
100                 NewExpression newExp = expr.Body as NewExpression;
101                 if (newExp.Members != null)
102                 {
103                     memberInfoList = newExp.Members.ToList();
104                 }
105             }
106             else if (expr.Body is NewObjectExpression)
107             {
108                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
109                 if (newExp.Members != null)
110                 {
111                     memberInfoList = newExp.Members.ToList();
112                 }
113             }
114             else if (expr.Body is UnaryExpression)
115             {   //t=>t.Id
116                 UnaryExpression unaryExpression = expr.Body as UnaryExpression;
117                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
118                 memberInfoList.Add(memberExp.Member);
119             }
120             #endregion
121 
122             #region 处理扩展expr
123             if (expandExpr.Body is NewExpression)
124             {   // t=>new{t.Id,t.Name}
125                 NewExpression newExp = expandExpr.Body as NewExpression;
126                 for (int i = 0; i < newExp.Members.Count; i++)
127                 {
128                     MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
129                     if (!removeMemberInfoList.Any(member => member.Name == newExp.Members[i].Name))
130                     {
131                         removeMemberInfoList.Add(newExp.Members[i]);
132                     }
133                 }
134             }
135             else if (expr.Body is NewObjectExpression)
136             {
137                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
138                 if (newExp.Members != null && newExp.Members.Count > 0)
139                 {
140                     for (int i = 0; i < newExp.Members.Count; i++)
141                     {
142                         MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
143                         if (!removeMemberInfoList.Any(member => member.Name == newExp.Members[i].Name))
144                         {
145                             removeMemberInfoList.Add(newExp.Members[i]);
146                         }
147                     }
148                 }
149             }
150             else if (expandExpr.Body is UnaryExpression)
151             {   //t=>t.Id
152                 UnaryExpression unaryExpression = expandExpr.Body as UnaryExpression;
153                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
154                 if (!memberInfoList.Any(exp => exp.Name == memberExp.Member.Name))
155                 {
156                     removeMemberInfoList.Add(memberExp.Member);
157                 }
158             }
159             #endregion
160 
161             for (int i = memberInfoList.Count - 1; i >= 0; i--)
162             {
163                 if (removeMemberInfoList.Any(member => member.Name == memberInfoList[i].Name))
164                 {
165                     memberInfoList.Remove(memberInfoList[i]);
166                 }
167             }
168             if (memberInfoList.Count <= 0)
169             {
170                 throw new System.Exception("Expression Remove Error.All Properties are removed.");
171             }
172             NewObjectExpression newObjExpression = new NewObjectExpression(typeof(object).GetConstructors()[0], null, memberInfoList);
173             result = Expression.Lambda<Func<T, object>>(newObjExpression, parameter);
174             return result;
175         }
176 
177         /// <summary>
178         /// Expression And
179         /// </summary>
180         /// <param name="expr"></param>
181         /// <returns></returns>
182         public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> expandExpr)
183         {
184             Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(Expression.And(expandExpr.Body, expr.Body), expr.Parameters);
185             return result;
186         }
187 
188         /// <summary>
189         /// Expression And
190         /// </summary>
191         /// <param name="expr"></param>
192         /// <returns></returns>
193         public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> expandExpr)
194         {
195             Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(Expression.Or(expandExpr.Body, expr.Body), expr.Parameters);
196             return result;
197         }
198     }
复制代码

Add方法可处理 NewExpression 类似 t=>new{t.Id,t.Name} , UnaryExpression 类似t=>t.Id,以及我们自定义的NewObjectExpression类型

所以我们在更新数据的时候就可以这么写了:

Dbc.Db.Update(dto, exp.Add(a => a.LastUpdateUserId));
Dbc.Db.Update(dto, exp.Add(a => new { a.LastUpdateUserId, a.UpdateTime }));

在Orm框架内部,解析NewObjectExpression时,解析方法如下

复制代码
 1         /// <summary>
 2         /// 通过Lambed Expression获取属性名称
 3         /// </summary>
 4         /// <param name="expr">查询表达式</param>
 5         /// <returns></returns>
 6         public static List<string> GetPiList<T>(Expression<Func<T, object>> expr)
 7         {
 8             List<string> result = new List<string>();
 9             if (expr.Body is NewExpression)
10             {   // t=>new{t.Id,t.Name}
11                 NewExpression nexp = expr.Body as NewExpression;
12                 if (nexp.Members != null)
13                 {
14                     result = nexp.Members.Select(member => member.Name).ToList();
15                 }
16             }
17             else if (expr.Body is NewObjectExpression)
18             {   // t=>new{t.Id,t.Name}
19                 NewObjectExpression nexp = expr.Body as NewObjectExpression;
20                 if (nexp.Members != null)
21                 {
22                     result = nexp.Members.Select(member => member.Name).ToList();
23                 }
24             }
25             else if (expr.Body is UnaryExpression)
26             {   //t=>t.Id
27                 UnaryExpression uexp = expr.Body as UnaryExpression;
28                 MemberExpression mexp = uexp.Operand as MemberExpression;
29                 result.Add(mexp.Member.Name);
30             }
31             else
32             {
33                 throw new System.Exception("不支持的Select lambda写法");
34             }
35             return result;
36         }
复制代码

至此,就完成了Expression<Func<T, object>>Add和Remove属性的扩展,Orm可以让代码更简洁.

三.后记

其实在使用新的类NewObjectExpression来解决之前,尝试过其它的许多方式,因为使用.net的类型可以在其它的框架程序中借鉴引用.不必局限在个人框架内部.

NewExpression内部有一些校验,本身Expression<Func<T, object>>是一个匿名类.试过处理NewExpression,以及新建类继承自NewExpression等方式.都没成功.

要是大家有更好的方法欢迎留言告知.希望本文能对大家有所帮助.