2013-07-30 2 views
5

Diese Abfrage, wenn auf ADO.net lief mit MissingSchemaAction.AddWithKey wirft Ausnahme:ADO.net SQL Server 2012 - Abfrage mit zusammengesetzten Schlüsseln und MissingSchemaAction.AddWithKey falsch Einschränkung fügt

Fehler beim Aktivieren. Eine oder mehrere Zeilen enthalten Werte, die Nicht-Null-, eindeutige oder Fremdschlüsselbeschränkungen verletzen.

Abfrage:

SELECT map.GroupId, b.PersonId 
FROM [GroupPersonMap] as map 
INNER JOIN [Person] AS b ON b.PersonId = map.PersonId 
GROUP BY map.GroupId, b.PersonId 

Inspizieren Einheimischen zeigt, dass eine eindeutige Einschränkung für PersonId hinzugefügt wurde. Nicht nur das, aber das Ausführen derselben Abfrage in SQL Server Manager gibt eine Ergebnismenge ohne Warnungen oder Fehler zurück. Dieser genaue Code wurde für SQL Server 2005 verwendet. Wenn Sie diese Abfrage in SQL Server 2005 ausführen, erstellt die Abfrage in ADO.net ordnungsgemäß eine zusammengesetzte Integritätsbedingung. Ist das ein Upgrade-Problem?

Als eine Randnotiz, weiß ich, dass die Einstellung EnforceConstraints = false eine Problemumgehung bietet. Idealerweise möchte ich dieses Problem an der Wurzel lösen.

-Setup zu reproduzieren:

CREATE TABLE [GroupPersonMap] 
(
[GroupId] [int] NOT NULL, 
[PersonId] [int] NOT NULL 
) ON [PRIMARY] 
GO 
ALTER TABLE [GroupPersonMap] ADD CONSTRAINT [PK_GroupPersonMAP] PRIMARY KEY CLUSTERED ([GroupId], [PersonId]) 

CREATE TABLE [Person] 
(
[PersonId] [int] NOT NULL IDENTITY(1, 1), 
[Val] INT 
) ON [PRIMARY] 
GO 
ALTER TABLE [Person] ADD CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([PersonId]) 

Dann Einfügen Werte:

INSERT INTO [GroupPersonMap] 
SELECT 1, 1 
UNION ALL 
SELECT 2, 1 

INSERT INTO [Person] 
SELECT 1 
+1

An welchem ​​Punkt tritt diese Fehlermeldung auf? Nach dem 2. Einsatz? – Codeman

Antwort

2

Sie können einige hilfreiche Debugging-Tipps in diesem Beitrag finden:

Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints

Das heißt, die Das erste, was mich an dieser Stelle herausspringt, ist, dass alle deine beitreten d Gruppierung sind nicht notwendig. Sie haben

geschrieben
SELECT map.GroupId, b.PersonId 
FROM [GroupPersonMap] as map 
INNER JOIN [Person] AS b ON b.PersonId = map.PersonId 
GROUP BY map.GroupId, b.PersonId 

aber man konnte die identische Ergebnisse mit

SELECT * FROM GroupPersonMap 

Hier ist, was ich meine:

1) Sie sind nicht alle Felder aus Tabelle b (Person) außer b Auswahl .PersonId. Aber Sie wissen aus Ihrer JOIN-Klausel, dass die Werte von b.PersonId gleich map.PersonId sein müssen, so dass keine Informationen von Person kommen, die nicht bereits in GroupPersonMap enthalten sind. So können wir das JOIN Streifen aus:

SELECT map.GroupId, map.PersonId 
FROM [GroupPersonMap] as map 
GROUP BY map.GroupId, map.PersonId 

2) Aber jetzt, map.GroupId, map.PersonId ist die genaue Primärschlüssel der Tabelle, so dass wir wissen, dass keine tatsächliche Aggregation jede Kombination von GroupId/PersonId occur-- wird, ist einzigartig per Definition. So wird jede Zeile der Eingabe zu einer und nur einer Ausgabezeile "gruppiert". Dies bedeutet, dass wir auch die GROUP BY-Klausel Streifen aus können:

SELECT map.GroupId, map.PersonId 
FROM [GroupPersonMap] as map 

3) Und nun, was wir in der SELECT-Klausel ist zur map.GroupId, map.PersonId - das ist alle Felder in der Tabelle. Sie können also noch weiter vereinfachen, indem Sie einfach "SELECT * FROM GroupPersonMap" auswählen. In der Praxis für Produktionscode ist es jedoch am besten, die gewünschten Felder immer aufzulisten. (Indem Sie genau angeben, was Sie wollen, werden Sie vor späteren Schemaänderungen geschützt.)

Noch eine Anmerkung zu Ihrem JOIN, wie es ist: Wenn Sie eine Tabelle auf ihrem Primärschlüssel verbinden, möchten Sie idealerweise auf dem vollständigen Schlüssel beitreten. (Dies ist die "erste Ordnung" der berühmten "dritten Normalform".) Wenn eine Tabelle einen zusammengesetzten Schlüssel aufweist, bedeutet dies, dass für jedes Feld in dem Schlüssel JOIN- und/oder WHERE-Kriterien enthalten sind. Andernfalls können Sie mit einem semikartesischen Join oder, in Fällen wie diesem, möglichen Problemen enden, bei denen die andere Hälfte des Primärschlüssels nicht angegeben ist. Ich würde schätzen, wenn Sie Ihre Abfrage so lassen möchten, wie sie ist, aber Ihren Fehler immer noch beseitigen, indem Sie einfach sagen, an welcher Gruppe Sie interessiert sind (z. B. WHERE map.GroupId = xxxx). Wenn Sie wirklich eine Liste von allem wollen, dann würde ich sagen, ein vereinfachtes Re-Write ohne die unnötige JOINing und GROUPE wäre Ihre beste erste Angriffslinie.