Wrong inferred constraint on composite primary key with a default

Ouverte
#283 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
35/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
À l'abandon
Stack technique
fsharp, sql
Domaine
databases

Piste de recherche

Reproduisez le schéma et les appels à AddRow de l’issue, puis examinez la gestion des contraintes autour de src/SqlClient/DataTable.fs:line 29 ainsi que l’inférence des métadonnées du Type-Provider. Déterminez pourquoi la clé primaire composite omet k3 lorsque cette colonne possède une valeur par défaut. Le travail est terminé lorsque la contrainte inférée contient k1, k2 et k3 et que les appels répétés à AddRow réussissent.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

bug
Description

If a table has a composite primary key with a default constraint on one of the columns, the generated constraint is wrong, leading to ConstraintException errors.

Repro steps

Let's define a table with a composite constraint, such as:

create table test.tbl(
  k1 uniqueidentifier not null, 
  k2 uniqueidentifier not null, 
  k3 uniqueidentifier not null default NEWID(), 
  v DOUBLE PRECISION,
PRIMARY KEY(k1, k2, k3))

Then define the ProgrammabilityProvider and a couple of fixed values:

type DB = SqlProgrammabilityProvider<ConnectionString>

let k1 = Guid.NewGuid()
let k2 = Guid.NewGuid()
Expected behavior

The following code should work (it does if I remove the default from k3 ):

let t = new DB.test.Tables.tbl()
t.AddRow(k1=k1, k2=k2, k3=Guid.NewGuid(), v=Some 1.0)
t.AddRow(k1=k1, k2=k2, k3=Guid.NewGuid(), v=Some 2.0)
t.AddRow(k1=k1, k2=k2, k3=Guid.NewGuid(), v=Some 3.0)

t.Constraints
> 
val it : Data.ConstraintCollection =
  seq [Constraint1 {Columns = [|k1; k2; k3|];
                    ConstraintName = "Constraint1";
                    ExtendedProperties = dict [];
                    IsPrimaryKey = true;
                    Table = [test].[tbl2];}]
Actual behavior

Since it have a default value, the type of k3 becomes Option<>, which means that the AddRow calls should be written as:

t.AddRow(k1=k1, k2=k2, k3=Some(Guid.NewGuid()), v=Some 1.0)
t.AddRow(k1=k1, k2=k2, k3=Some(Guid.NewGuid()), v=Some 2.0)

But on the second AddRow an exception is raised:


> 
System.Data.ConstraintException: Column 'k1, k2' is constrained to be unique.  Value '39477bbb-7256-4477-97de-54fb06458c27, dc74a8e9-38fe-41c8-bb63-168c3ee75ca7' is already present.
   at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action)
   at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent)
   at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean suppressEnsurePropertyChanged, Int32 position, Boolean fireEvent, Exception& deferredException)
   at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID, Int32 pos, Boolean fireEvent)
   at <StartupCode$FSharp-Data-SqlClient>[email protected]`1-Add(T item) in C:\Users\dmitry\Documents\GitHub\FSharp.Data.SqlClient\src\SqlClient\DataTable.fs:line 29
   at <StartupCode$FSI_0038>.$FSI_0038.main@() in C:\Users\myuser\Projects\MyProject\Scripts\scratch.fsx:line 60
Stopped due to error

this is because the primary key constraint isn't inferred correctly:

val it : Data.ConstraintCollection =
  seq [Constraint1 {Columns = [|k1; k2|];
                    ConstraintName = "Constraint1";
                    ExtendedProperties = dict [];
                    IsPrimaryKey = true;
                    Table = [test].[tbl];}]

k3 is missing, I guess because of an ambiguity between None values due to column nullability vs due to the presence of a default value.

Known workarounds

The only workaround I found is to remove the default constraint, such as:

DECLARE @constraintName AS VARCHAR(1024) = (
SELECT d.name
FROM sys.default_constraints d
JOIN sys.schemas s ON d.schema_id=s.schema_id
JOIN sys.tables t ON d.parent_object_id=t.object_id
JOIN sys.columns c ON t.object_id=c.object_id AND d.parent_column_id=c.column_id
WHERE s.name='test' AND t.name='tbl' AND c.name='k3' AND d.type='D')

DECLARE @statement AS VARCHAR(1024) = 'ALTER TABLE test.tbl DROP CONSTRAINT ' + @constraintName 

EXECUTE(@statement)

GO
Related information
  • FSharp.Data.SqlClient package 1.8.2 (Latest stable package on nuget.org)
  • Windows 10 1703
  • SQL Server 14.0
  • .NET framework 4.7.1, F# runtime 4.4.3.0
  • Visual Studio 2017 (15.6.4)
Langage dominant
F#
Étoiles
206
Forks
65
Métriques de merge des PR
Aucune PR mergée en 30 j

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de fsprojects/FSharp.Data.SqlClient

Toutes les issues de fsprojects/FSharp.Data.SqlClient

Issues similaires

Plus d'issues Databases

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.