Linq to SQL笔记(二)

  今天用Linq给数据表批量添加数据时,发现速度确实比ADO.net慢了不少,后面调出DataContext.Log记录一看,发现是一行一个命令添加数据,那速度当然慢了了,差不多慢了20倍左右,Linq的本质就是通过映射类等把c#等.net语言解释为SQL语句,我按照这个思路自己把程序语言解释为SQL,听说可以使用System.Linq.Expression里面的方法解释成SQL语句,但是我看了网上的代码,看不太明白,我就按自己想法封装了一个Insert方法,速度接近ADO.net有不对的请指正。

  第一步:从数据表映射类解释出表名,表列。

  先建立一个数据表映射类:

View Code
   
   
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、获取表名

View Code
   
   
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、获取列名及相关属性

View Code
   
   
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语句

View Code
   
   
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语句

View Code
   
   
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

View Code
   
   
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
}

你可能感兴趣的:(LINQ)