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
}

posted on 2011-07-02 17:34  小指令  阅读(544)  评论(0)    收藏  举报

导航