6

Sto utilizzando Entity Framework 5, il codice prima contro un database SQL 2005. Ho un repository, con un metodo che esegue una stored procedure - Il metodo ha questo aspetto;Entity framework 5 TSQL non compatibile con le stored procedure di chiamata di SQL 2005

public IEnumerable<PossibleDuplicateCustomer> GetPossibleDuplicates(Customer customer) 
    { 

     return DbContext.Database.SqlQuery<PossibleDuplicateCustomer>(
      "EXEC SearchPotentialDuplicates @CustomerId = {0}, @FirstName = {1}, @LastName = {2}, @dob = {3}", 
      customer.CustomerId, 
      customer.CustomerFirstName, 
      customer.CustomerLastName, 
      customer.Dob); 
    } 

Un'altra variante che ho provato è;

public IEnumerable<PossibleDuplicateCustomer> GetPossibleDuplicates(Customer customer) 
    { 
     return DbContext.Database.SqlQuery<PossibleDuplicateCustomer>(
      "SearchPotentialDuplicates @CustomerId, @FirstName, @LastName, @dob", 
      new SqlParameter("CustomerId", customer.CustomerId), 
      new SqlParameter("FirstName", customer.CustomerFirstName), 
      new SqlParameter("LastName", customer.CustomerLastName), 
      new SqlParameter("dob", customer.Dob)); 
    } 

Quando eseguo questo, ricevo un errore;

System.Data.SqlClient.SqlException (0x80131904): sintassi non corretta vicino a 'SearchPotentialDuplicates'.

Quindi ho afferrato lo sql generato utilizzando miniprofiler- che mi ha dato;

DECLARE @p0 int = 12644, 
    @p1 nvarchar(4) = N'adam', 
    @p2 nvarchar(3) = N'ant', 
    @p3 datetime = '1951-11-01T00:00:00' 

EXEC SearchPotentialDuplicates @CustomerId = @p0, @FirstName = @p1, @LastName = @p2, @dob = @p3 

ho provato a copiare e incollare questo in SQL Server Management Studio e ha dato un errore perché la sintassi di dichiarare e l'assegnazione in una linea non è supportato

Msg 139, Level 15, State 1, Line 0 
Cannot assign a default value to a local variable. 
Msg 137, Level 15, State 2, Line 6 
Must declare the scalar variable "@p0". 

Questo è un nuovo SQL 2008 cosa (http://blogs.microsoft.co.il/blogs/bursteg/archive/2007/12/05/sql-server-2008-t-sql-declare-and-set-in-the-same-statement.aspx) e non supporto in SQL 2005- Modifica della query a;

DECLARE @CustomerId int , 
    @FirstName nvarchar(25), 
    @LastName nvarchar(25) , 
    @dob datetime 

SET @CustomerId = 12645 
SET @FirstName = N'adam' 
SET @LastName = N'ant' 
SET @dob = '1951-11-01T00:00:00' 

exec SearchPotentialDuplicates @CustomerId, @FirstName, @LastName, @dob 

funziona bene! Quindi la mia domanda è: come mai la struttura dell'entità sta usando questa sintassi mentale? Ho fatto qualche ricerca su google e la gente parla di ProviderManifestToken, ma a quanto pare è necessario solo se si passa a una piattaforma totalmente diversa come sql ce, non tra le versioni sql. Quindi c'è un'impostazione che mi manca, o posso cambiare la query per forzarla ad eseguire in un modo diverso?

Grazie a tutti!

+0

Probabilmente, avrebbero potuto fornire supporto per SQL Server 2005 utilizzando la dichiarazione delle variabili vecchio stile, ma non chiamerei "sintassi mentale"; Penso che dovrebbe essere il modo preferito da tutti di dichiarare una variabile in T-SQL, a patto che tu non stia bersagliando qualcosa di più vecchio di SQL Server 2008. –

+1

haha ​​sì, non fraintendermi - è sicuramente la sintassi più pulita più ordinata- È mi ha sempre infastidito il fatto di dover dividere la dichiarazione/assegnazione su due righe! Ma è solo meglio se la piattaforma di destinazione lo supporta! – Shawson

+1

Che ne dici di ADO.Net e SqlCommand? Puoi scrivere un wrapper per chiamare proc memorizzati utilizzando questo approccio. So che è vecchio metodo e non risponde alla tua domanda, ma può risolvere il tuo problema. –

risposta

2

Finalmente ho funzionato- Ho provato a seguire questo articolo http://blog.oneunicorn.com/2012/04/21/code-first-building-blocks/ (di Arthur Vickers sul team di framework di entità) per dire a DbContext di usare la sintassi sql 2005- Quindi quando costruisco il contesto lo faccio;

var builder = new DbModelBuilder(); 
builder.Entity<PossibleDuplicateCustomer>(); 
var model = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2005")); 
_compiledSql2005Model = model.Compile(); 

// OverdriveDbContext : DbContext 
var context = new OverdriveDbContext(
    nameOrConnectionString: "OverdriveConnectionString", 
    model: _compiledSql2005Model); 

Questo ora esegue il seguente SQL;

exec sp_executesql N'EXEC SearchPotentialDuplicates @CustomerId, @FirstName, @LastName, @dob',N'@CustomerId int,@FirstName nvarchar(4),@LastName nvarchar(3),@dob datetime',@CustomerId=12645,@FirstName=N'adam',@LastName=N'ant',@dob='1951-11-01 00:00:00' 

che funziona perfettamente in SQL 2005. Una parola di cautela però - MiniProfiler (che sto usando per monitorare le chiamate Entity Framework) mostra in modo errato lo sql eseguito come:

DECLARE @CustomerId int = 12645, 
    @FirstName nvarchar(4) = N'adam', 
    @LastName nvarchar(3) = N'ant', 
    @dob datetime = '1951-11-01T00:00:00' 

EXEC SearchPotentialDuplicates @CustomerId, @FirstName, @LastName, @dob 

che mi ha fermato notando che avevo riparato questo per un paio d'ore! Quindi la lezione che c'è sul monitoraggio SQL di MiniProfiler non è un sostituto del buon vecchio Sql Profiler!