2008-11-13 16 views
12

Estoy usando LINQ-to-SQL para una aplicación que consulta una base de datos heredada. Necesito llamar a un procedimiento almacenado, que selecciona un único valor entero. Cambiar el procedimiento almacenado no es una opción.LINQ-to-SQL: ¿Procedimiento almacenado que devuelve un único valor escalar?

el diseñador crea un método con esta firma:

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

me gusta el tipo de retorno para ser int. ¿Cómo hago esto usando LINQ-to-SQL?

Respuesta

13

Esto sería trivial con una función escalar (UDF) en lugar de un SP. Sin embargo, debería funcionar con bastante facilidad, aunque si el SP es complejo (es decir, FMT_ONLY no puede inspeccionarlo al 100%), es posible que necesite "ayudarlo" ...

Aquí hay algunos dbml que generé de un simplfied SP que devuelve un entero; puede editar el dbml vía "abierta editor con ... 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> 

(tenga en cuenta que, obviamente, tiene que modificar los nombres y tipos de datos)

y aquí está la generada 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 el SP actual utiliza SELECT (en lugar de RETURN), entonces el DBML tendrá que reflejar esto se puede solucionar este problema al ocultar los detalles de implementación, y proporcionar un envoltorio público en una clase parcial, por ejemplo:

<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> 

Lo anterior describe un SP que devuelve una sola tabla con una sola columna; pero me he tomado la SP "privado" a los datos de contexto, y el tipo de resultado "interno" a la asamblea (ocultarlo):

[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)); 
} 

ahora en mi propio archivo de clase puedo añadir una nueva clase parcial (un nuevo archivo .cs) en el espacio de nombre correcto que expone el método más conveniente:

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

(el espacio de nombres y nombres de contexto tienen que ser los mismos que los datos del contexto real). Esto agrega un método público que oculta los detalles grungy de la persona que llama.

No edite el archivo designer.cs directamente; tus cambios se perderán Solo edite el dbml o las clases parciales.

+0

Exactamente lo que estaba buscando. Gracias. – driis

+0

@driss - si tiene problemas con SELECT, hágamelo saber –

+0

He utilizado la misma técnica en mi proyecto anteriormente. Funciona muy bien ... Hasta que edites tu DBML en el editor de alguna manera. Todos sus cambios serán sobrescritos. Solía ​​guardar un archivo xml separado cada vez que hacía modificaciones manuales, pero espero que haya una manera mejor de alguna manera. –

5

RETURN @VALUE como la última instrucción del proc.

luego detectará automáticamente el tipo int, string, bool, etc. y generará el método de envoltura en consecuencia.

+0

Esto funciona para mí. ¡Gracias! –

+1

+1 El valor devuelto debe provenir de una variable escalar, por lo que 'RETURN SELECT COUNT (*) FROM table' y 1RETURN SELECT @Value = COUNT (*) FROM table1 no funcionará pero' RETURN @ Value' lo hará. Además, MS SQL/LINQ to SQL no parece ser compatible con los tipos de retorno tinyint/byte. – Trisped

0

Si está utilizando el archivo .xsd de Visual Studio en un proyecto LINQ a clases de SQL, asegúrese de que:

  1. derecha haga clic en el procedimiento almacenado o una llamada a la función en el adaptador.
  2. Seleccione Propiedades
  3. Cambio ejecute el modo de escalares

que hará que su adaptador de tipo de retorno a la función "objeto". Luego debes convertirlo a int o string, o al tipo que sea.

Cuestiones relacionadas