एंटिटी फ्रेमवर्क रनटाइम पर कनेक्शन बदलता है


80

मेरे पास एक वेब एपीआई परियोजना है जो मेरे मॉडल और डीएएल विधानसभाओं का संदर्भ देती है। उपयोगकर्ता को एक लॉगिन स्क्रीन के साथ प्रस्तुत किया जाता है, जहां वह विभिन्न डेटाबेस का चयन कर सकता है।

मैं कनेक्शन स्ट्रिंग का निर्माण निम्नानुसार करता हूं:

    public void Connect(Database database)
    {
        //Build an SQL connection string
        SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
        {
            DataSource = database.Server,
            InitialCatalog = database.Catalog,
            UserID = database.Username,
            Password = database.Password,
        };

        //Build an entity framework connection string
        EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
        {
            Provider = database.Provider,
            Metadata = Settings.Default.Metadata,
            ProviderConnectionString = sqlString.ToString()
        };
    }

सबसे पहले, मैं वास्तव में डेटा संदर्भ के कनेक्शन को कैसे बदलूं?

और दूसरी बात, जैसा कि यह एक वेब एपीआई परियोजना है, क्या कनेक्शन स्ट्रिंग (उपयोगकर्ता द्वारा प्रति लॉगिन पर सेट) उपयोगकर्ता की बातचीत के दौरान लगातार है या इसे हर बार मेरे डेटा संदर्भ में पारित किया जाना चाहिए?


मैंने आपकी मानसिकता / टूलबॉक्स आवश्यकताओं में फिट होने के मामले में थोड़ा वैकल्पिक जोड़ा।
जीम टोलन

@ इवान-मार्क आपने इस भाग को कैसे हल किया और दूसरी बात, जैसा कि यह एक वेब एपी प्रोजेक्ट है, यह कनेक्शनस्ट्रिंग (प्रति लॉग इन पर सेट) उपयोगकर्ता की अंतःक्रिया के दौरान लगातार बनी रहती है या इसे मेरे डेटाकोटेक्स्ट में हर बार पारित किया जाना चाहिए
नरेंद्र सिंह राठौर

@NarendraSinghRathore कनेक्शन स्ट्रिंग्स को डेटाबेस नाम (या कुछ और) के साथ एक कुंजी फ़ाइल में संग्रहीत किया जाता है। उपयोगकर्ता लॉगिन पर एक डेटाबेस का चयन करता है और इसे एक कैश में संग्रहीत किया जाता है जहां कुंजी उपयोगकर्ता नाम हो सकती है। उपयोगकर्ता अपने उपयोगकर्ता नाम को हेडर के रूप में पारित करने के लिए अनुरोध करता है और कनेक्शनस्ट्रिंग को पुनर्प्राप्त किया जाता है और डेटाकोटेक्स्ट में पास किया जाता है।
इवान-मार्क डेबोनो

@ इवान-मार्कडेबोनो क्या आप इस कैश की व्याख्या कर सकते हैं ? क्या आप बैकएंड पर मेमोरीकैच या सेशन का उपयोग कर रहे हैं या फ्रंटएंड में कुकी के रूप में स्टोर कर रहे हैं। धन्यवाद!
नरेंद्र सिंह राठौर

1
@NarendraSinghRathore मैमोरी कैश इन ए सिंगलटन
इवान-मार्क

जवाबों:


110

इस उत्तर पर थोड़ी देर हो गई है लेकिन मुझे लगता है कि यह एक छोटा सा विस्तार विधि के साथ ऐसा करने का एक संभावित तरीका है। हम विन्यास पर ईएफ सम्मेलन और कुछ कम रूपरेखा कॉल का लाभ उठा सकते हैं।

वैसे भी, टिप्पणी कोड और उदाहरण उपयोग:

विस्तार विधि वर्ग:

