• 深入SQL Entity与EntityRef<T>内部


    引言

    最近在学习LINQ,已经逐步深入到LINQ to SQL和LINQ to Entity的部分。但是对SQL Entity专题中的EntityRef<T>很是迷惑,始终未能理解它是如何从数据库的1:1关系转变为C#中两个对象的相互引用的,于是有了这段摸索。

    阅读本文,需要对SQL Entity的内部结构有一定程度的了解。

    一切尽在不言中

    线索

    问题源自于下面我自己写的这段旨在测试引用关系的代码,Customers与Orders是通过“LINQ to SQL类”(.dbml)的方式,从数据库生成的SQL Entity类。其中,测试用例的客户Thomas Hardy的CustomerID为AROUT。

    using (NorthwindDataContext db = new NorthwindDataContext())
    {
        db.Log = Console.Out;
        Customers customer = db.Customers.Where(c => c.ContactName == "Thomas Hardy").SingleOrDefault();
        Console.WriteLine("the customer {0} lives in {1}", customer.City);
        Console.WriteLine("he gets {0} orders.", customer.Orders.Count);
    
        Orders order = db.Orders.Where(o => o.CustomerID == "AROUT").FirstOrDefault();
        Console.WriteLine("get the first order id is: {0}", order.OrderID);
    
        Console.WriteLine(object.ReferenceEquals("is the reference equal? {0}", customer, order.Customers));
    }

    运行的结果

    SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactT
    itle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Coun
    try], [t0].[Phone], [t0].[Fax]
    FROM [dbo].[Customers] AS [t0]
    WHERE [t0].[ContactName] = @p0
    -- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [Thomas Hardy]
    -- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
    
    the customer Thomas Hardy lives in London
    SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [
    t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[Sh
    ipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPosta
    lCode], [t0].[ShipCountry]
    FROM [dbo].[Orders] AS [t0]
    WHERE [t0].[CustomerID] = @p0
    -- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [AROUT]
    -- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
    
    he gets 13 orders.
    SELECT TOP (1) [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[Order
    Date], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight],
    [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[S
    hipPostalCode], [t0].[ShipCountry]
    FROM [dbo].[Orders] AS [t0]
    WHERE [t0].[CustomerID] = @p0
    -- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [AROUT]
    -- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
    
    get the first order id is: 10355
    is the reference equal? True

    从结果看,对象customer与order在我们没有显式地建立彼此的引用的情况下,通过LINQ to SQL仍实现了完美的相互引用,从而使最后的引用比较得到了True的结果。

    摸索过程

    打断点+单步调试,这是深入Entity内部的简易方法。最后得出如下的一张流程图。

    SQL Entity

    从图中可以看出,

    1. 子表对应的Entity对象并不会在父表Entity对象被填充时一并被构造并填充(除非显式地LoadWith)。EntitySet<T>与EntityRef<T>都是独立于作为其内部元素的Entity对象的数据结构。

    2. 总是先生成SQL查询语句,随后才由LINQ构造并填充Entity对象。

    3. attach/detach方法,是建立彼此引用的核心。

    EntityRef<T>的结构

    除了MSDN的帮助,我利用反射,获得了EntityRef<T>的结构图:

    EntityRef

    利用调试工具,还能看见其内部的私有成员:

    EntityRef Member

    到此,终于对LINQ to SQL Entity Class的数据加载,以及EntityRef<T>与EntitySet<T>的关系有了更深入的了解,心中的疑惑也终于有了一个答案。


    LINQ to Entity还在等待着我……

  • 相关阅读:
    Oracle基本操作汇总
    Oracle客户端+PLSQLDeveloper实现远程登录Oracle数据库
    ASP.NET后台执行JS代码
    ASP.NET 使用AJAX让GridView的数据行显示提示框(ToolTip)
    GridView如何实现双击行进行编辑,更新
    git push后是空目录,且提示modified content, untracked content
    SQL_2_查询Select语句的使用
    selenium2自动处理验证码
    jenkins配置邮箱时出错
    jenkins匿名用户登录
  • 原文地址:https://www.cnblogs.com/Abbey/p/2112229.html
Copyright © 2020-2023  润新知