7

Sto scrivendo un'applicazione di database utilizzando Visual Studio 2012 con Entity Framework 5 e SQL Server 2008. Vorrei che Entity Framework impersonasse un utente di SQL Server (es. accesso). Ho creato un nuovo costruttore per il contesto DB MyDatabaseEntities che include un argomento per il nome dell'utente da impersonare. Ecco il codice che ho scritto:Entity Framework 5 - Implementazione di SQL Server "Esegui come utente"

public partial class MyDatabaseEntities 
{ 
    private String _impersonateUser = null; 

    public MyDatabaseEntities(String impersonateUser) 
     : base("MyConnectionString") 
    { 
     _impersonateUser = impersonateUser; 

     this.Database.Connection.StateChange += Connection_StateChange; 

    } 

    void Connection_StateChange(object sender, StateChangeEventArgs e) 
    { 
     if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open) 
     { 
      using (var cmd = this.Database.Connection.CreateCommand()) 
      { 
       cmd.CommandType = CommandType.Text; 

       cmd.Parameters.Add(new SqlParameter("user", _impersonateUser)); 

       cmd.CommandText = "EXECUTE AS USER = @user"; 

       cmd.ExecuteNonQuery(); 

      } 

     } 

    } 

ho dovuto aggiungere l'assegno ...

if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open) 

... perché il metodo metodo di Connection_StateChange sembra per eseguire anche quando lo stato hasn' t cambiato. Poi problema è che quando faccio funzionare il codice due volte,

public void RunSimpleQuery() 
{ 
    using (MyDatabaseEntities context = new MyDatabaseEntities("UserName")) 
    { 
     var result = context.TableName.ToList(); 

    } 

} 

... Entity Framework getta un SqlException:

Un grave errore durante il comando corrente. I risultati, se , devono essere eliminati. \ R \ nSi è verificato un grave errore nel comando corrente . I risultati, se presenti, dovrebbero essere scartati.

Qualche idea?

Aggiornamento 1

ho nel mio codice di cui sopra, ho cambiato ...

cmd.CommandText = "EXECUTE AS USER = @user;"; 

... al ...

cmd.CommandText = "REVERT; EXECUTE AS USER = @user;"; 

... e io ancora ottenere lo stesso errore SqlException.

+0

Il problema è che EF chiude la connessione quando non ne ha bisogno e la restituisce al pool. Quindi, quando esegue nuovamente SQL, richiede una nuova connessione dal pool in cui il tuo evento potrebbe non essere inizializzato. –

+0

@LadislavMrnka Sì, hai identificato il problema. Immagino che dovrò specificare nella stringa di connessione di non usare il pool di connessioni ... è un peccato. Si prega di creare una risposta per questo (basta dire quello che hai detto nel commento) così posso darti il ​​merito. Grazie! – HydroPowerDeveloper

+0

Dovresti provare a prendere il controllo della connessione da te stesso (passando a DbContext) ma c'era qualche problema con questo: http://blogs.msdn.com/b/diego/archive/2012/01/26/exception -da-DbContext-api-EntityConnection-può solo essere-costruito-con-un-chiuso dbconnection.aspx. –

risposta

6

Il problema è che EF chiude la connessione quando non ne ha bisogno e la restituisce al pool. Quindi, quando esegue nuovamente SQL, richiede una nuova connessione dal pool in cui il tuo evento potrebbe non essere inizializzato. Ma ancora una volta credo che dovresti cercare di risolvere questo problema controllando manualmente la durata della connessione per avere entrambi i vantaggi del pool di connessioni e essere in grado di soddisfare le tue esigenze.

+0

Grazie ancora per tutto il tuo aiuto! – HydroPowerDeveloper

+0

BTW: Prendo il tuo consiglio per quanto riguarda il controllo manuale della durata della connessione per avere il vantaggio del collegamento della connessione con la rappresentazione (il collegamento che hai fornito è molto utile). Penso che vado con la tua strada. Aggiornerò il mio codice e lo posterò come un altro aggiornamento. – HydroPowerDeveloper

1

So che è una vecchia domanda, ma forse sarà utile per qualcuno.

ho fatto in un modo diverso, utilizzando il codice ...

Invece di

evento Connection_StateChanged

creo due metodi nella stessa classe:

public void ChangeUser(String sUser) 
    { 
     if(Database.Connection.State != ConnectionState.Open) 
      Database.Connection.Open(); 

     using (var cmd = Database.Connection.CreateCommand()) 
     { 
      cmd.CommandType = CommandType.Text; 
      cmd.Parameters.Add(new SqlParameter("user", sUser)); 
      cmd.CommandText = "EXECUTE AS USER = @user;"; 
      cmd.ExecuteNonQuery(); 
     } 
    } 

    public void Revert() 
    { 
     if (Database.Connection.State != ConnectionState.Open) 
      Database.Connection.Open(); 

     using (var cmd = Database.Connection.CreateCommand()) 
     { 
      cmd.CommandType = CommandType.Text; 
      cmd.CommandText = "REVERT;"; 
      cmd.ExecuteNonQuery(); 
     } 
    } 

Io lo uso prima e dopo l'esecuzione della stored procedure,

using (var db = new MyDatabaseEntities()) 
     { 
      db.ChangeUser(model.Username); 
      var result = db.Something(); 
      db.Revert(); 
      return result; 
     } 

Funziona bene con SP e non genera eccezioni anche dopo molte esecuzioni.Se riesco a catturare un evento dopo l'esecuzione del comando, forse tutto verrà incapsulato su MyDatabaseEntities.