2012-08-16 12 views
14

Ho una semplice tabella Padre Bambino in una base di dati in questo modoPerché linq-2-sql crea oggetti aggiuntivi non necessari?

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]) 

I dati che ho in loro è

Parent Table

Id Name 
1 John 

Tabella Bambino

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

Queste tabelle sono associate agli oggetti Parent e Child C# utilizzando la finestra di progettazione di Linq-2-SQL in Visual Studio senza opzioni non standard.

Ho fatto un semplice programma di test per interrogare tutti i bambini con i loro genitori

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())); 

      } 
     } 
    } 
} 

L'uscita del programma di cui sopra è

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 

Come si può vedere un oggetto Parent è stato creato per ogni Child nel database solo per essere scartati alla fine.

Domande:

  1. Perché Linq-2-SQL CREATE questi inutili aggiuntivi Parent oggetti?
  2. Esistono opzioni per evitare la creazione di oggetti aggiuntivi Parent?
+0

Non crea oggetti singleton come ci si aspetta e non dovrebbe. Che cosa accadrebbe se tu avessi una query che ha selezionato un oggetto e inizi a scrivere una query di aggiornamento sullo stesso id? Dovresti vedere immediatamente i risultati della modifica prima di inviare le modifiche? Un'istanza univoca viene creata per ogni query. –

+0

@JeffMercado, no: L2S distribuisce solo un'istanza per tabella e chiave. Questa è una caratteristica importante delle ORM (mappa delle identità). – usr

risposta

12

Questo è un effetto collaterale del modo, è implementato LoadWith. LINQ to SQL converte la query internamente:

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

Come potete vedere, stiamo caricando la Capogruppo una volta per ogni bambino (un inner join). Questo effetto non è normalmente visibile a causa della mappa dell'identità. Gli ORM assicurano che gli oggetti entità non siano mai duplicati da (tabella, chiave primaria). Questo è utile quando fai gli aggiornamenti.

LINQ to SQL legge il set di risultati restituito dal server (contiene la stessa N genitore!) E lo materializza in oggetti. Solo dopo aver completato la materializzazione, la mappa delle identità svolge il proprio lavoro e scarta le istanze padre duplicate.

Lo stesso effetto funziona per tutte le query che restituiscono la stessa entità più volte.

+3

Esattamente è un join interno. È come scrivere questa query e girare in SSMS. SELECT * FROM child JOIN genitore su child.ParentId = Parent.Id ... quando si esegue questa query si ottiene l'id padre per ogni figlio niente di nuovo, infatti VS sta seguendo le orme standard dello standard SQL. – MStp

Problemi correlati