为什么linq-2-sql会创建额外的不必要对象?

par*_*mar 14 .net c# linq orm linq-to-sql

我在数据库中有一个简单的Parent Child表

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])
Run Code Online (Sandbox Code Playgroud)

我在其中的数据是

父表

Id  Name
1   John
Run Code Online (Sandbox Code Playgroud)

儿童表

Id ParentId  Name
1     1    Mike
2     1    Jake
3     1    Sue
4     1    Liz
Run Code Online (Sandbox Code Playgroud)

这些表映射到ParentChild使用Visual Studio中的LINQ 2 SQL设计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()));

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上述程序的输出是

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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,为数据库中的Parent每个对象创建了一个对象,Child最终只能被丢弃.

问题:

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

usr*_*usr 12

这是一种副作用,LoadWith实施方式.LINQ to SQL将您的查询内部转换为:

from c in children
select { Child = c, Parent = c.Parent }
Run Code Online (Sandbox Code Playgroud)

如您所见,我们为每个孩子(内部联接)加载一次Parent.由于身份图,此效果通常不可见.ORM确保实体对象永远不会被(表,主键)复制.当您进行更新时,这会派上用场.

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

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

  • 它确实是一个内部联接.这就像编写此查询并在SSMS中运行一样.SELECT*FROM子JOIN父项在child.ParentId = Parent.Id ...当你运行这个查询时你得到的每个孩子的父ID都没什么新的,事实上这里的VS是遵循SQL标准的标准足迹. (3认同)