zoukankan      html  css  js  c++  java
  • LINQ to SQL使用教程

    前些时间用LINQ to SQL做了一些项目,现在打算总结一下,帮助新手快速入门,并写一些别的教程没提到的东西。

    一、LINQ to SQL和别的LINQ to XXX有什么关系?
    二、延迟执行(Deferred Loading)
    三、什么是LINQ to SQL?
    四,看看LINQ to SQL到底干了些啥?——创建自己的工具类
    五、创建一个基本查询
    六,大致扫一扫
        1,WHERE
        2,DISTINCT
        3,AVG/COUNT/SUM/MIN/MAX
        4,GROUP BY
        5,CASE WHEN
        6,INNER JOIN和OUTER JOIN
            6.1 內连接
            6.2 外连接
        7,ORDER BY
        8,EXISTS
        9,WHERE IN
        10,UNION ALL/UNION
        11,Intersect/Except
        12,Skip-Take
        13,直接执行SQL语句查询
        14,INSERT
        15,UPDATE
        16,DELETE
        17,First/FirstOrDefault/Single
        18,字符串操作
    七、查询条件拼接
    八、自动事务处理
    九、关于自增的ID字段
    十、关于默认值
    总结

    一、LINQ to SQL和别的LINQ to XXX有什么关系?

    我们能接触到的别的带有“LINQ”字眼的东西有:LINQ to Object和LINQ to Entity Framework。它们之间的关系可以说:除了使用了相似的语法,就没什么关系了。

    LINQ to Object使用的命名空间是:System.Linq,而LINQ to SQL使用的命名空间是System.Data.Linq。

    这是一个简单的LINQ to Object的例子:

            static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list)
            {
                foreach (var i in list)
                {
                    if (i >= 5)
                        yield return i;
                }
            }
    
            static void Main(string[] args)
            {
                List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
    
                //找出所有大于等于5的数
                IEnumerable<int> result = FindGreaterThan5(listTest);
                foreach (var i in result)
                {
                    Console.WriteLine(i);
                }
            }

    其中FindGreaterThan5的代码可以用LINQ to Object改为:

            static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list)
            {
                return list.Where(i => i >= 5);
            }

    执行的效果是完全一样的,但要注意一点:LINQ to Object只是简化了代码,并非提高了效率。而且,有时候把一个foreach语句写成一大坨LINQ表达式,其可读性也不好,所以究竟用还是不用,这个就看你的需要了。

    二、延迟执行(Deferred Loading)

    像上述例子的那种使用yield return的方式返回一个可枚举类型的函数,都会被“延迟”执行,要证明这点很简单,改一下上面的代码:

            static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list)
            {
                foreach (var i in list)
                {
                    if (i >= 5)
                        yield return i;
                    else
                    {
                        throw new Exception("你看不到这个异常");
                    }
                }
            }
    
            static void Main(string[] args)
            {
                List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
    
                //找出所有大于等于5的数
                IEnumerable<int> result = FindGreaterThan5(listTest);
            }

    这个程序执行没有任何问题,你看不到异常,因为FindGreaterThan5根本没有被执行,它只有在返回结果被用到的时候才会真正去执行(这样做的好处后面会提到)。如果你把foreach加上,改为:

            static void Main(string[] args)
            {
                List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
    
                //找出所有大于等于5的数
                IEnumerable<int> result = FindGreaterThan5(listTest);
                foreach (var i in result)
                {
                    Console.WriteLine(i);
                }
            }

    那这个异常就会出现,这个地方是要十分小心的,假如你这么写:

                IEnumerable<int> result; 
                try
                {
                    result = FindGreaterThan5(listTest);
                }
                catch(Exception) //你捕捉不到异常的
                {
                    return;
                }

    那是捕捉不到异常的,因为它实际上发生的地方是接下来的foreach处。解决方法有两种,一是try foreach语句,另一是“再包一层”,创建一个“Roll”函数:

            static IEnumerable<int> FindGreaterThan5Roll(IEnumerable<int> list)
            {
                return FindGreaterThan5(list);
            }

    然后try这个函数。

    三、什么是LINQ to SQL?

    貌似讲了一堆跟LINQ to SQL无关的东西,但我向你保证理解这些内容真的很重要!OK……终于到了其它一般的教程的那个开头:什么是LINQ to SQL?

    跟LINQ to Object一样,LINQ to SQL能够使得你对Microsoft SQL Server的访问代码变得简洁,它是对ADO.net的封装。所以它并非ADO.net的替代品,也不能带来执行效率上的提高(用的不好反而会更低效)。这里还需要特别说明的是:

    1. 只能用于Microsoft SQL Server这套DBMS,2005版及2008版我都试过,没问题。Oracle?MySQL?没门;
    2. LINQ to SQL已经有了更强大和复杂的替代品,LINQ to Entity Framework,简称LINQ to EF或者Entity Framework,详情请自行Google一下。

    那为什么还用LINQ to SQL?一来它继续长期有效(虽然微软停止更新它了),二来够用并且好用,而LINQ to EF则相对复杂。

    使用LINQ to SQL其实仍然是使用ADO.net,只是LINQ to SQL帮助你生成各个查询语句,不需要你手工来写,这样有什么好处?最大的好处就是:只要你的代码编译通过,那么就能生成正确的SQL语句,而不是报运行时错误,然后让你去检查SQL语句。

    当然,好处不止这个,还有如:简单,开发快捷,更灵活的where从句生成等。

    四,看看LINQ to SQL到底干了些啥?——创建自己的工具类

    前面说了,LINQ to SQL其实是“聪明”地帮你生成查询语句,但你不能完全相信它,因为它有时候是“自作聪明”,所以你要在调试的时候看看它究竟干了些什么。我的方法是将它的生成的SQL语句打印到Debug窗口中,这个小技巧帮我找到了不少的问题,OK,这里我把我写的这个小小的DataContext的帮助类贴出来:

        public class DebugWriter : TextWriter
        {
            public override void WriteLine(string value)
            {
                Debug.WriteLine(value);
            }
    
            public override void WriteLine(string format, params object[] arg)
            {
                Debug.WriteLine(format, arg);
            }
    
            public override Encoding Encoding
            {
                get { return Encoding.UTF8; }
            }
        }
    
        public static class DataContextHelper
        {
            public static void InitForModification(this DataContext dc)
            {
                dc.DeferredLoadingEnabled = false;
    #if DEBUG
                dc.Log = new DebugWriter();
    #endif
            }
    
            /// <summary>
            /// 如果一个表中的某一列引用到别的表,默认情况下LINQ to SQL会在遍历搜索结果的时候
            /// 动态地去获取别的表的内容,这样就可能产生大量的SQL查询
            /// 当把DeferredLoadingEnabled设置为false之后,LINQ to SQL则关闭这项功能,省去了大量的开销
            /// 事实上,我们更多的时候会用到LoadWith,直接生成一条联表查询
            /// </summary>
            public static void InitForQuery(this DataContext dc)
            {
                dc.ObjectTrackingEnabled = false;
                dc.DeferredLoadingEnabled = false;
    #if DEBUG
                dc.Log = new DebugWriter();
    #endif
            }
    
            public static DateTime GetDbDateTime(this DataContext dc)
            {
                try
                {
                    return dc.ExecuteQuery<DateTime>("SELECT GETDATE()").Single();
                }
                catch (Exception ex)
                {
                    throw new Exception("Database error.", ex); //建议替换成你的自定义异常类型
                }
            }
        }

    如果你对C#的扩展方法语法不是很清楚,那么可以参考我的另一篇博文:http://www.cnblogs.com/guogangj/archive/2012/03/02/2376927.html

    这个帮助类很有用,把它引入到你的工程的namespace去吧(在我的工程中,我把它放入一个公共类库中,因为好几个工程都要引用到,避免重复,DRY,OK?)

    • InitForQuery - 用于查询(注意看看我写的那几行注释,后面会提到)
    • InitForModification - 用于增删改
    • GetDbDateTime - 由于LINQ to SQL不直接支持GetDate函数,所以写一个函数来获取DBMS的时间

    接下来我们还是用Northwind数据库为例子,看看如何使用LINQ to SQL。(Northwind是一个小型数据库例子,很多代码都用它作为范例,在这里获取它的创建脚本:http://northwinddatabase.codeplex.com/)

    五、创建一个基本查询

    给你的工程add一个new item,叫Products.dbml,然后打开之,再如图把Products和Categories两张表拽进去。

    然后:

            static void Main(string[] args)
            {
                ProductsDataContext db = new ProductsDataContext();
                db.Log = new DebugWriter();
                var products = from p in db.Products select p;
                foreach (var product in products)
                {
                    Console.WriteLine(product.ProductName+ " (" + product.Category.CategoryName + ")");
                }
            }

    这里也许你有个问题,为什么from写在前面,而不是select,select写在前面不是更符合SQL的习惯么?想想看,如果你能自己在5分钟内想出来说明你比我聪明(^_^),OK,其实也跟技术本身关系不大,这样做的原因完全是为了我们的开发环境的智能提示(intellisense),知道from什么了,后面也就有智能提示了,否则select什么?不知道。

    F5,调试运行,看吧,这么一点点代码,就能把所有商品名称及其类型都给打印出来了,是不是很方便?——且慢!打开你的Debug窗口看看:

    我的天啊,一个查询就能完成的事情,为什么生成了这么多的SQL语句?这就是我前面所提到的DeferredLoadingEnabled这个选项,看我写的那个帮助类的InitForQuery方法的注释。避免这种情况的方法是关闭这个选项,并显式告诉LINQ to SQL,你需要哪些关联的加载内容,让LINQ to SQL自动给你生成一个联表查询。我们来改进下:

            static void Main(string[] args)
            {
                ProductsDataContext db = new ProductsDataContext();
                db.InitForQuery();
    
                DataLoadOptions ds = new DataLoadOptions();
                ds.LoadWith<Product>(p => p.Category);
                db.LoadOptions = ds;
    
                var products = from p in db.Products select p;
                foreach (var product in products)
                {
                    Console.WriteLine(product.ProductName+ " (" + product.Category.CategoryName + ")");
                }
            }

    注意看,这次用了我前面提供的扩展方法InitForQuery,还有一个DataloadOptions选项,告诉LINQ to SQL需要哪些额外信息,这里我们需要Category信息。好,看看Debug窗口,这次只有一个SQL语句:

    SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued], [t2].[test], [t2].[CategoryID] AS [CategoryID2], [t2].[CategoryName], [t2].[Description], [t2].[Picture]
    FROM [dbo].[Products] AS [t0]
    LEFT OUTER JOIN (
        SELECT 1 AS [test], [t1].[CategoryID], [t1].[CategoryName], [t1].[Description], [t1].[Picture]
        FROM [dbo].[Categories] AS [t1]
        ) AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]

    LINQ to SQL聪明地为我们生成了一个left outer join,这正是我们想要的。

    这个例子说明了:

    1. 我们在调试的时候得关注下LINQ to SQL到底干了些什么
    2. 使用LoadWith,而不要使用自动延迟加载

     另外,如果你不需要Product的所有列的话,你可以这样写:

            var products = from p in db.Products
            select new
                   {
                       ProductId = p.CategoryID,
                       ProductName = p.ProductName,
                       UnitPrice = p.UnitPrice
                   };

    这样生成的SQL语句是不太一样的,自己观察下,但这样生成出来的对象,是不能用于Insert和Update的,这个要注意一下。

    六,大致扫一扫

    写一篇无微不至的教程并非本文目的,这个已经有了不少好的教程,所以接下来就稍微简略一些,希望能对大家起到一定的抛砖引玉的作用。

    1,WHERE

    把1994年后雇佣的,或者Title中包含“经理”的员工选出来

                var result =
                    from e in db.Employees
                    where e.HireDate >= new DateTime(1994, 1, 1) || e.Title.Contains("Manager")
                    select e;

    2,DISTINCT

    获取有交易的客户ID(重复的去掉)

    var result = (from o in db.Orders select new { CustomerID = o.CustomerID }).Distinct();

    3,AVG/COUNT/SUM/MIN/MAX

    取得产品价格的平均值

                var result = db.Products.Select(p => p.UnitPrice).Average();
                var result = db.Products.Average(p => p.UnitPrice);
                var result = (from p in db.Products select p.UnitPrice).Average();

    从这也能看出写法并不是唯一的。其它集合操作函数也是类似的。

    4,GROUP BY

    选出每一类的最贵产品、最便宜产品及产品均价

                var result =
                    from p in db.Products
                    group p by p.CategoryID into g
                    select new
                    {
                        g.Key,
                        Amount = g.Count(),
                        MaxPrice = g.Max(item => item.UnitPrice),
                        MinPrice = g.Min(item=>item.UnitPrice),
                        AveragePrice = g.Average(item=>item.UnitPrice)
                    };

    5,CASE WHEN

                var q = from c in db.Customers
                        select new
                        {
                            Name = c.ContactName,
                            Address = new
                            {
                                City = c.City,
                                Region = c.Region == null ? "Unknown" : c.Region
                            }
                        };

    翻译为:

    SELECT [t0].[ContactName] AS [Name], [t0].[City],
        (CASE
            WHEN [t0].[Region] IS NULL THEN CONVERT(NVarChar(15),@p0)
            ELSE [t0].[Region]
         END) AS [Region]
    FROM [dbo].[Customers] AS [t0]

    6,INNER JOIN和OUTER JOIN

    想用LINQ to SQL直接写联表查询是很麻烦的,不过这也是唯一一个相比直接用SQL来得更麻烦的地方。

    6.1 內连接

                var result = from d in db.Order_Details
                             join o in db.Orders on d.OrderID equals o.OrderID
                             select new {d.OrderID, d.ProductID, d.UnitPrice, o.RequiredDate};

    翻译为

    SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t1].[RequiredDate]
    FROM [dbo].[Order Details] AS [t0]
    INNER JOIN [dbo].[Orders] AS [t1] ON [t0].[OrderID] = [t1].[OrderID]

    另外一种更紧凑的写法

                var result = from d in db.Order_Details
                     from o in db.Orders.Where(item=>item.OrderID==d.OrderID)
                     select new { d.OrderID, d.ProductID, d.UnitPrice, o.RequiredDate };

    翻译为

            SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t1].[RequiredDate]
            FROM [dbo].[Order Details] AS [t0], [dbo].[Orders] AS [t1]
            WHERE [t1].[OrderID] = [t0].[OrderID]

    执行效果一样的

    6.2 外连接

                 var result = from d in db.Order_Details
                              join o in db.Orders on d.OrderID equals o.OrderID into temp
                              from p in temp.DefaultIfEmpty()
                              select new {d.OrderID, d.ProductID, d.UnitPrice, p.RequiredDate};

    另一种更紧凑的写法是:

                var result = from d in db.Order_Details
                             from o in db.Orders.Where(item => item.OrderID == d.OrderID).DefaultIfEmpty()
                             select new {d.OrderID, d.ProductID, d.UnitPrice, o.RequiredDate };

    翻译为

    SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t1].[RequiredDate] AS [RequiredDate]
    FROM [dbo].[Order Details] AS [t0]
    LEFT OUTER JOIN [dbo].[Orders] AS [t1] ON [t1].[OrderID] = [t0].[OrderID]

    7,ORDER BY

    正序的情况

        var result = from p in db.Products orderby p.UnitPrice select p;

    逆序的情况

        var result = from p in db.Products orderby p.UnitPrice descending select p;

    也可以选择多列排序

        var result = from p in db.Products orderby p.UnitPrice, p.UnitsInStock select p;

    上面的句子也可以这么写,一样的

        var result = from p in db.Products.OrderBy(item => item.UnitPrice).ThenBy(item => item.UnitsInStock) select p;

    8,EXISTS

    选出没有订单的客户

        var result = from c in db.Customers where !c.Orders.Any() select c;

    其实Any还可以带条件参数哦。

    9,WHERE IN

    查看指定的几个客户的订单

    var result = (
        from o in db.Orders
        where (
        new string[] { "AROUT", "BOLID", "FISSA" })
        .Contains(o.CustomerID);

    10,UNION ALL/UNION

    Concat不会去除重复项目,相当于SQL的Union All;而Union会去除重复项,相当于SQL的Union

    看看有来自哪些国家的客户和雇员

                var q = (
                         from c in db.Customers
                         select c.Country
                        ).Union(
                         from e in db.Employees
                         select e.Country
                        );

    11,Intersect/Except (是用复合查询加EXIST实现的)

                var q = (
                         from c in db.Customers
                         select c.Country
                        ).Intersect(
                         from e in db.Employees
                         select e.Country
                        );

    查询顾客和职员同在的国家,Interset其实是用一个复合查询实现的。

                var q = (
                         from c in db.Customers
                         select c.Country
                        ).Except(
                         from e in db.Employees
                         select e.Country
                        );

    去除顾客和职员同在的国家。

    12,Skip-Take(是用ROW_NUMBER()函数实现的)

    获取从第21个产品开始的10个产品。

                var q = (
                            from p in db.Products
                            select p
                        ).Skip(20).Take(10);

    13,直接执行SQL语句查询

    如果发现查询语句很难写,(或者写出来LINQ会傻乎乎地生成低效的多次执行)可以考虑直接使用SQL语句,但缺点就是失去了编译器检查的功能,并且得自己构建好一个类,用于存放数据(如果此类还没有的话)。

    IEnumerable<Employee> emps = db.ExecuteQuery<Employee>("select * from Employees");

    PS:直接写“*”可不太好

    14,INSERT

    注意:如果指定的ID存在,则会自动执行Update,而不是Insert(LINQ to SQL是不是很“智能”?都有些自作聪明了)

    Region nwRegion = new Region()
    {
        RegionID = 32,
        RegionDescription = "Rainy"
    };
    db.Regions.InsertOnSubmit(nwRegion);
    db.SubmitChanges();

    15,UPDATE

    真奇怪,update和insert居然不同,没有一个专门的Update方法,而是直接取出数据库的条目,然后修改其属性,在SubmitChanges,当然,条目的类型必须是dbml自动帮我们生成的类型,不能是自定义的。这是简单的Update的例子:

    Customer cust = db.Customers.First(c => c.CustomerID == "ALFKI");
    cust.ContactTitle = "Vice President";
    db.SubmitChanges();

    这是Update多条的例子:

    var q = from p in db.Products
            where p.CategoryID == 1
            select p;
    foreach (var p in q)
    {
        p.UnitPrice += 1.00M;
    }
    db.SubmitChanges();

    16,DELETE

    先选后删

    OrderDetail orderDetail =
        db.OrderDetails.First
        (c => c.OrderID == 10255 && c.ProductID == 36);
    db.OrderDetails.DeleteOnSubmit(orderDetail);
    db.SubmitChanges();

    17,First/FirstOrDefault/Single(是用TOP实现的)

    都是取出一条记录,区别是:

    • First – 至少有一条,否则抛异常
    • FirstOrDefault – 如果一条都没有,则返回默认值(对象的话默认值就是null)
    • Single – 有且只有一条,否则抛异常

    选出ID为1的雇员:

    Employee theveryemp = db.Employees.Single(item => item.EmployeeID == 1);

    这个语句会立即执行,如果获取不到或者不止一条,则抛出异常。

    18,字符串操作

    以下这些LINQ中对字符串操作的部分都会被聪明地转变为相关的SQL语句,而不是使用C#代码来操作。具体会被转换成什么,大家动手试试看。

    Location = c.City + ", " + c.Country
    p.ProductName.Length < 10
    c.ContactName.Contains("Anders")
    c.ContactName.IndexOf(" ")
    c.ContactName.StartsWith("Maria")
    c.ContactName.EndsWith("Anders")
    p.ProductName.Substring(3);
    e.HomePhone.Substring(6, 3) == "555"
    e.LastName.ToUpper()
    c.CategoryName.ToLower()
    e.HomePhone.Substring(0, 5).Trim()
    e.HomePhone.Insert(5, ":")
    e.HomePhone.Remove(9)
    e.HomePhone.Remove(0, 6)
    s.Country.Replace("UK", "United Kingdom")

    七、查询条件拼接

    客户端在查询的时候往往会附带一些查询条件,例如商品名称模糊查询,日期范围,商品类型范围,当然还有分页等等。我们通常把这些查询条件封装到一个对象中去,然后让服务器来解释这个对象并拼接SQL查询语句。拼接SQL语句是极其容易出错的事情,而且检查起来还比较费劲,因为SQL语句写起来并不像C#代码那样可以自动格式化。如今使用LINQ to SQL这些问题就不存在了。

    var q = from p in db.Products select p;
    if(条件A)
    {
        q.Where(p=>p.XXX==A);
    }
    if(条件B)
    {
        q.Where(p=>p.YYY!=B);
    }
    if(条件C)
    {
        q.Where(p=>p.ZZZ.Contains(C));
    }
    //……
    

    回头想想本文初所提到的延迟执行,到这里你应该知道为什么需要延迟执行了吧,就是为了方便你拼接这些LINQ表达式,如果每个select或者where都执行一次,那可是会带来严重的性能问题的。

    八、自动事务处理

    也许你发现了,对于增删改,都是在SubmitChanges的时候执行,而且一次SubmitChanges,能改多个表多条记录,那事务在哪里?其实LINQ to SQL已经自动帮我们封装好事务了,在执行的过程中,一旦有一步失败,操作将会回滚,这个完全不需要我们担心。

    九、关于自增的ID字段

    按设计惯例,每张表都应该有一个自增的ID字段,对于这个字段,其值总是由数据库自动生成的,所以我们在Insert一行的时候,从来不需要指定其ID。例如,我们查看ProductID的属性列表,有个叫Auto Generated Value的属性,其值为True,即代表这个字段的值是DBMS自动生成的,你不需要指定。

    那么我们插入了一条记录之后,我们想取回这个自动生成的ID的值,怎么办呢?按以前的做法是:

    select scope_identity()

    现在的做法是在SubmitChanges()之后直接通过插入的对象带出这个自动生成的ID的值:

                Category newCategory = new Category {CategoryName = "Fruit", Description = "Fruits..."};
                db.Categories.InsertOnSubmit(newCategory);
                db.SubmitChanges();
                Console.WriteLine(newCategory.CategoryID);

    那现在有这么种情况,我要添加一个订单,同时给这个订单添加若干条明细,怎么办?这个看起来有点难,难在哪里?你要添加明细,你就必须知道主档的ID,但在SubmitChanges之前,你是拿不到主档的ID的;如果你在Insert了主档之后就Submit,那一旦在Insert明细的时候失败,你就无法回滚了。

    OK,其实这么想的话还是按照旧的思路,LINQ to SQL是一套ORM,我们应该直接指定其对象的关系,而不是去关心ID的值是多少,这是正确的做法:

                Order newOrder = new Order { CustomerID = "ALFKI", ShipAddress = "Shanghai ..." };
                Order_Detail newDetail1 = new Order_Detail { Discount = 1.0f, ProductID = 1, Quantity = 1, UnitPrice = 9.0M };
                Order_Detail newDetail2 = new Order_Detail { Discount = 0.9f, ProductID = 2, Quantity = 2, UnitPrice = 5.0M };
                newOrder.Order_Details.Add(newDetail1);
                newOrder.Order_Details.Add(newDetail2);
                db.Orders.InsertOnSubmit(newOrder);
                db.SubmitChanges();

    十、关于默认值

    数据库的表中的很多字段都带有默认值,前面提到的自增ID就是一个例子,但大多字段跟ID不同的是:ID是强制的并且一定是DBMS自动分配的,而这些带默认值的字段则不一定强制,并且允许由用户传入值。如果把这些带默认值的字段跟自增ID一样,设置其“Auto Generated Value”属性为True的话,我们就没办法设置它的值了,它的值总是由DBMS自动分配,而事实上,我们想要的结果是:当我没有给值的时候使用默认值,当我有给值的时候,使用我的值。很不幸,LINQ to SQL做不到,我尝试过很多种方法,结果很明确,就是做不到!这也许算是LINQ to SQL的一个缺陷吧。

    所以,使用LINQ to SQL的话就把DBMS的默认值忽略掉吧,每次都手工把值传进去好了……

    总结

    感谢你看完本文,本文肯定不是最全面的对LINQ to SQL的技术文章,但真心是本人实战的总结,如果上面提到的内容你都理解,那LINQ to SQL你也就掌握差不多了……呃,我是说即便你再遇到什么问题,你也肯定有解决的思路了。

  • 相关阅读:
    PHP magic_quotes_gpc的详细使用方法
    tinkphp URL重写,支持伪静态
    element-UI中table表格的@row-click事件和@selection-change耦合了
    element-ui dialog组件添加可拖拽位置 可拖拽宽高
    vue.js 父组件如何触发子组件中的方法
    Element UI Form 每行显示多列,即多个 el-form-item
    vue组件的3种书写形式
    Java 微信公众号迁移
    Java 微信公众号导出所有粉丝(openId)
    [四]并发类容器
  • 原文地址:https://www.cnblogs.com/guogangj/p/2920961.html
Copyright © 2011-2022 走看看