| 

.NET C# Java Javascript Exception

2
Hallo!

Dies ist mein erstes Projekt mit dem Entity Framework und schon habe ich ein riesiges Problem. Ich habe mir eine Testdatenbank angelegt und im Visual Studio mit das Entity Framework Model generieren lassen. Dabei hat er natürlich den Connectionstring in der App.config hinterlegt. Das Programm soll aber beim Konden laufen und dementsprechend auch auf einem anderen DB-Server. Jetzt habe ich mir aus der MSDN ein Beispiel rausgesucht, wie ich den Connectionstring ändern kann und es auf meine Bedürfnisse angepaßt. Das sieht so aus:

strDBServer = objReg.Read("DBServer");
strDBName = objReg.Read("DBName");

objLog.d(TAG, "Anfang DBInit");

// Specify the provider name, server and database.
string providerName = "System.Data.SqlClient";

// Initialize the connection string builder for the
// underlying provider.
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();

// Set the properties for the data source.
sqlBuilder.DataSource = strDBServer;
sqlBuilder.InitialCatalog = strDBName;
sqlBuilder.IntegratedSecurity = true;
sqlBuilder.ConnectTimeout = 30;

// Build the SqlConnection connection string.
string providerString = sqlBuilder.ToString();

// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();

//Set the provider name.
entityBuilder.Provider = providerName;

// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;

// Set the Metadata location.
entityBuilder.Metadata = @"res://*/WorktimeTrackerDB.csdl|
res://*/WorktimeTrackerDB.ssdl|
res://*/WorktimeTrackerDB.msl";
//Console.WriteLine(entityBuilder.ToString());

EntityConnection conn = new EntityConnection(entityBuilder.ToString());
//conn.Open();
context.Database.Connection.ConnectionString = conn.ConnectionString;
context = new WorktimeTrackerDBContainer();

objLog.d(TAG, "DBServer neu: " + context.Database.Connection.DataSource);
objLog.d(TAG, "DBName neu: " + context.Database.Connection.Database);

objLog.d(TAG, "Verbinding ist " + context.Database.Connection.State);


Aber scheinbar öffnet er die neue Verbindung nicht und die Logausgaben werden auch nicht ausgeführt.

Wie kann ich an einfachsten den neuen Server ansprechen?
News:
11.02.2015
tschroeer 35 4
5 Antworten
1
Was Du suchst findest Du hier:
Changing Databases at Run-time using Entity Framework

Dieser Code funktioniert, nutze es selber, mit dem EF ab Version 5.x
17.02.2015
JEwen 2,7k 5
Ok, das werde ich bei nächster Gelegenheit mal testen. Jetzt habe ich leider erst eine andere Baustelle
tschroeer 17.02.2015
0
Hier eine kleine Korrektur von mir. Jetzt versucht er zumindest sich mit der DB zu verbinden , aber es klappt nicht.

strDBServer = objReg.Read("DBServer");
strDBName = objReg.Read("DBName");

objLog.d(TAG, "Anfang DBInit");
context = new WorktimeTrackerDBContainer();
objLog.d(TAG, "DBServer alt: " + context.Database.Connection.DataSource);
objLog.d(TAG, "DBName alt: " + context.Database.Connection.Database);

objLog.d(TAG, "alter ConString: " + context.Database.Connection.ConnectionString);

// Specify the provider name, server and database.
string providerName = "System.Data.SqlClient";

// Initialize the connection string builder for the
// underlying provider.
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();

// Set the properties for the data source.
sqlBuilder.DataSource = strDBServer;
sqlBuilder.InitialCatalog = strDBName;
sqlBuilder.IntegratedSecurity = true;
sqlBuilder.ConnectTimeout = 30;

// Build the SqlConnection connection string.
string providerString = sqlBuilder.ToString();

// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();

//Set the provider name.
entityBuilder.Provider = providerName;

// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;

// Set the Metadata location.
entityBuilder.Metadata = @"res://*/WorktimeTrackerDB.csdl|
res://*/WorktimeTrackerDB.ssdl|
res://*/WorktimeTrackerDB.msl";

