7

Ich schreibe eine Datenbankanwendung mit Visual Studio 2012 mit Entity Framework 5 und SQL Server 2008. Ich möchte, dass Entity Framework einen SQL Server-Benutzer imitiert (dh Benutzer ohne Anmeldung). Ich habe einen neuen Konstruktor für den DB-Kontext MyDatabaseEntities erstellt, der ein Argument für den Namen des Benutzers enthält, der sich imitieren soll. Hier ist der Code, den ich geschrieben habe:Entity Framework 5 - Implementierung von SQL Server "Als Benutzer ausführen"

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(); 

      } 

     } 

    } 

Ich hatte die Kontrolle hinzufügen ...

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

... weil die Methode Connection_StateChange Methode auszuführen scheint, selbst wenn der Zustand hasn‘ t hat sich geändert. Dann Problem ist, dass, wenn ich den Code ausführen zweimal,

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

    } 

} 

... Entity Framework wirft ein SqlException:

ein schwerwiegender Fehler auf dem aktuellen Befehl. Die Ergebnisse, falls any, sollten verworfen werden. \ R \ nEin schwerwiegender Fehler ist beim aktuellen -Befehl aufgetreten. Die Ergebnisse, falls vorhanden, sollten verworfen werden.

Irgendwelche Ideen?

aktualisieren 1

ich in meinem Code oben, ich geändert ...

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

... bis ...

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

... und ich immer noch bekomme den gleichen SqlException Fehler.

+0

Das Problem ist, dass EF die Verbindung schließt, wenn sie es nicht benötigt, und es zurück in den Pool zurückgibt. Wenn es erneut SQL ausführt, fordert es eine neue Verbindung aus dem Pool an, in der Ihr Ereignis möglicherweise nicht initialisiert wird. –

+0

@LadislavMrnka Ja, Sie haben das Problem identifiziert. Ich denke, dass ich in der Verbindungszeichenfolge angeben muss, um Verbindungspooling nicht zu verwenden ... es ist eine Schande. Bitte erstellen Sie eine Antwort dafür (sagen Sie einfach, was Sie in dem Kommentar gesagt haben), damit ich Ihnen den Kredit geben kann. Vielen Dank! – HydroPowerDeveloper

+0

Sie sollten lieber versuchen, die Kontrolle über die Verbindung selbst zu übernehmen (indem Sie es an DbContext übergeben), aber es gab ein Problem damit: http://blogs.msdn.com/b/diego/archive/2012/01/26/exception -from-dbcontext-api-entityconnection-kann nur mit constructed-with-a-closed-dbconnection.aspx erstellt werden. –

Antwort

6

Das Problem besteht darin, dass EF die Verbindung schließt, wenn sie nicht benötigt wird, und sie an den Pool zurückgibt. Wenn es erneut SQL ausführt, fordert es eine neue Verbindung aus dem Pool an, in der Ihr Ereignis möglicherweise nicht initialisiert wird. Aber wieder glaube ich, dass Sie versuchen sollten, dies zu lösen, indem Sie die Verbindungslebensdauer manuell steuern, um sowohl den Vorteil des Verbindungspoolings zu haben als auch Ihre Anforderungen erfüllen zu können.

+0

Nochmals vielen Dank für Ihre Hilfe! – HydroPowerDeveloper

+0

BTW: Ich nehme Ihren Rat in Bezug auf die manuelle Kontrolle der Verbindungslaufzeit, um den Vorteil der Verbindung Pooling mit Identitätswechsel (der Link, den Sie bereitgestellt haben, ist sehr hilfreich). Ich denke, dass ich mit deinem Weg gehen werde. Ich aktualisiere meinen Code und poste ihn als ein weiteres Update. – HydroPowerDeveloper

1

Ich weiß, ist eine alte Frage, aber vielleicht wird es für jemanden nützlich sein.

ich in einer anderen Art und Weise haben, Ihr Code ...

Statt

Connection_StateChanged Ereignis

Ich schaffe zwei Methoden in der gleichen Klasse:

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

Ich benutze es vor und nach der gespeicherten Prozedur ausführen,

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

Es funktioniert gut mit SPs und es wirft keine Ausnahme auch nach vielen Ausführungen.Wenn ich ein Ereignis nach dem Ausführen des Befehls abfangen könnte, werden möglicherweise alle auf MyDatabaseEntities gekapselt.

Verwandte Themen