PDA

View Full Version : گفتگو: ساختار درونی EF



maktab
دوشنبه 05 دی 1390, 13:21 عصر
می خوام بدونم EF چگونه با بانک ارتباط برقرار میکنه؟ (نحوه استفاده رو نمیخوام)
مثلا وقتی ما 10 تا جدول داشته باشیم و از اونا EF بسازیم تویه برنامه 10 تا کلاس خواهیم داشت و 10 تا شی.
هر کلاس ساختار جدول ها رو پیاده سازی میکنه (پروپرتی) و شی ها هم لیستی از داده های هر جدول هستن.
خب حالا چندتا سوال در مورد ساختارش:
وقتی ما اطلاعات یه شی رو میخونیم مستقیما از بانک خونده میشه؟ یا اولین بار این شی درون برنامه ذخیره میشه و در دفعات بعدی فقط خونده میشه(شبیه دیتاست)؟

بقیه سوالات رو بعدا میپرسم :لبخند:. ممنون از اینکه جواب میدید.

raziee
سه شنبه 06 دی 1390, 01:14 صبح
با سلام.
بر اساس اینکه آیا نیاز به اجرای یک کوری باشه یا نه با دیتابیس ارتباط بر قرار میکنه.
کد زیر رو ببینید:
var items = new DbContext().Users;
اگر این خط دستور رو در برنامه تون بنویسید و هیچ وقت مقادیر items رو استفاده نکنید هیچ تراکنشی هم با بانک انجام نمیشه.
اما کد زیر رو نگاه کنید:
var items = new DbContext().Users.ToList();
در این کد تراکنش انجام میشه. چون ما خواستیم (اجبار کردیم) که انجام بشه. (به دلیل ToList)
اما این موضوع که آیا در هر بار درخواست برای دسترسی به یک Object با دیتابیس ارتباط برقرار میکنه یا نه بستگی به این داره که اون Object در DbContext موجود باشه یا نه!
مثلا:
var item = new DbContext().Users.Find(1);
در این کد برای هر بازیابی با دیتابیس ارتباط برقرار میکنه چون در هر بار درخواست یک شیء جدید از DbContext ساخته میشه.
اما در این کد:
static var db = DbContext();
var item = db.Users.Find(1);

به دلیل تعریف db از static و عدم ایجاد شیء جدید در هر بار درخواست! ، تنها برای بار اول (که داده ی مربوطه در DbContext موجود نیست) با دیتابیس ارتباط برقرار میکنه.

maktab
سه شنبه 06 دی 1390, 19:25 عصر
حالا فرض کنیم این کد رو داشته باشیم:


var items = new DbContext();


بعد چندین بار ازش استفاده کنیم. به این صورت:


items.User.ToList();

تویه هر بار استفاده داره به بانک وصل میشه دیگه؟

raziee
سه شنبه 06 دی 1390, 19:59 عصر
با سلام.
بستگی داره به جایی که یک Instance از DbContext ایجاد میکنید و جایی که درخواست ها رو انجام میدید.

public class Entity
{
[Key]
public int Id { get; set; }
}

public class User : Entity
{
public string UserName { get; set; }
}

public interface IRepository<T>
{
T Get(int id);
IEnumerable<T> GetAll();
IEnumerable<T> Where(Expression<Func<T, bool>> predicate);
void Insert(T o);
void Insert(IEnumerable<T> oo);
void Save();
void Delete(T o);
void Restore(T o);
}

public class Repository<T> : IRepository<T> where T : Entity,new ()
{
protected readonly DbContext c;

public Repository(DbContext context)
{
c = context;
}

public T Get(int id)
{
return c.Set<T>().Find(id);
}

public IEnumerable<T> GetAll()
{
return c.Set<T>();
}

public IEnumerable<T> Where(Expression<Func<T, bool>> predicate)
{
return c.Set<T>().Where(predicate);
}

public void Insert(T o)
{
c.Set<T>().Add(o);
}

public void Insert(IEnumerable<T> oo)
{
foreach (var o in oo)
Insert(o);
}

public void Save()
{
c.SaveChanges();
}

public void Delete(T o)
{
c.Set<T>().Remove(o);
}
}

به کلاس پایین نگاه کنید:
هر بار که یک Instance از UserServiceFirst گرفته بشه در متد GetFirst برای اولین بار اطلاعات از دیتابیس خونده میشه.
اما در متد GetSecond چون اطلاعات در DbContext موجود هست دیگه به دیتابیس درخواستی رو نمیفرسته.

public class UserServiceFirst
{
IRepository<User> repo = new Repository<User>(new DbContext());
UserServiceFirst()
{
GetFirst();
GetSecond();
}
public void GetFirst()
{
var users = repo.GetAll().ToList();
}
public void GetSecond()
{
var users = repo.GetAll().ToList();
}
}


در کلاس زیر به خاطر تعریف DbContext از نوع static تنها زمانی اطلاعات از دیتابیس درخواست خواهد شد که DbContext برابر با null باشه و ازش یک شیء جدید در حافظه ایجاد بشه و فرقی نداره از UserServiceSecond کی یک شیء جدید ایجاد بشه!!

public class UserServiceSecond
{
static DbContext db;
static DbContext Db
{
get
{
if (db == null) db = new DbContext();
return db;
}
}
IRepository<User> repo = new Repository<User>(Db);
UserServiceSecond()
{
GetFirst();
GetSecond();
}
public void GetFirst()
{
var users = repo.GetAll().ToList();
}
public void GetSecond()
{
var users = repo.GetAll().ToList();
}
}

حالا نگاه کنید اگه کلاس UserServiceFirst رو به صورت زیر بنویسیم هم در متد GetFirst و هم در متد GetSecond اطلاعات از دیتابیس خونده خواهد شد.

public class UserServiceFirst
{
UserServiceFirst()
{
GetFirst();
GetSecond();
}
public void GetFirst()
{
IRepository<User> repo = new Repository<User>(new DbContext());
var users = repo.GetAll().ToList();
}
public void GetSecond()
{
IRepository<User> repo = new Repository<User>(new DbContext());
var users = repo.GetAll().ToList();
}
}