//EntityConnection conn = new EntityConnection(entityBuilder.ToString());
//conn.Open();
//context.Database.Connection.ConnectionString = conn.ConnectionString;
context = new WorktimeTrackerDBContainer(entityBuilder.ToString());
objLog.d(TAG, "DBServer neu: " + context.Database.Connection.DataSource);
objLog.d(TAG, "DBName neu: " + context.Database.Connection.Database);
objLog.d(TAG, "neuer ConString: " + context.Database.Connection.ConnectionString);
11.02.2015
tschroeer 35 4
1
Welche Version des EF? Was bedeutet "Es klappt nicht?" Exception?
JEwen 17.02.2015
0
Ich arbeite mit .NET 4.5 und das EF müßte 5.0 sein. Wenn ich den Connectionstring austausche, kann er die Verbindung nicht öffnen. Der Status bleibt bei "opening" hängen und ich kann keine Daten abrufen oder hinzufügen.
17.02.2015
tschroeer 35 4
context = new WorktimeTrackerDBContainer(entityBuilder.ToString()); dürfte falsch sein, da entityBuilder nur die Metadaten enthält. Der ConnectionString steht aber im auskommentierten Teil! Nimm den Code aus meiner Antwort. Der funktioniert.
JEwen 17.02.2015
Streich den Kommentar mit "nur die Metadaten enthält...". Habs gerade gesehen, der ConnectionString ist auch drin.
JEwen 17.02.2015
0
Welchen Grund hat es, dass der ConnectionString zur Laufzeit geändert werden muss?
Bei der Installation sollte doch der korrekt ConnectionString hinterlegt werden.
Und warum muss der Context dann offen bleiben, wenn ich die Verbindung ändere?
02.03.2015
lbm1305 849 1 8
Tja, ganz einfach. Ich entwickle hier mit einer Testdatenbank auf einem Testserver und beim Kunden heißt der Db Server nun einmal anders als in meiner Firma.

Und der Context soll nicht offen bleiben sondern nach dem DB-Wechseln wieder geöffnet werden.

Ich habe das jetzt mit Trick 17 geschafft. Ich habe einfach in unseren DNS-Server und beim DNS des Kunden einen CNAME für den DB-Server eingetragen, der beim Kunden und uns gleich lautet. Und auf diesen CNAME beziehe ich mich jetzt im ConnectionString.
tschroeer 03.03.2015
Wir haben auch Datenbanken zum Entwickeln und im Produktiveinsatz. Beide Datenbanken haben Ihren eigenen ConnectionString. Im Produktivsystem wurde die Verbindungszeichenfolge aber bei der Erstinstallation geändert.
lbm1305 03.03.2015
Das EF bringt eine SqlConnectionFactory Klasse mit, mit der man unter Zuhilfenahme des ConnectionString und dem Namen der Datenbank eine Instanz von DbConnection erstellen kann. Für das Entwicklungssystem und das Produktivsystem kann an einer geeigneten Stelle dann der jeweilige ConnectionString (sowie der Name der DB) abgelegt werden kann. Die Factory kann dann entscheiden, welche Zeichenfolge herangezogen werden soll.
lbm1305 03.03.2015
0
Du kannst über die Konfigurationsdatei Deiner laufenden Anwendung die Verbindungszeichenfolge ändern und sogar verschiedene Datenbanken anbieten:

Füge Deiner Konfigurationsdatei ein paar Eigenschaften hinzu:

<?xml version="1.0"?>
<configuration>
<applicationSettings>
<...Properties.Settings>
<setting name="DataProvider" serializeAs="String">
<value>EF</value>
</setting>
<setting name="Provider" serializeAs="String">
<value>System.Data.SqlClient</value>
</setting>
<setting name="Metadata" serializeAs="String">
<value>res://*/DataModel.csdl|res://*/DataModel.ssdl|res://*/DataModel.msl</value>
</setting>
</...Properties.Settings>
</applicationSettings>
<userSettings>
<...Properties.Settings>
<setting name="ProviderConnectionString" serializeAs="String">
<value>Password=pwd;Persist Security Info=True;User ID=userid;Initial Catalog=databasename;Data Source=SERVER\Instance</value>
</setting>
</...Properties.Settings>
</userSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>


Eine Hilfsklasse dient zum Zusammenbauen des Connectionstrings:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Resources;
using System.Diagnostics;


