Entity Framework 4.1 Code-First approach to realize many-to-many relation over Domain-Services -


i had problems while creating database model using newest entity framework , code-first (see entity framework 4.1 code first approach create many-to-many relation details).

meanwhile i've figured out problem isn't entity framework more, using along wcf ria domainservices.

for sake of completeness - that's relevant code-first code:

// // models //  public class author {     public author()     {         this.books = new collection<book>();     }      [databasegenerated(databasegeneratedoption.identity)]     [key]     public int id { get; set; }      [maxlength(32)]     [required]     public string name { get; set; }      [include]     [association("author_book", "id", "id")]     public collection<book> books { get; set; } }  public class book {     public book()     {         // this.authors = new collection<author>();     }      [databasegenerated(databasegeneratedoption.identity)]     [key]     public int id { get; set; }      [maxlength(32)]     [required]     public string name { get; set; }      // create navigation property, there seems no way     // tell domainservice include it.     // public collection<author> authors { get; set; } }   // // mappings //  public class authormapping : entitytypeconfiguration<author> {     public authormapping()         : base()     {         this.hasmany (g => g.books)             .withmany(/*m => m.authors*/)             .map     (gm => gm.totable("author_book"));     } }   // // dbcontext //  public class bookauthormodelcontext : dbcontext {     public bookauthormodelcontext()         : base(@"data source=localhost\mssqlserver2008r2;database=bookauthor;integrated security=true;")     {     }       public dbset<author> authors  { get; set; }     public dbset<book>   books { get; set; }       protected override void onmodelcreating(dbmodelbuilder modelbuilder)     {         modelbuilder.configurations.add(new authormapping());         modelbuilder.conventions.remove<pluralizingtablenameconvention>();     } }   // // domainservice //  [enableclientaccess()] public class bookauthordomainservice : domainservice {     static bookauthordomainservice()     {         database.setinitializer<bookauthormodelcontext>(new bookauthormodelinitializer());     }      public bookauthordomainservice()     {         this.m_modelcontext = new bookauthormodelcontext();     }       public iqueryable<author> getauthors()     {         return this.m_modelcontext.authors.include("books");     }      public void insertauthor(author author)     {         this.m_modelcontext.insert(author);     }      public void updateauthor(author author)     {         this.m_modelcontext.update(author, this.changeset.getoriginal(author));     }      public void deleteauthor(author author)     {         this.m_modelcontext.delete(author);     }       public iqueryable<book> getbooks()     {         return this.m_modelcontext.books;//.include("authors");     }      public void insertbook(book author)     {         this.m_modelcontext.insert(author);     }      public void updatebook(book author)     {         this.m_modelcontext.update(author, this.changeset.getoriginal(author));     }      public void deletebook(book author)     {         this.m_modelcontext.delete(author);     }       protected override void dispose(bool disposing)     {         if (disposing)             this.m_modelcontext.dispose();         base.dispose(disposing);     }      protected override bool persistchangeset()     {         this.m_modelcontext.savechanges();         return base.persistchangeset();     }       private bookauthormodelcontext m_modelcontext; } 

the sql-tables created expected. in client application i'm using radgridview domaindatasource:

<usercontrol>     <usercontrol.resources>         <webservices:bookauthordomaincontext x:name="bookauthordomaincontext"/>     </usercontrol.resources>      <riacontrols:domaindatasource x:name="authordomaindatasource"                                   domaincontext="{staticresource bookauthordomaincontext}" queryname="getauthorsquery"                                                                   d:designdata="{d:designinstance webmodels:author, createlist=true}">      <telerik:radgridview x:name="authorgridview" datacontext="{binding elementname=authordomaindatasource}"                           itemssource="{binding data}" isbusy="{binding isbusy}"/> </usercontrol> 

now things interesting. if add 2 records empty database - 1 author table , other book table - both records 'id' field '1'. interesting thing is, getauthorsquery() included books adds book authors 'books' property. there no entry in created author_book (join-)table. so, i've started sql-profiler see going here. that's found out:

select  [project1].[id] [id],  [project1].[name] [name],  [project1].[c1] [c1],  [project1].[id1] [id1],  [project1].[name1] [name1] ( select      [limit1].[id] [id],      [limit1].[name] [name],      [join1].[id] [id1],      [join1].[name] [name1],      case when ([join1].[author_id] null) cast(null int) else 1 end [c1]       (select top (20) [c].[id] [id], [c].[name] [name]         [dbo].[author] [c] ) [limit1]     left outer join  (select [extent2].[author_id] [author_id], [extent3].[id] [id], [extent3].[name] [name]          [dbo].[author_book] [extent2]         inner join [dbo].[book] [extent3] on [extent3].[id] = [extent2].[book_id] ) [join1] on [limit1].[id] = [join1].[author_id] )  [project1] order [project1].[id] asc, [project1].[c1] asc 

