PDA

View Full Version : سوال: تغییر کانکشن ذخیره شده مربوط به Entity Framework



علی فتحی
جمعه 22 خرداد 1394, 14:15 عصر
سلام : یک روش برای بانکهای مختلف قراردادن دیتا داخل پوشه های مختلف میباشد . طبق نمونه زیر با linq راحت میشه اینکارو کرد. چون app.confige همان مسیر setiing میباشد .اما در انتی تی حتی بدون ستینگ هم میشه کار کرد.

دوستان اگر لطف کنن نمونه زیر رو به ef تبدیل کنن خیلی ممنون میشم شاید بدرد دیگر دوستان هم بخوره با تشکر

یک راه دیگه ایا میشه با کد نویسی دیتاسورس=قسمت زررنگ مشخص شده=رو با کد نویسی تغییر داد؟با linq to xml

Mahmoud.Afrad
یک شنبه 24 خرداد 1394, 00:15 صبح
فضاهای نام زیر رو نیاز داری

using System.Configuration;
using System.Data.EntityClient;

در متد زیر به جای Database1Entities نام کلاس context پروژه خودتون رو بنویسید.

private void ChangeConnection(ref Database1Entities db, string attachDbFilename)
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);

ConnectionStringSettings connection =
config.ConnectionStrings.ConnectionStrings[db.GetType().Name];

string strConnectionString = connection.ConnectionString;
EntityConnection entityConnection = new EntityConnection(strConnectionString);
DbConnection dbConnection = entityConnection.StoreConnection;
SqlConnectionStringBuilder sqlConnectionStringBuilder =
new SqlConnectionStringBuilder(dbConnection.Connection String)
{
AttachDBFilename = attachDbFilename
};
EntityConnectionStringBuilder entityConnectionStringBuilder = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
Metadata = @"res://*/",
ProviderConnectionString = sqlConnectionStringBuilder.ConnectionString
};
connection.ConnectionString = entityConnectionStringBuilder.ConnectionString;
config.Save(System.Configuration.ConfigurationSave Mode.Modified, true);
System.Configuration.ConfigurationManager.RefreshS ection("connectionStrings");
db.Connection.ConnectionString = entityConnectionStringBuilder.ConnectionString;
}

نحوه استفاده: هر جا نیاز داشتید باید مسیر دیتابیس رو بسازید و همراه نمونه ای از context به متد ارسال کنید.

ChangeConnection(ref db, @"|datadirectory|\Data\Database2.mdf");

زمان دیباگ اگر محتوای فایل کانفیگ رو ببینید تغییر اعمال شده. البته بعد از خروج از حالت دیباگ ممکنه کانفیگ به حالت قبل برگرده که چیز مهمی نیست و فقط در دیباگ این اتفاق خواهد افتاد.




البته این کد در صورتی که در ابتدا دیتابیس در مسیر قبلی موجود نباشه دچار خطا خواهد شد(اگر دیتابیس رو قبلش تغییر مکان داده باشید). میشه با تغییرات کمی متد رو مستقل از context کرد تا فقط کانکشن تغییر کنه و بعد از تغییر context رو ساخت.

علی فتحی
یک شنبه 24 خرداد 1394, 09:45 صبح
سخت شد جواب نداد این کد نتیجه همون استفاده از لینک بهتره؟

Mahmoud.Afrad
یک شنبه 24 خرداد 1394, 15:33 عصر
چرا سخت. خیلی هم راحته. استفاده از متدی که گذاشتم کاری نداره. به صورت زیر متد رو تغییر بده.

private void ChangeConnection(string connectionStringName, string attachDbFilename)
{
try
{
Configuration config = ConfigurationManager.OpenExeConfiguration(Configur ationUserLevel.None);
ConnectionStringSettings connection = config.ConnectionStrings.ConnectionStrings[connectionStringName];
if (connection == null) return;
string strConnectionString = connection.ConnectionString;
EntityConnection entityConnection = new EntityConnection(strConnectionString);
DbConnection dbConnection = entityConnection.StoreConnection;
SqlConnectionStringBuilder sqlConnectionStringBuilder =
new SqlConnectionStringBuilder(dbConnection.Connection String)
{
AttachDBFilename = attachDbFilename
};
EntityConnectionStringBuilder entityConnectionStringBuilder = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
Metadata = @"res://*/",
ProviderConnectionString = sqlConnectionStringBuilder.ConnectionString
};
connection.ConnectionString = entityConnectionStringBuilder.ConnectionString;
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");
}
catch (Exception ex)
{
throw ex;
}
}

