2008-11-13 10 views
12

J'utilise LINQ-to-SQL pour une application qui interroge une base de données existante. J'ai besoin d'appeler une procédure stockée, qui sélectionne une seule valeur entière. Changer la procédure stockée n'est pas une option.LINQ-to-SQL: procédure stockée qui renvoie une seule valeur scalaire?

Le concepteur crée une méthode avec cette signature:

private ISingleResult<sp_xal_seqnoResult> NextRowNumber([Parameter(DbType="Int")] System.Nullable<int> increment, [Parameter(DbType="Char(3)")] string dataset) 

Je voudrais que le type de retour pour être int. Comment faire cela en utilisant LINQ-to-SQL?

Répondre

13

Cela serait trivial avec une fonction scalaire (UDF) plutôt qu'avec un SP. Cependant, cela devrait fonctionner assez facilement - bien que si le SP est complexe (ie FMT_ONLY ne peut pas l'inspecter à 100%) alors vous devrez peut-être "l'aider" ...

Voici un dbml que j'ai généré à partir d'un simplfied SP qui renvoie un entier; vous pouvez modifier le dbml via « ouvrir avec ... éditeur xml).

<Function Name="dbo.foo" Method="foo"> 
    <Parameter Name="inc" Type="System.Int32" DbType="Int" /> 
    <Parameter Name="dataset" Type="System.String" DbType="VarChar(20)" /> 
    <Return Type="System.Int32" /> 
</Function> 

(notez que vous devez évidemment modifier les noms et les données-types)

Et voici le produit C#:

.
[Function(Name="dbo.foo")] 
public int foo([Parameter(DbType="Int")] System.Nullable<int> inc, [Parameter(DbType="VarChar(20)")] string dataset) 
{ 
    IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), inc, dataset); 
    return ((int)(result.ReturnValue)); 
} 

Si votre utilise le courant SP SELECT (au lieu de RETURN), le DBML devra refléter cela, vous pouvez résoudre ce problème en se cachant les détails de mise en œuvre et la fourniture d'une enveloppe publique dans une classe partielle, par exemple:

<Function Name="dbo.foo" Method="FooPrivate" AccessModifier="Private"> 
    <Parameter Name="inc" Type="System.Int32" DbType="Int" /> 
    <Parameter Name="dataset" Type="System.String" DbType="VarChar(20)" /> 
    <ElementType Name="fooResult" AccessModifier="Internal"> 
     <Column Name="value" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" /> 
    </ElementType> 
</Function> 

Ce qui précède décrit un SP qui retourne une seule table avec une seule colonne; mais je l'ai fait le SP « privé » aux données contexte, et le type de résultat « interne » à l'assemblée (cacher):

[Function(Name="dbo.foo")] 
private ISingleResult<fooResult> FooPrivate(
    [Parameter(DbType="Int")] System.Nullable<int> inc, 
    [Parameter(DbType="VarChar(20)")] string dataset) 
{ 
    IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), inc, dataset); 
    return ((ISingleResult<fooResult>)(result.ReturnValue)); 
} 

Maintenant dans mon propre fichier de classe je peux ajouter une nouvelle classe partielle (un nouveau fichier .cs) dans l'espace de noms correct, qui expose la méthode plus pratique:

namespace MyNamespace { 
    partial class MyDataContext 
    { 
     public int Foo(int? inc, string dataSet) 
     { 
      return FooPrivate(inc, dataSet).Single().value; 
     } 
    } 
} 

(l'espace de noms et les noms de contexte doivent être les mêmes que les données contexte réel). Cela ajoute une méthode publique qui cache les détails grungy de l'appelant.

Ne pas modifier le fichier designer.cs directement; vos changements seront perdus. Éditez seulement les classes dbml ou partielles.

+0

Exactement ce que je cherchais. Merci. – driis

+0

@driss - si vous rencontrez des problèmes avec SELECT, faites le moi savoir –

+0

J'ai déjà utilisé la même technique dans mon projet. Cela fonctionne très bien .. Jusqu'à ce que vous modifiez votre DBML dans l'éditeur en quelque sorte. Tous vos changements seront écrasés. J'avais l'habitude de garder un fichier xml séparé chaque fois que je faisais des modifications manuelles, mais j'espère qu'il y a un meilleur moyen de quelque façon. –

5

RETURN @VALUE comme dernière instruction de la proc.

puis il détecte automatiquement le type int, string, bool etc et génère la méthode wrapper en conséquence.

+0

Cela fonctionne pour moi. Merci! –

+1

+1 La valeur renvoyée doit provenir d'une variable scalaire, ainsi 'RETURN SELECT COUNT (*) FROM table' et 1RETURN SELECT @Value = COUNT (*) FROM table1 ne fonctionnera pas mais' RETURN @ Value' sera activé. En outre, MS SQL/LINQ to SQL ne semble pas prendre en charge les types de retour tinyint/byte. – Trisped

0

Si vous utilisez fichier .xsd de Visual Studio dans un projet LINQ to SQL classes, assurez-vous:

  1. cliquez droit sur la procédure stockée ou appel de fonction dans l'adaptateur.
  2. Sélectionnez Propriétés
  3. Modifier Exécuter le mode de Scalar

Cela fera votre type fonction d'adaptateur de retour à "Objet". Vous devez ensuite le convertir en int ou string, ou tout autre type qu'il devrait être.

Questions connexes