今天用Linq给数据表批量添加数据时,发现速度确实比ADO.net慢了不少,后面调出DataContext.Log记录一看,发现是一行一个命令添加数据,那速度当然慢了了,差不多慢了20倍左右,Linq的本质就是通过映射类等把c#等.net语言解释为SQL语句,我按照这个思路自己把程序语言解释为SQL,听说可以使用System.Linq.Expression里面的方法解释成SQL语句,但是我看了网上的代码,看不太明白,我就按自己想法封装了一个Insert方法,速度接近ADO.net有不对的请指正。
第一步:从数据表映射类解释出表名,表列。
先建立一个数据表映射类:
1 [Table(Name = " Student " )]
2 public class Student
3 {
4 [Column(Name = " 序号 " , CanBeNull = false , IsPrimaryKey = true )]
5 public int ID { get ; set ; }
6 [Column(Name = " 名字 " , CanBeNull = false )]
7 public string Name { get ; set ; }
8 [Column(Name = " 年龄 " , CanBeNull = false )]
9 public int Age { get ; set ; }
10
11 public Student() { }
12
13 public Student( int id, string name, int age)
14 {
15 ID = id;
16 Name = name;
17 Age = age;
18 }
19
20 public override string ToString()
21 {
22 return ID.ToString() + " \t " + Name + " \t " + Age.ToString();
23 }
24 }
1、获取表名
1 public static class DataContextExtension
2 {
3 private static string GetTableName < TEntity > ( this DataContext context)
4 {
5 string tableName = "" ;
6 Attribute[] atb = Attribute.GetCustomAttributes( typeof (TEntity));
7 foreach (var item in atb)
8 {
9 if (item.GetType() == typeof (TableAttribute))
10 {
11 tableName = ((TableAttribute)item).Name;
12 }
13 }
14 return tableName;
15 }
16 }
2、获取列名及相关属性
1 public static Dictionary < PropertyInfo,ColumnAttribute > GetTableCol < TEntity > ( this DataContext context)
2 {
3 Dictionary < PropertyInfo,ColumnAttribute > col = new Dictionary < PropertyInfo,ColumnAttribute > ();
4
5 PropertyInfo[] m = typeof (TEntity).GetProperties();
6 foreach (var item in m)
7 {
8 Attribute[] pat = Attribute.GetCustomAttributes(item);
9 foreach (var item1 in pat)
10 {
11 if (item1.GetType() == typeof (ColumnAttribute))
12 {
13 col[item] = (ColumnAttribute)item1;
14 }
15 }
16 }
17 return col;
18 }
第二步、把数据解释并生成SQL Insert语句
1、创建Insert SQL语句
1 public static string CreateInsertCmd < TEntity > ( this DataContext context, IEnumerable < TEntity > collection, int TEntityLength = 50 )
2 {
3 StringBuilder cmd = new StringBuilder(collection.Count < TEntity > () * TEntityLength + 100 );
4 // 获取表名
5 string tableName = GetTableName < TEntity > (context);
6 // 获取表列
7 Dictionary < PropertyInfo,ColumnAttribute > col = GetTableCol < TEntity > (context);
8 string insert = " insert into " + tableName + " ( " ;
9 foreach (var item in col)
10 {
11 if ( ! item.Value.IsDbGenerated)
12 {
13 insert += " [ " + item.Value.Name + " ], " ;
14 }
15 }
16 cmd.Append(insert);
17 cmd.Remove(cmd.Length - 1 , 1 );
18 cmd.Append( " ) values " );
19 // 添加数据
20 foreach (var item in collection)
21 {
22 cmd.Append( " ( " );
23 foreach (var c in col)
24 {
25 if ( ! c.Value.IsDbGenerated)
26 {
27 if (c.Key.PropertyType == typeof ( string ))
28 {
29 cmd.Append( " ' " + c.Key.GetValue(item, null ).ToString() + " ', " );
30
31 }
32 else
33 {
34 cmd.Append(c.Key.GetValue(item, null ).ToString() + " , " );
35 }
36 }
37 }
38 cmd.Remove(cmd.Length - 1 , 1 );
39 cmd.Append( " ), " );
40
41 }
42 cmd.Remove(cmd.Length - 1 , 1 );
43 cmd.Append( " ; " );
44
45 return cmd.ToString();
46 }
2、当批量数据大于1000行时,需把Insert语句拆分为不大于1000行的多个Insert语句
1 public static string []CreateInsertCmds < TEntity > ( this DataContext context, IEnumerable < TEntity > collection, int TEntityLength = 50 )
2 {
3 int n = 998 ;
4 int cmdCount = collection.Count < TEntity > () / n;
5 string [] cmds = new string [cmdCount + 1 ];
6 List < TEntity > l = collection.ToList < TEntity > ();
7 int i;
8 for (i = 0 ; i < cmdCount ; i ++ )
9 {
10 cmds[i] = CreateInsertCmd < TEntity > (context,l.GetRange(i * n,n));
11 }
12 cmds[i] = CreateInsertCmd(context,l.GetRange(i * n,collection.Count < TEntity > () - i * n));
13 return cmds;
14 }
第三步,执行DataContext.ExecuteCommand
1 public static void InsertAll < TEntity > ( this DataContext context,IEnumerable < TEntity > collection)
2 {
3 string []cmds = CreateInsertCmds < TEntity > (context,collection);
4 foreach (var item in cmds)
5 {
6 context.ExecuteCommand(item);
7 }
8 }
第三步,完整代码及测试代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Linq.Mapping; using System.Data.Sql; using System.Reflection; #if DEBUG using System.Diagnostics; using NUnit.Framework; #endif namespace System.Data.Linq { public static class DataContextExtension { public static bool CreateTable(this DataContext context, Type type) { MetaTable metaTable = context.Mapping.GetTable(type); string typeName = "System.Data.Linq.SqlClient.SqlBuilder"; Type contextType = typeof(DataContext).Assembly.GetType(typeName); if (contextType == null) { return false; } BindingFlags bf = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod; object sql = contextType.InvokeMember("GetCreateTableCommand", bf, null, null, new[] { metaTable }); if (context.ExecuteCommand((string)sql, new object[] { }) <= 0) { return false; } return true; } public static bool CreateTable<TEntity>(this DataContext context) { return CreateTable(context, typeof(TEntity)); } public static bool DeleteTable(this DataContext context, Type type) { MetaTable metaTable = context.Mapping.GetTable(type); string cmdtext = "drop table "+metaTable.TableName; if (context.ExecuteCommand(cmdtext, new object[] { }) > 0) { return true; } else { return false; } } public static bool DeleteTable<TEntity>(this DataContext context) { return DeleteTable(context, typeof(TEntity)); } public static string[]CreateInsertCmds<TEntity>(this DataContext context, IEnumerable<TEntity> collection,int TEntityLength = 50) { int n = 998; int cmdCount = collection.Count<TEntity>() / n; string[] cmds = new string[cmdCount+1]; List<TEntity> l = collection.ToList<TEntity>(); int i; for (i = 0; i < cmdCount ; i++) { cmds[i] = CreateInsertCmd<TEntity>(context,l.GetRange(i*n,n)); } cmds[i] = CreateInsertCmd(context,l.GetRange(i*n,collection.Count<TEntity>() - i*n)); return cmds; } public static void InsertAll<TEntity>(this DataContext context,IEnumerable<TEntity>collection) { string []cmds = CreateInsertCmds<TEntity>(context,collection); foreach (var item in cmds) { context.ExecuteCommand(item); } } public static string CreateInsertCmd<TEntity>(this DataContext context, IEnumerable<TEntity> collection,int TEntityLength = 50) { StringBuilder cmd = new StringBuilder(collection.Count<TEntity>() *TEntityLength + 100); //获取表名 string tableName = GetTableName<TEntity>(context); //获取表列 Dictionary<PropertyInfo,ColumnAttribute> col = GetTableCol<TEntity>(context); string insert = "insert into " + tableName + "("; foreach (var item in col) { if (!item.Value.IsDbGenerated) { insert += "["+item.Value.Name + "],"; } } cmd.Append(insert); cmd.Remove(cmd.Length - 1, 1); cmd.Append(") values"); //添加数据 foreach (var item in collection) { cmd.Append("("); foreach (var c in col) { if (!c.Value.IsDbGenerated) { if (c.Key.PropertyType == typeof(string)) { cmd.Append("'" + c.Key.GetValue(item, null).ToString() + "',"); } else { cmd.Append(c.Key.GetValue(item, null).ToString() + ","); } } } cmd.Remove(cmd.Length - 1, 1); cmd.Append("),"); } cmd.Remove(cmd.Length - 1, 1); cmd.Append(";"); return cmd.ToString(); } public static Dictionary<PropertyInfo, ColumnAttribute> GetTableCol<TEntity>(this DataContext context) { Dictionary<PropertyInfo, ColumnAttribute> col = new Dictionary<PropertyInfo, ColumnAttribute>(); PropertyInfo[] m = typeof(TEntity).GetProperties(); foreach (var item in m) { Attribute[] pat = Attribute.GetCustomAttributes(item); foreach (var item1 in pat) { if (item1.GetType() == typeof(ColumnAttribute)) { col[item] = (ColumnAttribute)item1; } } } return col; } private static string GetTableName<TEntity>(this DataContext context) { string tableName = ""; Attribute[] atb = Attribute.GetCustomAttributes(typeof(TEntity)); foreach (var item in atb) { if (item.GetType() == typeof(TableAttribute)) { tableName = ((TableAttribute)item).Name; } } return tableName; } } [Table(Name = "Teacher")] public class Teacher { [Column(Name = "序号",IsPrimaryKey = true, CanBeNull = false)] public int ID { get; set; } [Column(Name = "名字",CanBeNull = false)] public string Name { get; set; } [Column(Name = "年龄",CanBeNull = false)] public int Age { get; set; } } public class Person : DataContext { public Table<Student> Student; public Person(string conString) : base(conString) { } } #if DEBUG [TestFixture] public class LinqSql { public static string constr = AppDomain.CurrentDomain.BaseDirectory + @"\Person1.mdf"; public static Person db; [Test] public static void CreateDatabase() { db = new Person(constr); if (db.DatabaseExists()) { db.DeleteDatabase(); db.Connection.Close(); db.Dispose(); db = new Person(constr); } db.CreateDatabase(); Trace.WriteLine(constr); Trace.WriteLine(constr); db.CreateTable(typeof(Teacher)); Table<Teacher> tl; if ((tl =db.GetTable<Teacher>()) != null) { Trace.WriteLine(typeof(Teacher) + "表已经存在"); db.DeleteTable<Teacher>(); } } [Test] public static void CreateInsertCmd() { List<Teacher> tl = new List<Teacher>() { new Teacher() { Name = "fds", ID = 1, Age = 22 } , new Teacher(){Name = "ffdf",ID = 2,Age = 23}}; db.InsertAll<Teacher>(tl); } } #endif }