2016-11-30 2 views
0

Ich verbinde Tabellen in meinem Befehl. Ich möchte die aktuelle Zeile löschen.
Unten ist mein Befehl und was ich normalerweise mache.
Aber heute habe ich den Fehler:Zeile löschen - generierte sql wird nicht für mehrere Tabellen unterstützt

generated sql is not supported for multiple table delete row

Was bedeutet das ??

OleDbCommand mycmdL = new OleDbCommand("SELECT DISTINCT AreaSize.*, Bathrooms.*, Cities.*, Prices.*, Properties.*, Rooms.*, Types.*, Users.* FROM Users INNER JOIN (Types INNER JOIN (Rooms INNER JOIN (Prices INNER JOIN (Cities INNER JOIN (Bathrooms INNER JOIN (AreaSize INNER JOIN Properties ON AreaSize.AreaSizeID = Properties.AreaSize) ON Bathrooms.BathroomID = Properties.Bathrooms) ON Cities.CityID = Properties.City) ON Prices.PriceID = Properties.Price) ON Rooms.RoomID = Properties.Rooms) ON Types.TypeID = Properties.PropertyType) ON Users.UserID = Properties.AgentID WHERE Users.UserID [email protected]", clsDataSource.mycon); 

myadaptL = new OleDbDataAdapter(mycmdL); 
myadaptL.Fill(clsDataSource.myset, "Properties"); 
tbListing = clsDataSource.myset.Tables["Properties"]; 

-Code aktuelle Zeile löschen:

try 
     { 
      if (MessageBox.Show("Are you sure?", "??", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) 
      { 
       DataRow myrow = tbListing.Rows[current]; 
       myrow.Delete(); 
       OleDbCommandBuilder mybuild = new OleDbCommandBuilder(myadaptL); 
       myadaptL.Update(tbListing); 

      } 
     } 
     catch (Exception) 
     { 

      throw; 
     } 
    } 
+0

Sie haben 'CommandText' von' DeleteCommand' nicht angezeigt. –

+0

Ich verwende nicht den Befehlstext. Ich lösche die aktuelle Zeile mit myrow.Delete() und commandbuider – NewPassionnate

Antwort

1

But today I have the error:
generated sql is not supported for multiple table delete row

What does that mean??

Da die Fehlermeldung sagt, kann die DbCommandBuilder nur automatisch generieren SQL für einzelne Tabellenabfragen. Dies macht es einfach, Apps zu implementieren, die Basistabellen wie Kunde, Produkt, Mitarbeiter usw. pflegen. Sie können für eine ähnliche Beziehung wie Customer-Order-OrderLines-ServiceItem verwendet werden, aber Sie müssen anders vorgehen.

Aber bevor Sie das tun wissen, dass es verschiedene Frameworks gibt, um zu helfen, diese Art von Sache für Sie zu implementieren und zu verwalten. Untersuchen Sie ORMs.


Da die DataAdapter kann nur eine Tabelle zu einem Zeitpunkt aktualisieren, werden Sie mehrere Adapter benötigen. Anstatt einen SQL-JOIN zu verwenden, können Sie die PK-FK-Beziehung definieren. Änderungen an übergeordneten Zeilen werden auf untergeordnete Elemente angewendet.

Für Demozwecke habe ich Tabellen geschickt Namen Parent, Child und SubChild. Eine übergeordnete Zeile kann viele untergeordnete Zeilen enthalten (1: m). Jedes Kind kann viele Subchild-Zeilen (1: m) haben.

// form/class level objects 
DataSet dsSample; 
OleDbDataAdapter daParent; 
OleDbDataAdapter daChild; 
OleDbDataAdapter daSubCh; 

An anderer Stelle konfigurieren, dass sie:

daParent = new OleDbDataAdapter("SELECT Id, Name, Lorem FROM Parent", 
    AceConnStr); 
dsSample.Tables.Add("Parent"); 

var cbP = new OleDbCommandBuilder(daParent); 
daParent.UpdateCommand = cbP.GetUpdateCommand(); 
daParent.InsertCommand = cbP.GetInsertCommand(); 
daParent.FillSchema(dsSample.Tables["Parent"], SchemaType.Source); 
daParent.Fill(dsSample.Tables["Parent"]); 


// repeat for Child - use care with copy-paste! 
daChild = new OleDbDataAdapter("SELECT Id, ParentId, Name, Lorem FROM Child", 
       AceConnStr); 
dsSample.Tables.Add("Child"); 

var cbS = new OleDbCommandBuilder(daChild); 
daChild.UpdateCommand = cbS.GetUpdateCommand(); 
daChild.InsertCommand = cbS.GetInsertCommand(); 
daChild.FillSchema(dsSample.Tables["Child"], SchemaType.Source); 
daChild.Fill(dsSample.Tables["Child"]); 

// do the same for the subchild adapter 
// omitted for brevity 
// ... 

// the PK cols 
DataColumn colParent = dsSample.Tables["Parent"].Columns["Id"]; 
DataColumn colChild = dsSample.Tables["Child"].Columns["Id"]; 


// set FK constraints, rules 
ForeignKeyConstraint fkParentChild = new ForeignKeyConstraint("ParentChild", 
      colParent, 
      dsSample.Tables["Child"].Columns["ParentId"]); 