public static class ConnectionTools
{
    // all params are optional
    public static void ChangeDatabase(
        this DbContext source,
        string initialCatalog = "",
        string dataSource = "",
        string userId = "",
        string password = "",
        bool integratedSecuity = true,
        string configConnectionStringName = "") 
        /* this would be used if the
        *  connectionString name varied from 
        *  the base EF class name */
    {
        try
        {
            // use the const name if it's not null, otherwise
            // using the convention of connection string = EF contextname
            // grab the type name and we're done
            var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
                ? source.GetType().Name 
                : configConnectionStringName;

            // add a reference to System.Configuration
            var entityCnxStringBuilder = new EntityConnectionStringBuilder
                (System.Configuration.ConfigurationManager
                    .ConnectionStrings[configNameEf].ConnectionString);

            // init the sqlbuilder with the full EF connectionstring cargo
            var sqlCnxStringBuilder = new SqlConnectionStringBuilder
                (entityCnxStringBuilder.ProviderConnectionString);

            // only populate parameters with values if added
            if (!string.IsNullOrEmpty(initialCatalog))
                sqlCnxStringBuilder.InitialCatalog = initialCatalog;
            if (!string.IsNullOrEmpty(dataSource))
                sqlCnxStringBuilder.DataSource = dataSource;
            if (!string.IsNullOrEmpty(userId))
                sqlCnxStringBuilder.UserID = userId;
            if (!string.IsNullOrEmpty(password))
                sqlCnxStringBuilder.Password = password;

            // set the integrated security status
            sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;

            // now flip the properties that were changed
            source.Database.Connection.ConnectionString 
                = sqlCnxStringBuilder.ConnectionString;
        }
        catch (Exception ex)
        {
            // set log item if required
        }
    }
}

मूल उपयोग:

// assumes a connectionString name in .config of MyDbEntities
var selectedDb = new MyDbEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDb.ChangeDatabase
    (
        initialCatalog: "name-of-another-initialcatalog",
        userId: "jackthelady",
        password: "nomoresecrets",
        dataSource: @".\sqlexpress" // could be ip address 120.273.435.167 etc
    );

मुझे पता है कि आपके पास पहले से ही बुनियादी कार्यक्षमता है, लेकिन सोचा कि इससे थोड़ी विविधता आएगी।


6
यह बहुत अच्छा है, धन्यवाद! मैं एक विस्तारित के साथ एक बहु-किरायेदार परियोजना पर इसका उपयोग करने में सक्षम हूं Controllerजो हमेशा अपने ग्राहक विशिष्ट डीबी को नियंत्रक के 'डीबी' को सेट करेगा। यह भी मुझे (या किसी भी भविष्य के व्यवस्थापक / डेवलपर्स) को मुक्त करने के लिए हर ग्राहक के लिए एक नया कनेक्शन स्ट्रिंग बनाने से जोड़ा जाता है।
ल्यूक

3
हाँ, मैं सचमुच इस मुद्दे पर एक व्यवहार्य मजबूत समाधान के साथ आने की कोशिश कर दिनों के लिए संघर्ष किया और इस सरल विस्तार विधि ने मेरी समस्याओं का जवाब दिया। पिछले साल इसे वापस बनाने के बाद से, मुझे इसमें कोई बदलाव नहीं करना पड़ा है, इसलिए मुझे लगता है कि यह अच्छी तरह से परीक्षण की गई सड़क है :)। वैसे भी, खुशी है कि यह कुछ बक्से टिक ... बात करने के लिए अच्छा है।
जिम टोलन

5
मुझे यह त्रुटि मिल रही है System.ArgumentException: Keyword समर्थित नहीं: 'डेटा स्रोत' EF 4 में
sheshadri

2
@ user1234 मुझे भी त्रुटि मिली: कीवर्ड ने 'डेटा स्रोत' का समर्थन नहीं किया। इस समस्या को हल करने के लिए मुझे उनके कोड के इस हिस्से को बदलना पड़ा: // add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder { ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString).ConnectionString };
A.Ima

2
@jimtollan हर बार जब मैं नया कनेक्शन बनाता हूं तो यह पुराने कनेक्शन स्ट्रिंग से बनाया जाता है, जो app.config में सेव होता है !!
अब्दुस्सलाम एलशरीफ

62

DbContextएक रचनाकार अधिभार है जो एक कनेक्शन स्ट्रिंग या कनेक्शन स्ट्रिंग के नाम को स्वीकार करता है। अपने स्वयं के संस्करण को लागू करें और इसे बेस कंस्ट्रक्टर को दें:

public class MyDbContext : DbContext
{
    public MyDbContext( string nameOrConnectionString ) 
        : base( nameOrConnectionString )
    {
    }
}

