Le problème est avec SSDT (SQL Server Data Tools) et non avec SQLCLR. Oui, SQLCLR prend en charge DATETIME2
via DateTime?
/Nullable<DateTime>
. Malheureusement, SSDT (j'utilise VS2013 et SSDT v 12.0.50512.0) ne pas encore (je suis optimiste ici, je sais) soutenir inférer DATETIME2
à partir de DateTime
ou DateTime?
. Mais, il ne se trompe pas non plus en utilisant DateTime?
comme il le faisait. Toutefois, DateTime
ou DateTime?
s'afficheront comme un DATETIME
normal dans le SQL généré.
Je ne suis pas sûr de tout vraiment moyen « approprié » de dire SSDT quel doit être le type de données. Il existe en réalité un certain nombre d'options qui ne sont pas prises en charge, y compris les options UDF générales telles que WITH RETURNS NULL ON NULL INPUT
et les options de paramètres telles que les valeurs par défaut. C'est triste et frustrant, oui.
Le meilleur que je suis venu avec à ce jour (et je suis toujours à la recherche d'autres options) est d'ajouter un script après le déploiement à ALTER
la définition de la fonction avec les options souhaitées:
- Dans le Menu du projet, sélectionnez Ajouter un nouvel élément ... (contrôle + Maj +A dans VS2013)
- Aller à SQL Server - > Scripts utilisateur
- Sélectionnez Script post-déploiement
- Donnez-lui un nom (le nom lui-même ne détermine pas si elle est pré-deploy, post-deploy, ou non plus; il doit juste se terminer par .sql) et cliquez sur Ajouter
- Vous serez placé dans une (la plupart du temps) script SQL vide
Entrez dans un ou plusieurs ALTER
déclarations, semblable à ce qui suit:
-- declare once
DECLARE @ObjectName sysname; -- keep lower-case to work in case-sensitive collations
SET @ObjectName = N'Test';
IF (EXISTS(
SELECT *
FROM sys.assembly_modules sam
WHERE sam.[object_id] = OBJECT_ID(@ObjectName)
)
)
BEGIN
PRINT 'Checking custom properties for [' + @ObjectName + N']...';
IF (EXISTS(
SELECT *
FROM sys.parameters sp
INNER JOIN sys.types st
ON st.system_type_id = sp.system_type_id
WHERE sp.[object_id] = OBJECT_ID(@ObjectName)
AND st.[name] <> N'datetime2' -- keep lower-case to work in
-- case-sensitive collations
)
)
BEGIN
PRINT 'Setting custom properties for [' + @ObjectName + N']...';
BEGIN TRY
EXEC('
ALTER FUNCTION [dbo].[Test](@d [datetime2])
RETURNS [datetime2] WITH EXECUTE AS CALLER
AS EXTERNAL NAME [Test].[Test.UserDefinedFunctions].[Test];
');
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
SET @ErrorMessage = ERROR_MESSAGE();
RAISERROR(@ErrorMessage, 16, 1);
RETURN;
END CATCH;
END;
END;
ELSE
BEGIN
RAISERROR(N'Oops. [%s] was renamed or no longer exists!', 16, 1, @ObjectName);
RETURN;
END;
---
SET @ObjectName = N'NextObjectToFix';
-- copy the rest from above
Ce script post-déploiement sera toujours être inclus à la fin des scripts de génération _Create
et de publication/incrémentielle. D'où la logique supplémentaire de voir si les changements sont déjà présents ou non. Vrai, généralement ne fait pas de mal à toujours exécuter le ALTER
, mais dans les rares cas où cet objet est une dépendance de quelque chose d'autre, comme une contrainte de vérification ou une colonne calculée, il est probablement préférable de le laisser seul sauf doit changer.
Vous pouvez obtenir la définition ALTER
appropriée soit à partir du script \bin\Configuration\*_Create.sql
(juste changer le CREATE
-ALTER
), ou SSMS si vous faites un clic droit sur l'objet et sélectionnez Modifier . Dans les deux cas, changez le type de données et toutes les autres options (évidemment ;-).
Un autre, un peu lié, idée est de tout simplement pas compter sur le processus d'édition Visual Studio/SSDT pour l'objet wrapper T-SQL CREATE
déclarations, et ne l'utiliser que pour gérer l'ensemble. Dans cette configuration, vous un -check l'option Générer sur le DDL SQLCLR onglet de Propriétés du projet. Ensuite, vous ajouteriez un script Post Deployment (comme indiqué dans la suggestion ci-dessus) et ajouteriez vos propres instructions CREATE FUNCTION ...
, CREATE PROCEDURE ...
, etc. Pour le développement initial, ce n'est pas aussi simple et rapide d'introduire un nouvel objet que d'utiliser SSDT pour générer ce DDL, mais étant donné que les nouveaux objets ne sont pas créés très souvent, et que leurs signatures sont modifiées beaucoup moins fréquemment. ce DDL vous-même n'est vraiment pas si mauvais (et en fait, il est très similaire au processus que j'utilise pour ma bibliothèque SQL# qui a plus de 250 objets.Pratiquement parlant, une fois que vous avez une instruction de chaque type d'objet CREATE
, vous pouvez Il suffit de les copier et les coller pour de nouveaux objets et de changer les noms et les paramètres, etc. Le plus de travail que cette approche nécessite est de créer un nouveau TVF s'il renvoie un tas de champs, mais ce n'est pas vraiment beaucoup de travail étant donné avoir à entrer dans le même dans la TableDefinition
propriété de la SqlFunction
attr Ibute de toute façon si vous utilisiez SSDT pour gérer la création DDL.
Je crois que SQLDateTime a la plus haute résolution dans les versions .NET plus récentes. Avez-vous essayé cela? –
Désolé, mon commentaire ci-dessus n'est pas vrai: http://msdn.microsoft.com/fr-fr/library/system.data.sqltypes.sqldatetime(v=vs.110).aspx –
Jason: Je me rends compte qu'il a été quelques années, mais juste au cas où vous cherchiez encore de l'aide à ce sujet, je viens de poster une réponse :-). –