У меня были некоторые проблемы при создании модели базы данных с использованием новейших Entity Framework и Code-First (см. Entity Framework 4.1 Code First для создания отношения «многие ко многим» для получения подробной информации).
Тем временем я понял, что проблема заключается не в самой Entity Framework, а в ее использовании вместе с WCF RIA DomainServices.
Ради полноты - это мой соответствующий код Code-First:
//
// 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; }
// I really would like to create this navigation property, but there seems to be no way
// to tell my DomainService to 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;
}
Таблицы SQL созданы, как и ожидалось. В моем клиентском приложении я использую 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>
Теперь все становится интересным. Если я добавлю две записи в пустую базу данных - одну в таблицу «Автор», а другую в таблицу «Книга», то в поле «ИД» обеих записей будет «1». Интересно то, что GetAuthorsQuery () с включенными Книгами добавляет Книгу в Свойство Книг Авторов.
В созданной таблице Author_Book (join-) нет записи. Итак, я запустил свой SQL-Profiler, чтобы увидеть, что именно здесь происходит. Вот что я узнал:
SELECT
[Project1].[ID] AS [ID],
[Project1].[Name] AS [Name],
[Project1].[C1] AS [C1],
[Project1].[ID1] AS [ID1],
[Project1].[Name1] AS [Name1]
FROM ( SELECT
[Limit1].[ID] AS [ID],
[Limit1].[Name] AS [Name],
[Join1].[ID] AS [ID1],
[Join1].[Name] AS [Name1],
CASE WHEN ([Join1].[Author_ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM (SELECT TOP (20) [c].[ID] AS [ID], [c].[Name] AS [Name]
FROM [dbo].[Author] AS [c] ) AS [Limit1]
LEFT OUTER JOIN (SELECT [Extent2].[Author_ID] AS [Author_ID], [Extent3].[ID] AS [ID], [Extent3].[Name] AS [Name]
FROM [dbo].[Author_Book] AS [Extent2]
INNER JOIN [dbo].[Book] AS [Extent3] ON [Extent3].[ID] = [Extent2].[Book_ID] ) AS [Join1] ON [Limit1].[ID] = [Join1].[Author_ID]
) AS [Project1]
ORDER BY [Project1].[ID] ASC, [Project1].[C1] ASC
Почему он это делает? Я действительно хотел бы использовать свое отношение «многие ко многим», но я также был бы рад использовать однонаправленное отношение (по крайней мере, что-то работало бы).
Заранее спасибо за любую помощь.