तब बस एक कॉन्फ़िगर कनेक्शन स्ट्रिंग या एक कनेक्शन स्ट्रिंग का नाम ही पास करें जब आप अपना पलटाते हैं DbContext

var context = new MyDbContext( "..." );

मुझे पता ही नहीं चला कि यह फंक्शन पहले से ही मेरे DbContext व्युत्पन्न वर्ग में मौजूद था इसलिए मैंने इसका इस्तेमाल किया।
ब्रायन लेमिंग

2
मुझे लगता है कि इस उत्तर को स्वीकृत उत्तर के रूप में चिह्नित करना चाहिए।
शून्य

2
यह उत्तर बहुत अच्छा है, लेकिन @eMeL के अनुसार। यह वर्ग स्वतः पूर्ण है, इसलिए यदि आप मॉडल को अद्यतन करते हैं तो आपको इस पर आधारित एक और वर्ग बनाना चाहिए ताकि कोई ओवरराइट न हो।
जुआन कार्लोस ओरोपेजा

4
@JuanCarlosOropeza: EF ने आंशिक रूप से वर्गों (बॉट hcontext और इकाइयाँ) को उत्पन्न किया, इसलिए आप अपनी खुद की फ़ाइल बना सकते हैं, अपने DbContext को फिर से घोषित (आंशिक रूप में) कर सकते हैं और वहाँ अपने कस्टम कार्य जोड़ सकते हैं।
डॉट नेट

14

जिम टोलन का जवाब बहुत अच्छा है, लेकिन मुझे त्रुटि मिली: कीवर्ड ने 'डेटा स्रोत' का समर्थन नहीं किया। इस समस्या को हल करने के लिए मुझे उनके कोड के इस हिस्से को बदलना पड़ा:

// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
    (System.Configuration.ConfigurationManager
            .ConnectionStrings[configNameEf].ConnectionString);

इसके लिए:

// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
{
    ProviderConnectionString = new  SqlConnectionStringBuilder(System.Configuration.ConfigurationManager
               .ConnectionStrings[configNameEf].ConnectionString).ConnectionString
};

