c# - Entity Framework Designer First get navigation property as Tasks -


the task pattern says in order consistent has async or not async.

by using entity framework designer first can achieve quite

var course = await db.courses.findasync(courseid); 

courses dbset generated entity framework , therefore has async methods. problem if add navigation property class, latter not dbset , not contain async method definition.

as example, if add navigation property students table, created virtual icollection students means cannot use async methods. want having entity framework automatically generate task<> in order able await navigation properties.

is possible? goal achieve this:

var course = await db.courses.findasync(courseid); var student = await course.students.findasync(studentid); 

while @ moment options mixing async/notasync code:

var course = await db.courses.findasync(courseid); var student = course.students.first(p => p.id = studentid); 

or not using navigation property @ all:

var course = await db.courses.findasync(courseid); var student = await db.students.where(p => p.courseid == course.id && p.id == studentsid).firstasync(); 

can suggest solution not require code first?

edit according https://entityframework.codeplex.com/wikipage?title=task-based%20asynchronous%20pattern%20support%20in%20ef.#asynclazyloading im searching called "async lazy loading" , not feature available yet (and maybe never be). seems can either use lazy loading or async features, maybe should wrap property in task awaiting task.run(course.students.first(p => p.id = studentid)) i'm not sure idea.

in opinion, lazy loading (which in opinion case enumerating navigation property trigger database access) bad access pattern, means database access happen @ surprising places, can make application performance difficult predict.

all solutions below use import system.data.entity.

solution 1: use eager loading include

var course = await db.courses.include(c => c.students).firstordefaultasync(c => c.id == courseid); var student = course.students.first(p => p.id == studentid); 

advantages:

  • one database access required load objects - , solution scales if want retrieve more 1 course object @ time;
  • the students navigation property loaded , can used freely;

drawbacks:

  • there @ least 1 database access;
  • the whole set of related student objects loaded if needed one;

solution 2: use loadasync method exists on concrete collection class;

this solution relies on fact lazy-loaded collections entitycollection<tentity> class.

first, define extension method:

public static async task loadasync<t>(icollection<t> collection)     t : class {     if (collection == null) throw new argumentnullexception("collection");      var entitycollection = collection system.data.entity.core.objects.dataclasses.entitycollection<t>;      if (entitycollection == null || entitycollection.isloaded) return;     await entitycollection.loadasync(cancellationtoken.none).configureawait(false); } 

then write like:

var course = await db.courses.findasync(courseid); await course.students.loadasync(); var student = course.students.first(p => p.id = studentid); 

advantage:

  • there may no database access @ if objects loaded in context;
  • the navigation property students guaranteed loaded;

drawbacks:

  • susceptible "n+1 queries" issue;
  • both course , set of related student objects can grow stale, may trigger concurrency issues down road; (note concurrency issues affect relationship harder resolve concurrency issues affect single record)

solution 3: use createsourcequery method on concrete class load student object want.

ok, doing not work, , pretty bad idea.

however, solution same advantages/drawbacks can written, in way:

var course = await db.courses.findasync(courseid); var studentsquery = c in db.courses                     c.id == courseid                     s in c.students                     select s; var student = await studentsquery.firstasync(p => p.id = studentid); 

advantage:

  • you load 1 student object going use;

drawbacks:

  • the students navigation property not loaded, meaning cannot used without potentially triggering database access;
  • the second line trigger database access (susceptible "n+1 queries" issue, or running method times);

solution 4: eager loading, more selective: load both course , student interest in initial linq query.

i not 100% sure that solution work written.

var query = c in db.courses             c.id == courseid             select new { course = c, student = c.students.first(p => p.id == studentid) };  var result = await query.firstordefaultasync(); var course = result.course; var student = result.student; 

advantages:

  • only 1 database access required retrieve both objects;
  • you retrieve objects going work on;

drawbacks:

  • the students navigation property not loaded, meaning cannot used without potentially triggering database access;

** when use solution? **

  • if need navigation property filled (either because know make use of of elements, or because want pass parent entity component allowed make use of property wants), use solution 1 or 2;
  • if not need navigation property filled, use solution 4. use solution 3 if categorically have course object loaded;

Comments

Popular posts from this blog

javascript - how to protect a flash video from refresh? -

android - Associate same looper with different threads -

visual studio 2010 - Connect to informix database windows form application -