namespace Data.Contracts
{
public class ConfigurationReader
{
#region static fields
private static string _ProviderConnectionString = Properties.Settings.Default.ProviderConnectionString;
private static string _Metadata = Properties.Settings.Default.Metadata;
private static string _Provider = Properties.Settings.Default.Provider;
#endregion

#region static properties

/// <summary>
/// Gets or sets the provider.
/// </summary>
/// <value>
/// The provider.
/// </value>
public static string Provider
{
get { return ConfigurationReader._Provider; }
set { ConfigurationReader._Provider = value; }
}

/// <summary>
/// Gets or sets the provider connection string.
/// </summary>
/// <value>
/// The provider connection string.
/// </value>
public static string ProviderConnectionString
{
get { return ConfigurationReader._ProviderConnectionString; }
set { ConfigurationReader._ProviderConnectionString = value; }
}

/// <summary>
/// Gets or sets the metadata.
/// </summary>
/// <value>
/// The metadata.
/// </value>
public static string Metadata
{
get { return ConfigurationReader._Metadata; }
set { ConfigurationReader._Metadata = value; }
}
#endregion

/// <summary>
/// Reads the data provider setting.
/// </summary>
/// <returns></returns>
public static eDataProvider readDataProviderSetting()
{
switch (Properties.Settings.Default.DataProvider)
{
case "Test":
return eDataProvider.Test;
case "EF":
return eDataProvider.EntityFramework;
default:
return eDataProvider.EntityFramework;
}
}

/// <summary>
/// Gets the connection string built from configurated values
/// </summary>
public static string ConnectionString
{
get
{
System.Data.EntityClient.EntityConnectionStringBuilder csb = new System.Data.EntityClient.EntityConnectionStringBuilder();
csb.Provider = _Provider;
csb.ProviderConnectionString = ProviderConnectionString;
csb.Metadata = Metadata;
return csb.ToString();
}
}

}
}


Für das Abrufen des ObjectContexts (Definiere dafür auch eine eigene MissingDataProviderException):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;

namespace astendo.SVP.Data.EF
{
public enum eObjectContext
{
DB1Entities,
DB2Entities
}
public class ObjectContexts
{
/// <summary>
/// Gets the object context.
/// </summary>
/// <param name="conString">The con string.</param>
/// <param name="context">The target context.</param>
/// <returns></returns>
public static ObjectContext getObjectContext(string conString, eObjectContext context)
{
try
{
switch (context)
{
case eObjectContext.DB1Entities:
return new DB1Entities(conString);
case eObjectContext.DB2Entities:
return new DB2Entities(conString);
default:
return new DB1Entities(conString);
}
}
catch (Exception ex)
{
throw new MissingDataProviderException("can't connect to " + conString, ex);
}

}
}
}


Verwendung in der Anwendung zum Beispiel so:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Data.EF
{
public class userDataMapping : IDataMapper<bl_user>
{
#region IDataMapper<bl_user> Member

/// <summary>
/// Creates the specified item.
/// </summary>
/// <param name="item">The item.</param>
public void Create(bl_user item)
{
using (DB1Entities database = ObjectContexts.getObjectContext(Contracts.ConfigurationReader.ConnectionString, eObjectContext.DB1Entities) as DB1Entities)
{
Mitarbeiter M = new Mitarbeiter();
M.Aktiv = item.Aktiv;
M.Login = item.Login;
M.Nachname = item.Nachname;
M.Vorname = item.Vorname;
database.Mitarbeiter.AddObject(M);
database.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
item.ID = M.ID;
}
}

#endregion

}
}


Und in dem UI-Projekt alles initialisieren:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace UI.Windows
{
static class Program
{
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
//ChangeInitialConfiguration();
ConfigurationReader.Provider = Properties.Settings.Default.Provider;
ConfigurationReader.ProviderConnectionString = Properties.Settings.Default.ProviderConnectionString;
ConfigurationReader.Metadata = Properties.Settings.Default.Metadata;
Application.Run(mainForm);
}

//Für ClickOnce Installationen die Connection nach Installation initialisieren
public static bool ChangeInitialConfiguration()
{
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;
string configPath = Application.ExecutablePath + ".config";
if (deployment.IsFirstRun)
{
Properties.Settings.Default.ProviderConnectionString = "Data Source=ServerAtInstallation;Initial Catalog=databaseAtInstallation;Integrated Security=True";
Properties.Settings.Default.Save();

/* Alternative to Save user settings
* Properties.Settings.Default.Upgrade();
*/
return true;
}
}
return false;
}
}
}



Nach der Installation im Zielsystem kann die Konfiguration jederzeit angepasst werden und wenn Du ClickOnce benutzt, wird nur beim ersten Start automatisch die Konfiguration auf das Zielsystem geändert.
21.03.2015
Dominik.Hilke 131 2

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH