2012-08-16 59 views
14

我有一个简单的亲子数据库表中,像这样为什么linq-2-sql会创建额外的不必要的对象?

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 

这些表映射到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())); 

      } 
     } 
    } 
} 

上述程序的输出是

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 

正如你可以看到一个Parent目标是为每一个Child创建只在数据库中被丢弃。

问题:

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

它不会像您所期望的那样创建单例对象,也不应该这样做。如果您有一个查询选择了一个对象,并且您开始在同一个ID上编写更新查询,会发生什么?您应该在提交更改之前立即看到更改的结果吗?为每个查询创建一个唯一的实例。 – 2012-08-17 00:09:25

+0

@JeffMercado,no:L2S只发布每个表和关键字的一个实例。这是ORM(身份地图)的一个重要特征。 – usr 2012-08-20 21:11:20

回答

12

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

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

正如你所看到的,我们一旦加载家长为每个孩子(内部连接)。由于身份地图的缘故,此效果通常不可见。 ORM确保实体对象永远不会被(表,主键)重复。当您进行更新时,这会派上用场。

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

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

+3

正是它是一个内部联接。这就像编写这个查询并在SSMS中运行一样。 SELECT * FROM child JOIN父对child.ParentId = Parent.Id ...当你运行这个查询时,你得到每个孩子的父母id没有新东西,实际上这里的VS跟随着SQL标准的标准脚步。 – MStp 2012-08-23 07:25:48

相关问题