کد دکمه button1 رو به صورت زیر تغییر بده.

private void button1_Click(object sender, EventArgs e)
{
string strConnectionStringName = "DDDDDEntities";
string strAttachDbFilename = "|DataDirectory|\\" + comboBox1.Text + "\\DDDDD.mdf";
try
{
ChangeConnection(strConnectionStringName, strAttachDbFilename);
Configuration config = ConfigurationManager.OpenExeConfiguration(Configur ationUserLevel.None);
ConnectionStringSettings connection =
config.ConnectionStrings.ConnectionStrings[strConnectionStringName];
if (connection == null) return;
textBox3.Text = connection.ConnectionString;
GetData();
MessageBox.Show("سال انتخاب شد", comboBox1.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

در کل این کار درست نیست که برای هر سال دیتابیس مجزا در نظر بگیری چون اصل یکپارچگی دیتابیس نقض میشه.

این هم فایل پروژه که اصلاح کردم
http://www.uplooder.net/cgi-bin/dl.cgi?key=0c135b7e1851791ed14f4e6b75155759

علی فتحی
دوشنبه 22 تیر 1394, 02:21 صبح
دست گلتون درد نکنه دقیقا همونی که میخواستم فقط تغییرات در WinLinq.vshost.exe اعمال نمیشه

آیا مشکلی در عملیات ثبت و ویرایش و.... روی بانک ایجاد نمی کنه؟

Mahmoud.Afrad
دوشنبه 22 تیر 1394, 20:15 عصر
اطلاعات app.config توی فایل WinLinq.exe.Config ذخیره میشه.
البته گفتم اگر از درون ویژوال استادیو اجرا کنید وقتی برنامه رو ببندید اطلاعات به مقادیر پیشفرض برمیگردند. ولی با اجرای مستقیم فایل از درون پوشه دیباگ مشکلی نیست.

Amir4317
دوشنبه 22 تیر 1394, 22:36 عصر
سلام!
اقتباس از تنظیم رشته اتصالی Entity Framework به بانک اطلاعاتی به وسیله کد
(http://www.dotnettips.info/post/1789/%d8%aa%d9%86%d8%b8%db%8c%d9%85-%d8%b1%d8%b4%d8%aa%d9%87-%d8%a7%d8%aa%d8%b5%d8%a7%d9%84%db%8c-entity-framework-%d8%a8%d9%87-%d8%a8%d8%a7%d9%86%da%a9-%d8%a7%d8%b7%d9%84%d8%a7%d8%b9%d8%a7%d8%aa%db%8c-%d8%a8%d9%87-%d9%88%d8%b3%db%8c%d9%84%d9%87-%da%a9%d8%af)

در زمان ساخت مدل از بانک اطلاعاتی در روش Database First به صورت پیش فرض تنظیمات مربوط به اتصال (Connection String) مدل به بانک اطلاعاتی در فایل config برنامه ذخیره می‌شود. مشکل این روش آن است که در سیستم‌های مختلف، بسته به بستری که نرم افزار قرار است بر روی آن اجرا شود، باید تنظیمات مربوط به بانک اطلاعاتی صورت گیرد.مثلا فرض کنید شما در زمان توسعه نرم افزار، SQL Server را به صورت Local بر روی سیستم خود نصب کرده اید و Connection String ساخته شده توسط ویزارد Entity Framework بر همین اساس ساخته و ذخیره شده‌است. حال بعد از انتشار برنامه، شخصی تصمیم دارد برنامه را بر روی سیستمی نصب کند که بانک اطلاعاتی Local نداشته و تصمیم به اتصال به یک بانک اطلاعاتی بر روی سرور دیگر یا با مشخصات (Login و Password و ...) دیگر را دارد. برای این مواقع نیاز به پیاده سازی روشی است تا کاربر نهایی بتواند تنظیمات مربوط به اتصال به بانک اطلاعاتی را تغییر دهد. روش‌های مختلفی مثل تغییر فایل app.config به صورت Runtime یا ... در سایت‌های مختلف ارائه شده که اکثرا روش‌های غیر اصولی و زمانبری جهت پیاده سازی هستند.

ساده‌ترین روش جهت انجام این کار، اعمال تغییری کوچک در Constructor کلاس مدل مشتق شده از DBContext می‌باشد. فرض کنید مدلی از بانک اطلاعاتی Personnely با نام PersonallyEntities ساخته اید که حاصل آن کلاس زیر خواهد بود:

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


همانطور که مشاهده می‌کنید، در Constructor این کلاس، نام Connection String مورد استفاده جهت اتصال به بانک اطلاعاتی به صورت زیر آورده شده که به Connection String ذخیره شده در فایل Config اشاره می‌کند:

"name=PersonallyEntities"


اگر به Connection String ذخیره شده در فایل Config دقت کنید متوجه می‌شوید که Connection String ذخیره شده، دارای فرمتی خاص و متفاوتی نسبت به Connection String معمولی ADO.NET است. متن ذخیره شده شامل تنظیمات و Metadata مدل ساخته شده جهت ارتباط با بانک اطلاعاتی نیز می‌باشد:

metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=Personally;integrated security=True;MultipleActiveResultSets=True;App=En tityFramework"


جهت تولید پویای Connection String، بسته به تنظیمات کاربر، نیاز است تا در آخر Connection String ی با فرمت بالا در اختیار Entity Framework قرار دهیم تا امکان اتصال به بانک فراهم شود. جهت تبدیل Connection String معمول ADO.NET به Connection String قابل فهم EF میتوان از کلاس EntityConnectionStringBuilder به صورت زیر استفاده کرد:


public static string BuildEntityConnection(string connectionString)
{
var entityConnection = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = connectionString,
Metadata = "res://*"
};

return entityConnection.ToString();
}


همانطور که مشاهده می‌کنید، متد بالا با دریافت یک connectionString که همان ADO.NET ConnectionString ما می‌باشد، تنظیمات و Metadata مورد نیاز Entity Framework را به آن اضافه کرده و یک EF ConnectionString برمی‌گرداند. برای اینکه بتوان EF ConnectionString تولید شده را در هنگام اجرای برنامه به صورت Runtime اعمال کرد، نیاز است تا تغییر کوچکی در Constructor کلاس مدل تولید شده توسط Entity Framework ایجاد کرد. کلاس PersonnelyEntities به صورت زیر تغییر پیدا می‌کند:


public partial class PersonallyEntities : DbContext
{
public PersonallyEntities(string connectionString)
: base(connectionString)
{

}
}




با اضافه شدن پارامتر connectionString به سازنده کلاس PersonnelyEntities برای ساخت یک نمونه از مدل ساخته شده در کد نیاز است تا Connection String مورد نظر جهت برقراری ارتباط با بانک را به عنوان پارامتر، به متد سازنده پاس دهیم. سپس مقدار این پارامتر به کلاس والد ( DbContext ) جهت برقراری ارتباط با بانک اطلاعاتی ارجاع داده شده:

: base(connectionString)


در آخر به صورت زیر میتوان توسط EF به بانک اطلاعاتی مورد نظر متصل شد :

var entityConnectionString = BuildeEntityConnection("Data Source=localhost;Initial Catalog=Personally; Integrated Security=True");
var PersonallyDb = new PersonallyEntities(entityConnectionString);



با این روش میتوان ADO Connection String مربوط به اتصال بانک اطلاعاتی را به راحتی به صورت داینامیک به وسیله اطلاعات وارد شده توسط کاربر و کلاس‌های تولید Connection String نظیر SQLConnectionStringBuilder تولید کرد و بدون تغییر در کد‌های برنامه، به بانک‌های مختلفی متصل شد. همچنین با داینامیک کردن متد Provider کلاس EntityConnectionStringBuilder که در کد بالا با "System.Data.SqlClient" مقدار دهی شده، می‌توان وابستگی برنامه بانک اطلاعی خاص را از بین برد و بسته به تنظیمات مورد نظر کاربر، به موتورهای مختلف بانک اطلاعاتی متصل شد که البته لازمه این کار رعایت یکسری نکات فنی در پیاده سازی پروژه است که از حوصله این مقاله خارج است.


موفق باشید

علی فتحی
سه شنبه 23 تیر 1394, 00:52 صبح
تشکر اقا امیر : اقا محمود دقیقا مثل کدهای شنا عمل کرده و به خوبی کار میکنه : امتحان کردم

ولی با لینک خیلی خیلی راحتر میشه اینکارو کرد.

private void button1_Click(object sender, EventArgs e) {
textBox3.Text = ("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirecto ry|" + comboBox1.Text + "\\DDDDD.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
Properties.Settings.Default.DDDDDConnectionString = textBox3.Text;
Properties.Settings.Default.Save();
MessageBox.Show("سال انتخاب شد", comboBox1.Text);
Form1_Load(sender, e);

علی فتحی
پنج شنبه 25 تیر 1394, 01:34 صبح
تشکر مخصوص تمام کسانی که در نتیجه گرفتن این تاپیک کمک کردند واقعا عالی و بدرد بخور بود.

perfeshnal
چهارشنبه 02 تیر 1395, 14:07 عصر
سلام

من از EF استفاده می کنم و احتمالا همینطور که می دونید EF این قابلیت رو داره که در صورت وجود نداشتن دیتابیس اون رو بسازه
من یک مشکلی دارم که این دیتابیس رو EF در محل دیفالت خود SqlServer در پوشه DATA میسازه من می خوام که دیتابیس در کنار فایل اجرایی برنامه ساخته بشه
خیلی در اینترنت جستجو کردم ولی به نتیجه نرسیدم شایدم واژه های درستی برای جستجو انتخاب نکردم !
ممنون میشم اگر کسی اطلاعاتی در این مورد داره راهنمایی کنه
مرسی

ژیار رحیمی
چهارشنبه 02 تیر 1395, 16:58 عصر
سلام. با استفاده از SQL Managment Object

رفرنس های لازم

using System.IO;
using System.Collections.Specialized;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Windows.Forms;
using Microsoft.SqlServer.Management.Smo;

در مسیر پروژه یک پوشه بنام DB ساخته میشود و دیتابیس به داخل این پوشه انتقال داده میشود.

public static void ReLocateDataBaseFiles()
{
var dbName="DBTest";
var srv = new Server(@".\SQLEXPRESS");
srv.ConnectionContext.LoginSecure = true;
srv.ConnectionContext.DatabaseName = "master";
srv.ConnectionContext.Connect();

//گرفتن مسیر فایل های دیتابیس از مسیر DATA اسکیول سرور
var strDataSQL = string.Format(@"{0}\{1}.mdf", srv.DefaultFile, dbName);
var strLogSQL = string.Format(@"{0}\{1}_log.LDF", srv.DefaultFile, dbName);
//چک کردن پوشه DB برای انتقال فایل های دیتابیس در مسیر پروژه
if (Directory.Exists(Application.StartupPath + @"\DB"))
Directory.Delete(Application.StartupPath + @"\DB");
//ایجاد پوشه DB با پرومیشن کامل دسترسی
CreateDirectoryDBwithPermission();
//قطع کردن تمام ارتباطات با دیتابیس
srv.KillAllProcesses(dbName);
//Detach کردن
srv.DetachDatabase(dbName, true);
//انتقال دیتابیس در مسیر اسکیوال به به مسیر پروژه داخل پوشه DB
var strDataPath = string.Format(@"{0}\DB\{1}.mdf", Application.StartupPath, dbName);
var strLogPath = string.Format(@"{0}\DB\{1}_log.LDF", Application.StartupPath, dbName);
File.Move(strDataSQL, strDataPath);
File.Move(strLogSQL, strDataPath);
var files = new StringCollection
{
strDataPath,
strLogPath
};
//Attach کردن فایل ها از مسیر جدید
srv.AttachDatabase(dbName, files);
//if (srv.ConnectionContext.IsOpen)
srv.ConnectionContext.Disconnect();
}
public static void CreateDirectoryDBwithPermission()
{
var dInfo = Directory.CreateDirectory(Application.StartupPath + @"\DB");
var dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}

perfeshnal
پنج شنبه 03 تیر 1395, 08:17 صبح
سلام

ممنون از راهنماییتون امتحان میکنم
فقط یک مسئله پس راهی نداریم که به EF آدرس بدیم یجوری که آقا دیتابیس رو در این مسیر بساز اول باید ساخته بشه بعد انتقال بدیم
بازم از راهنمایی تون ممنونم

abdullah20
پنج شنبه 03 تیر 1395, 16:43 عصر
پست جناب رحیمی را کامل مطالعه نکردم ولی ی روش دیگه اون اینه ک
کانکشن خودتون را تغییر بدید و در کلاس Configuration مسیر را معرفی کنید

perfeshnal
جمعه 04 تیر 1395, 15:31 عصر
پست جناب رحیمی را کامل مطالعه نکردم ولی ی روش دیگه اون اینه ک
کانکشن خودتون را تغییر بدید و در کلاس Configuration مسیر را معرفی کنید
ممنون از پاسختون
آیا نمونه کدی راجب پاسختون دارید ؟
البته مربوط به SQLEXPRESS نباشه localمعمولی می خوام

Mahmoud.Afrad
جمعه 04 تیر 1395, 18:49 عصر
perfeshnal (http://barnamenevis.org/member.php?20345-perfeshnal) اگر منظورتون در زمان طراحی هست ، کانکشن رو باید تغییر بدید. اگر نمیدونید چه تغییری ، تگ connectionStrings داخل App.config رو بزارید تا دوستان اصلاح کنند.

perfeshnal
شنبه 05 تیر 1395, 18:34 عصر
perfeshnal (http://barnamenevis.org/member.php?20345-perfeshnal) اگر منظورتون در زمان طراحی هست ، کانکشن رو باید تغییر بدید. اگر نمیدونید چه تغییری ، تگ connectionStrings داخل App.config رو بزارید تا دوستان اصلاح کنند.
سلام

کاری با زمان طراحی ندارم می خوام مکان دیتابیسی که EF می سازه در صورت نبودن دیتابیس رو خودم مشخص کنم همین
جناب ژیار رحیمی راه حلی رو بعد از ساخت دیتابیس گفتند که میشه از اون هم استفاده کرد ولی من بیشتر می خوام در حین ساخت دیتابیس مکان رو مشخص کنم نه بعد از ساخت دوباره انتقال بدم

<connectionStrings>
<add name="DBContext" connectionString="data source=.;initial catalog=DB;integrated security=True;MultipleActiveResultSets=True;App=En tityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>

perfeshnal
یک شنبه 06 تیر 1395, 22:09 عصر
سلام خسته نباشید

منتظر راه حل دیگه ای نباشم ؟

hamix666
شنبه 17 مهر 1395, 12:04 عصر
با سلام من مشکلم اینجاست که برنامه به صورت ویزاردی به بانک ef متصل شده است کانکشن استرینگم فرق می کنه حالا نیاز دارم برنامه رو در شبکه استفاده کنم ولی نمی تونم این کار رو انجام بدم امکان اینکه بخوام به کد فرست تبدیل کنم هم وجود نداره می شه راهنماییم کنین یا یه قطعه کدی برام برازین ؟

hamix666
یک شنبه 18 مهر 1395, 10:33 صبح
کسی نیست کمک کنه ؟

Amin69
چهارشنبه 17 آذر 1395, 00:12 صبح
سلام
من هرچی تلاش کردم نتونستم این روش رو پیاده کنم. میشه بگید مشکل از کجاست؟
سازنده رو به این تغییر دادم:
public Entities(string connectionString)
: base(connectionString)
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
و کد فراخوانی اینه:
var entityConnectionString = BuildeEntityConnection(@"Data Source=.\SQLEXPRESS;attachdbfilename=E:\edb.mdf; Integrated Security=True");
entity = new Entities(entityConnectionString);
اما هنگام اجرا خطا میده که باید نام Entity انتخاب بشه...