fkParentChild.DeleteRule = Rule.Cascade; 
fkParentChild.UpdateRule = Rule.Cascade; 
fkParentChild.AcceptRejectRule = AcceptRejectRule.Cascade; 
dsSample.Tables["Child"].Constraints.Add(fkParentChild); 


// set FK constraints, rules for Child-SubChild 
ForeignKeyConstraint fkChildSub = new ForeignKeyConstraint("ChildSub", 
      colChild, 
      dsSample.Tables["SubChild"].Columns["ChildId"]); 
fkChildSub.DeleteRule = Rule.Cascade; 
fkChildSub.UpdateRule = Rule.Cascade; 
fkChildSub.AcceptRejectRule = AcceptRejectRule.Cascade; 
dsSample.Tables["SubChild"].Constraints.Add(fkChildSub); 

dsSample.EnforceConstraints = true; 

Wenn ein Elternteil Zeile gelöscht wird die zugehörigen untergeordneten Zeilen betroffen sein werden; Gleiches für Child-to-SubChild. Beachten Sie, dass selbst wenn Sie sich nicht für eine Art von ORM entscheiden, viele davon aufgeteilt und von Klassen behandelt werden können, die sich auf den Akteur beziehen. Zum Beispiel eine Room oder City Klasse, die dieses Datenbit behandelt.

Testen der Beziehung (en)

Eine Abfrage für die auf "ParentB" im Zusammenhang Reihen:

enter image description here

  • Es gibt 3 im Zusammenhang Kind Reihen (3 verschiedene Child.Ids)
  • Es gibt 4 SubChild Zeilen im Zusammenhang mit denen ChildRows
  • Wenn Sie möchten, zu de Code die Namen, ChildB1 ist die erste untergeordnete Zeile für ParentB; ChildB-1C bedeutet, dass das Subchild mit der ersten Childrow verknüpft ist, die sich auf ElternB bezieht. Das ist nicht so klar geworden, wie ich gedacht habe.

Test:

// delete ParentB 
var dr = dsSample.Tables["Parent"].Select("name = 'ParentB'")[0]; 
dr.Delete(); 

// if constraints work, there should be 
// multiple Child and SubChild rows affected 
var childChanges = dsSample.Tables["Child"].GetChanges(DataRowState.Deleted); 
var subChanges = dsSample.Tables["SubChild"].GetChanges(DataRowState.Deleted); 

Console.WriteLine("Child changes: {0}, subCh changes: {1}", 
         childChanges.Rows.Count, 
         subChanges.Rows.Count); 

Ergebnis:

Child changes: 3, subCh changes: 4

Perfect! Löschen einer einzelnen übergeordneten Zeile kaskadiert, um auch die 3 untergeordneten Zeilen zu löschen, die wiederum 4 untergeordnete Zeilen löschen. Achten Sie darauf, dass Zeilen auf jeder Ebene sind. Wenn es keine verknüpften Subchildzeilen gibt, erhalten Sie eine NulLReferenceException unter subChanges.Rows.Count.

Datenbank aktualisiert

Dies bringt die Änderungen bekommen und sie um die Anwendung. Normalerweise wendet DataAdapter alle Einfügungen, Aktualisierungen und Löschungen für Sie auf einmal an. Das wird nicht funktionieren ohne Einschränkungen zu verletzen, so einige Code verwenden, um die Änderungen anzuwenden, um:

// Assuming changes were applied on DS/DT rows, 
// changed rows should be duly marked, so just 
// run the updates 

// insert first 

DataTable parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Added); 
DataTable childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Added); 
DataTable subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Added); 

// dont Update the DS.Tables...it will try 
// to do ALL pending changes 
if (parentRows != null) 
    daParent.Update(parentRows); 

if (childRows != null) 
    daChild.Update(childRows); 

if (subChRows != null) 
    daSubCh.Update(subChRows); 

// then update..order doesnt matter 
parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Modified); 
childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Modified); 
subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Modified); 
if (parentRows != null) 
    daParent.Update(parentRows); 

if (childRows != null) 
    daChild.Update(childRows); 

if (subChRows != null) 
    daSubCh.Update(subChRows); 

// then deletes...in reverse order! 
parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Deleted); 
childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Deleted); 
subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Deleted); 
if (subChRows != null) 
    daSubCh.Update(subChRows); 

if (childRows != null) 
    daChild.Update(childRows); 

if (parentRows != null) 
    daParent.Update(parentRows); 

// our work is done...time for cheesecake 
dsSample.AcceptChanges(); 

Achten Sie darauf, Prozess löscht in umgekehrter Reihenfolge - subChild zunächst auf bis zu Eltern Reihen. Wenn alles wie vorgesehen funktioniert, sollte die Access-Abfrage aus, bevor jetzt leer sein:

enter image description here

et voilà!


Es ist nicht möglich, von dieser SQL zu sagen, was Sie tun (oder wenn die DB Vorbild ist auch richtig). Aber es ist zweifelhaft, dass Sie für jeden Tisch einen Adapter benötigen würden - einige sehen wie Lookups aus. In diesem Fall könnten sie Hilfsklassen/Objekte sein, die diesen Dienst bereitstellen.

Ressourcen

Verwandte Themen