why doing this? use many-to-many relation, happy use uni-directional relation (at least working).

thanks in advance help.

i'm not using attributes, maps. never less, hope you'll find useful.

this how write many-to-many relationship between authors , books, , able access book it's author , viceversa, well.

the following complete example, can copy&paste&compile.

using system; using system.collections.generic; using system.linq; using system.text; using wordandimages.entities; using system.data.entity; using system.data.entity.modelconfiguration; using system; using system.collections.generic; using system.linq; using system.text; using system.data.entity; using system.data.entity.modelconfiguration; using system.componentmodel.dataannotations;  namespace bookstore {     public class author     {         public int id { get; set; }         public string name { get; set; }         public virtual icollection<book> books { get; set; }         public author()         {             books = new list<book>();         }     }      public class book     {         public int id { get; set; }         public string title { get; set; }         public virtual icollection<author> authors { get; set; }         public book()         {             authors = new list<author>();         }     }      public class context : dbcontext     {         static context()         {             database.setinitializer<context>(null);         }          public dbset<author> authors { get; set; }         public dbset<book> books { get; set; }          protected override void onmodelcreating(dbmodelbuilder modelbuilder)         {             modelbuilder.configurations.add(new authormap());             modelbuilder.configurations.add(new bookmap());         }     }      public class bookmap : entitytypeconfiguration<book>     {         public bookmap()         {             this.hasmany(t => t.authors)             .withmany(a => a.books)             .map(t => t.totable("authorsbooks").mapleftkey("book_id").maprightkey("author_id"));         }     }      public class authormap : entitytypeconfiguration<author>     {         public authormap()         {             this.hasmany(a => a.books)             .withmany(b => b.authors)             .map(t => t.totable("authorsbooks").mapleftkey("author_id").maprightkey("book_id"));         }     }      class program     {         static void main(string[] args)         {              #region saving              var context = new context();             context.database.delete();             context.database.createifnotexists();              var book1 = new book { title = "joy" };             var book2 = new book { title = "happy" };              var author1 = new author { name = "lisa" };             var author2 = new author { name = "john" };             var author3 = new author { name = "luca" };              book1.authors.add(author1);             book1.authors.add(author2);              book2.authors.add(author1);             book2.authors.add(author3);              context.books.add(book1);             context.books.add(book2);             context.savechanges();              #endregion              #region accessing book it's author , viceversa              var context2 = new context();               var recovered_book1 = context2.books.where(b => b.title == "joy").firstordefault();             console.writeline(string.format("book1 has title {0} , has {1} authors", recovered_book1.title, recovered_book1.authors.count));             foreach (var author in recovered_book1.authors)                 console.writeline(author.name);              var recovered_book2 = context2.books.where(b => b.title == "joy").firstordefault();             console.writeline(string.format("book2 has title {0} , has {1} authors", recovered_book2.title, recovered_book2.authors.count));             foreach (var author in recovered_book1.authors)                 console.writeline(author.name);               var recovered_author1 = context2.authors.where(a => a.name == "lisa").firstordefault();             console.writeline(string.format("{0} wrote {1} books", recovered_author1.name, recovered_author1.books.count));             foreach (var book in recovered_author1.books)                 console.writeline(book.title);              console.readline();             #endregion         }     } } 

when comes recover book database, runs query

select top (1)  [extent1].[id] [id],  [extent1].[title] [title] [dbo].[books] [extent1] n'joy' = [extent1].[title] 

when recovers (with lazy load) authors, runs

exec sp_executesql n'select  [extent2].[id] [id],  [extent2].[name] [name]  [dbo].[authorsbooks] [extent1] inner join [dbo].[authors] [extent2] on [extent1].[author_id] = [extent2].[id] [extent1].[book_id] = @entitykeyvalue1',n'@entitykeyvalue1 int',@entitykeyvalue1=1 

Comments

Popular posts from this blog

c# - how to write client side events functions for the combobox items -

exception - Python, pyPdf OCR error: pyPdf.utils.PdfReadError: EOF marker not found -