【问题标题】:Why does linq-2-sql create extra unnecessary objects?为什么 linq-2-sql 会创建额外的不必要对象?
【发布时间】:2012-08-13 09:15:53
【问题描述】:

我在这样的数据库中有一个简单的父子表

CREATE TABLE [Parent](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](256) NOT NULL)    
ALTER TABLE [Parent] ADD CONSTRAINT [PK_Parent_Id] PRIMARY KEY ([Id])    

CREATE TABLE [Child](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NOT NULL,
    [Name] [nvarchar](256) NOT NULL)    
ALTER TABLE [Child] ADD CONSTRAINT [PK_Child_Id] PRIMARY KEY ([Id])
ALTER TABLE [Child] ADD CONSTRAINT [FK_Child_Parent_ID] 
    FOREIGN KEY([ParentId]) REFERENCES [Parent] ([Id])

我在其中的数据是

父表

Id  Name
1   John

子表

Id ParentId  Name
1     1    Mike
2     1    Jake
3     1    Sue
4     1    Liz

这些表使用 Visual Studio 中的 Linq-2-SQL 设计器映射到 ParentChild C# 对象,没有非标准选项。

我做了一个简单的测试程序来查询所有孩子和他们的父母

public partial class Parent
{
    static int counter = 0;
    //default OnCreated created by the linq to sql designer
    partial void OnCreated()
    {
        Console.WriteLine(string.Format("CreatedParent {0} hashcode={1}",
            ++counter , GetHashCode()));
    }
}

class Program
{
    static void Main(string[] args)
    {
        using (var db = new SimpleDbDataContext())
        {
            DataLoadOptions opts = new DataLoadOptions();
            opts.LoadWith<Child>(c => c.Parent);
            db.LoadOptions = opts;
            var allChildren = db.Childs.ToArray();
            foreach (var child in allChildren)
            {
                Console.WriteLine(string.Format("Parent name={0} hashcode={1}",
                    child.Parent.Name, child.Parent.GetHashCode()));

            }
        }
    }
}

上述程序的输出是

CreatedParent 1 hashcode=53937671
CreatedParent 2 hashcode=9874138
CreatedParent 3 hashcode=2186493
CreatedParent 4 hashcode=22537358
Parent name=John hashcode=53937671
Parent name=John hashcode=53937671
Parent name=John hashcode=53937671
Parent name=John hashcode=53937671

如您所见,为数据库中的每个 Child 创建了一个 Parent 对象,但最终被丢弃。

问题:

  1. 为什么 Linq-2-Sql 会创建这些不必要的额外 Parent 对象?
  2. 是否有任何选项可以避免创建额外的 Parent 对象?

【问题讨论】:

  • 它不会像您期望的那样创建单例对象,也不应该这样做。如果您有一个查询选择了一个对象,并且您开始在同一个 id 上编写更新查询,会发生什么?您是否应该在提交更改之前立即看到更改的结果?为每个查询创建一个唯一的实例。
  • @JeffMercado,不:L2S 只为每个表和键分配一个实例。这是 ORM(身份映射)的一个重要特性。

标签: c# .net linq linq-to-sql orm


【解决方案1】:

这是一种副作用,LoadWith 被实现了。 LINQ to SQL 在内部将您的查询转换为:

from c in children
select { Child = c, Parent = c.Parent }

如您所见,我们为每个子节点加载一次父节点(内部连接)。由于恒等映射,此效果通常不可见。 ORM 确保实体对象永远不会被(表、主键)重复。这在您进行更新时会派上用场。

LINQ to SQL 读取从服务器返回的结果集(它包含相同的 Parent N 次!)并将其具体化为对象。只有在物化完成后,身份映射才能完成其工作并丢弃重复的父实例。

相同的效果适用于多次返回同一实体的所有查询。

【讨论】:

  • 确实是内连接。这就像编写此查询并在 SSMS 中运行。 SELECT * FROM child JOIN parent on child.ParentId = Parent.Id... 当你运行这个查询时,你会得到每个孩子的父 id 没什么新鲜的,实际上这里 VS 是遵循 SQL 标准的标准脚步。
猜你喜欢
  • 1970-01-01
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 2021-07-18
  • 2014-01-08
相关资源
最近更新 更多