EF 中的导航属性和事务

本文详细介绍了Entity Framework(EF)中DBContext的生命周期,包括数据库连接、IDisposable接口的实现以及SaveChanges方法的事务处理。此外,还探讨了延迟加载(懒加载)和贪婪加载的原理及使用,强调了在Linq查询中的应用。对于导航属性,文章讲解了主外键关系、Include方法以及自增Id的自动填充。最后,文章深入讨论了事务管理,包括SaveChanges自动开启的事务、BeginTransaction、TransactionScope以及分布式事务的实现,并提供了源码下载链接。


一、DBContext生命周期

1.数据库连接

DBContext对象是一个上下文,可以理解成一个数据库连接实例;包含了一系列的数据操作。

2.实现了IDisposable接口

DBContext对象很耗系统资源;一般使用Using包裹(使用完马上自动释放)。

3.SaveChanges方法

SaveChanges是以DBContext为维度的,会自动开启事务去执行多个数据库操作。

4.建议用法

一次请求一个DBContext实例,用完尽快释放;不要单例,也不要多线程使用同一个DBContext。

二、延迟加载(懒加载)/贪婪加载

1.原理解析

只有在使用到的时候才去执行获取数据(生成对应的Sql,按需获取,思想是延迟一切可以延迟的。
而贪婪加载是把对象的关联数据也查询出来,关联数据是(Include)导航属性的数据。
代码如下(示例):

 public static void TestLoading()
        {
   
   
            using (CodeFirstContext ctx = new CodeFirstContext())
            {
   
   
                Console.WriteLine($"LazyLoadingEnabled:{ctx.Configuration.LazyLoadingEnabled}");
                //ctx.Configuration.LazyLoadingEnabled = true;
                var list = ctx.Clients.Where(c => c.Id > 1);
                foreach (var item in list)
                {
   
   
                    Console.WriteLine(item.ClientName);
                }
    //            Sql:
    //            SELECT 
    //            [Extent1].[Id] AS[Id], 
    //[Extent1].[Name] AS[Name], 
    //[Extent1].[Tel] AS[Tel], 
    //[Extent1].[Sex] AS[Sex], 
    //[Extent1].[Address] AS[Address], 
    //[Extent1].[CreateTime] AS[CreateTime], 
    //[Extent1].[CreatorId] AS[CreatorId]
    //FROM[dbo].[Client] AS[Extent1]
    //WHERE[Extent1].[Id] > 1
                var clientList = ctx.Clients.Include("OrderInfos").Where(c => c.Id > 1);
    //            Sql:
    //            SELECT
    //[Project1].[Id] AS[Id], 
    //[Project1].[Name] AS[Name], 
    //[Project1].[Tel] AS[Tel], 
    //[Project1].[Sex] AS[Sex], 
    //[Project1].[Address] AS[Address], 
    //[Project1].[CreateTime] AS[CreateTime], 
    //[Project1].[CreatorId] AS[CreatorId], 
    //[Project1].[C1] AS[C1], 
    //[Project1].[Id1] AS[Id1], 
    //[Project1].[ClientId] AS[ClientId], 
    //[Project1].[ProductId] AS[ProductId], 
    //[Project1].[Amount] AS[Amount], 
    //[Project1].[Price] AS[Price], 
    //[Project1].[CreateTime1] AS[CreateTime1], 
    //[Project1].[CreatorId1] AS[CreatorId1]
    //FROM(SELECT
    //    [Extent1].[Id] AS[Id],
    //    [Extent1].[Name] AS[Name],
    //    [Extent1].[Tel] AS[Tel],
    //    [Extent1].[Sex] AS[Sex],
    //    [Extent1].[Address] AS[Address],
    //    [Extent1].[CreateTime] AS[CreateTime],
    //    [Extent1].[CreatorId] AS[CreatorId],
    //    [Extent2].[Id] AS[Id1],
    //    [Extent2].[ClientId] AS[ClientId],
    //    [Extent2].[ProductId] AS[ProductId],
    //    [Extent2].[Amount] AS[Amount],
    //    [Extent2].[Price] AS[Price],
    //    [Extent2].[CreateTime] AS[CreateTime1],
    //    [Extent2].[CreatorId] AS[CreatorId1],
    //    CASE WHEN([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS[C1]
    //    FROM[dbo].[Client] AS[Extent1]
    //    LEFT OUTER JOIN[dbo].[Order] AS[Extent2] ON[Extent1].[Id] = [Extent2].[ClientId]
    //    WHERE[Extent1].[Id] > 1
    //)  AS[Project1]
    //ORDER BY[Project1].[Id] ASC, [Project1].[C1] ASC
                foreach (var item in clientList)
                {
   
   
                    Console.WriteLine(item.ClientName);
                }
            }
        }

2.延迟查询在Linq中的使用

IEnumerable(Linq to object):处理的是内存数据,原理是使用委托&迭代器来完成的延迟查询。
IQueryable(Linq to Sql):处理的数据库中的数据,原理是使用Expression(生成Sql语句)、ElementType(指定一个查询需要返回的结果类型)和IQueryProvider(获取与此数据源相关联的查询提供程序。)来完成的延迟查询。
代码如下(示例):

public static void TestLazyQueryFromLinq()
        {
   
   
            //Linq to object(操作内存数据)
            int[] randomSleepTimes = new int[] {
   
    1, 2, 4, 5, 6, 7, 8 };
            //IEnumerable+委托+迭代器完成的延迟查询---处理的是内存数据
            IEnumerable<int> list = randomSleepTimes.Where(rv =>
            {
   
   
                System.Threading.Thread.Sleep(rv * 1000);
                return rv > 0;
            });
            foreach (var item in list)
            {
   
   
                Console.WriteLine($"{DateTime.Now}    {item}");
            }

            //Linq to Sql
            using (CodeFirstContext ctx = 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值