मैं वास्तव में माफी चाहता हूँ। मुझे पता है कि मुझे अन्य उत्तरों का जवाब देने के लिए उत्तरों का उपयोग नहीं करना चाहिए, लेकिन मेरा जवाब एक टिप्पणी के लिए बहुत लंबा है :(


6

निर्मित वर्ग 'आंशिक' है!

public partial class Database1Entities1 : DbContext
{
    public Database1Entities1()
        : base("name=Database1Entities1")
    {
    }

... और आप इसे इस तरह कहते हैं:

using (var ctx = new Database1Entities1())
      {
        #if DEBUG
        ctx.Database.Log = Console.Write;
        #endif

इसलिए, आपको केवल मूल ऑटो-जेनरेट की गई क्लास (उसी क्लास के नाम के साथ!) के लिए एक आंशिक स्वयं की क्लास फ़ाइल बनाने की जरूरत है और कनेक्शन स्ट्रिंग पैरामीटर के साथ एक नया कंस्ट्रक्टर जोड़ें, जैसे कि Moo का उत्तर।

इसके बाद आप मूल के मुकाबले पैराट्राइज्ड कंस्ट्रक्टर का उपयोग कर सकते हैं। :-)

उदाहरण:

using (var ctx = new Database1Entities1(myOwnConnectionString))
      {
        #if DEBUG
        ctx.Database.Log = Console.Write;
        #endif

उपरोक्त समाधान मेरे लिए काम कर रहा है। आप लिंक
कार्तिक गोयल

0

अपने web.config या app.config में कई कनेक्शन स्ट्रिंग्स जोड़ें।

तो आप उन्हें एक स्ट्रिंग के रूप में प्राप्त कर सकते हैं:

System.Configuration.ConfigurationManager.
    ConnectionStrings["entityFrameworkConnection"].ConnectionString;

फिर सेट करने के लिए स्ट्रिंग का उपयोग करें:

Provider
Metadata
ProviderConnectionString

यह बेहतर यहाँ समझाया गया है:

Web.config से कनेक्शन स्ट्रिंग पढ़ें


कनेक्शन स्ट्रिंग्स को एक अलग sql सर्वर डेटाबेस में संग्रहीत किया जाता है और उपयोगकर्ता के लिए एक सूची प्रस्तुत की जाती है।
इवान-मार्क डेबोनो

0
string _connString = "metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost;initial catalog=DATABASE;persist security info=True;user id=sa;password=YourPassword;multipleactiveresultsets=True;App=EntityFramework"";

EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(_connString);
ctx = new Entities(_connString);

आप web.config से कनेक्शन स्ट्रिंग प्राप्त कर सकते हैं, और अभी EntityConnectionStringBuilder कंस्ट्रक्टर में सेट कर सकते हैं, और संदर्भ के लिए कंस्ट्रक्टर में एक तर्क के रूप में EntityConnectionStringBuilder का उपयोग कर सकते हैं।

उपयोगकर्ता नाम से कनेक्शन स्ट्रिंग कैश करें। कैश से जोड़ने / प्राप्त करने को संभालने के लिए सामान्य तरीकों के एक जोड़े का उपयोग करके सरल उदाहरण।

private static readonly ObjectCache cache = MemoryCache.Default;

// add to cache
AddToCache<string>(username, value);

// get from cache

 string value = GetFromCache<string>(username);
 if (value != null)
 {
     // got item, do something with it.
 }
 else
 {
    // item does not exist in cache.
 }


public void AddToCache<T>(string token, T item)
    {
        cache.Add(token, item, DateTime.Now.AddMinutes(1));
    }

public T GetFromCache<T>(string cacheKey) where T : class
    {
        try
        {
            return (T)cache[cacheKey];
        }
        catch
        {
            return null;
        }
    }

हां, लेकिन क्या उपयोगकर्ता के नियंत्रक की कार्रवाई को कॉल करने के लिए नए कनेक्शन को dbcontext को पारित करने की आवश्यकता होती है?
इवान-मार्क डेबोनो

आप शायद प्रत्येक कॉल के बाद संदर्भ का निपटान करेंगे, इसलिए हाँ। संदर्भ केवल एक अनुरोध (कार्य की इकाई) के लिए रहना चाहिए। स्पष्टीकरण
12

तो मैं अपने सत्र की अवधि के लिए उपयोगकर्ता के कनेक्शन को कैसे और कहाँ संग्रहीत करूंगा? (कई उपयोगकर्ता वेब एपीआई परियोजना से जुड़ सकते हैं और अलग
-

कैशिंग के बारे में कैसे, और इसे उपयोगकर्ता नाम या किसी अन्य कुंजी द्वारा पुनर्प्राप्त करें।
12

0

मेरे मामले में मैं DbContext के विपरीत ObjectContext का उपयोग कर रहा हूं, इसलिए मैंने उस उद्देश्य के लिए स्वीकृत उत्तर में कोड को साझा किया।

public static class ConnectionTools
{
    public static void ChangeDatabase(
        this ObjectContext source,
        string initialCatalog = "",
        string dataSource = "",
        string userId = "",
        string password = "",
        bool integratedSecuity = true,
        string configConnectionStringName = "")
    {
        try
        {
            // use the const name if it's not null, otherwise
            // using the convention of connection string = EF contextname
            // grab the type name and we're done
            var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
                ? Source.GetType().Name
                : configConnectionStringName;

            // add a reference to System.Configuration
            var entityCnxStringBuilder = new EntityConnectionStringBuilder
                (System.Configuration.ConfigurationManager
                    .ConnectionStrings[configNameEf].ConnectionString);

            // init the sqlbuilder with the full EF connectionstring cargo
            var sqlCnxStringBuilder = new SqlConnectionStringBuilder
                (entityCnxStringBuilder.ProviderConnectionString);

            // only populate parameters with values if added
            if (!string.IsNullOrEmpty(initialCatalog))
                sqlCnxStringBuilder.InitialCatalog = initialCatalog;
            if (!string.IsNullOrEmpty(dataSource))
                sqlCnxStringBuilder.DataSource = dataSource;
            if (!string.IsNullOrEmpty(userId))
                sqlCnxStringBuilder.UserID = userId;
            if (!string.IsNullOrEmpty(password))
                sqlCnxStringBuilder.Password = password;

            // set the integrated security status
            sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;

            // now flip the properties that were changed
            source.Connection.ConnectionString
                = sqlCnxStringBuilder.ConnectionString;
        }
        catch (Exception ex)
        {
            // set log item if required
        }
    }
}

मुझे यह त्रुटि मिली कि कीवर्ड समर्थित नहीं है: 'डेटा स्रोत'। मैं EF 4 का उपयोग कर रहा हूँ
sheshadri

0

मैं एप्लिकेशन कॉन्फ़िगरेशन में कई डेटा स्रोत रखना चाहता था। इसलिए app.config में एक खंड स्थापित करने के बाद मैंने डेटा स्रोत को स्वैप किया और फिर इसे कनेक्शन स्ट्रिंग के रूप में dbcontext में पास कर दिया।

//Get the key/value connection string from app config  
var sect = (NameValueCollection)ConfigurationManager.GetSection("section");  
var val = sect["New DataSource"].ToString();

//Get the original connection string with the full payload  
var entityCnxStringBuilder = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings["OriginalStringBuiltByADO.Net"].ConnectionString);     

//Swap out the provider specific connection string  
entityCnxStringBuilder.ProviderConnectionString = val;

//Return the payload with the change in connection string.   
return entityCnxStringBuilder.ConnectionString;

यह मुझे पता लगाने के लिए थोड़ा सा लगा। मुझे उम्मीद है कि यह किसी को बाहर करने में मदद करता है। मैं इसे बहुत जटिल बना रहा था। इससे पहले।


0

मेरे पास सामान्य कनेक्शन स्ट्रिंग को एंटिटी फ्रेमवर्क प्रारूप में बदलने के लिए दो विस्तार विधियां हैं। यह संस्करण प्राथमिक प्रोजेक्ट के लिए app.config फ़ाइल से कनेक्शन स्ट्रिंग्स की नकल के बिना कक्षा पुस्तकालय परियोजनाओं के साथ अच्छी तरह से काम कर रहा है। यह VB.Net है लेकिन C # में बदलना आसान है।

Public Module Extensions

    <Extension>
    Public Function ToEntityConnectionString(ByRef sqlClientConnStr As String, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
        Dim sqlb As New SqlConnectionStringBuilder(sqlClientConnStr)
        Return ToEntityConnectionString(sqlb, modelFileName, multipleActiceResultSet)
    End Function

    <Extension>
    Public Function ToEntityConnectionString(ByRef sqlClientConnStrBldr As SqlConnectionStringBuilder, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
        sqlClientConnStrBldr.MultipleActiveResultSets = multipleActiceResultSet
        sqlClientConnStrBldr.ApplicationName = "EntityFramework"

        Dim metaData As String = "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string='{1}'"
        Return String.Format(metaData, modelFileName, sqlClientConnStrBldr.ConnectionString)
    End Function

End Module

उसके बाद मैं DbContext के लिए एक आंशिक वर्ग बनाता हूं:

Partial Public Class DlmsDataContext

    Public Shared Property ModelFileName As String = "AvrEntities" ' (AvrEntities.edmx)

    Public Sub New(ByVal avrConnectionString As String)
        MyBase.New(CStr(avrConnectionString.ToEntityConnectionString(ModelFileName, True)))
    End Sub

End Class

एक क्वेरी बनाना:

Dim newConnectionString As String = "Data Source=.\SQLEXPRESS;Initial Catalog=DB;Persist Security Info=True;User ID=sa;Password=pass"

Using ctx As New DlmsDataContext(newConnectionString)
    ' ...
    ctx.SaveChanges()
End Using

0

SQL सर्वर और SQLite डेटाबेस दोनों के लिए, उपयोग करें:

_sqlServerDBsContext = new SqlServerDBsContext(new DbContextOptionsBuilder<SqlServerDBsContext>().UseSqlServer("Connection String to SQL DB").Options);

SQLite के लिए, सुनिश्चित करें Microsoft.EntityFrameworkCore.Sqliteकि इंस्टॉल किया गया है, फिर कनेक्शन स्ट्रिंग बस "डेटा स्रोत = '+ फ़ाइल नाम" है।

_sqliteDBsContext = new SqliteDBsContext(new DbContextOptionsBuilder<SqliteDBsContext>().UseSqlite("Connection String to SQLite DB").Options);

-6
Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext();

var query = from p in db.SyncAudits orderby p.SyncTime descending select p;
Console.WriteLine(query.ToString());

इस कोड को आज़माएं ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.