实体框架不恰当地将新记录插入导航表

时间:2013-11-26 11:48:09

标签: asp.net-mvc sql-server-2008-r2 ef-code-first entity-framework-6

我在插入具有多对多导航属性的记录时遇到问题,

我有这些模型

//ModelBase
public class ModelBase
{
    [Key]
    public long Id { get; set; }
}

//Book
public class Book : ModelBase
{
    public string Title { get; set; }
    public virtual ICollection<Author> Authors { get; set; }
    public virtual ICollection<PublishedBook> PublishedBooks { get; set; }
}

//Author
public class Author : ModelBase
{
    public string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }
}

DTO调用BookDtoAuthorDto来传输图层之间的数据

从控制器我将数据填充到DTO并调用Create方法(位于单独的层中)以将数据保存到数据库,

BookDto bookDto = new BookDto()
{
    Id = model.Id,
    Title = model.Title,
    Authors = model.AuthorIds.Select(c => new AuthorDto { Id = c }).ToList()
}

using (ServiceFactory facory = new ServiceFactory())
{
    factory.Book.Create(bookDto);
}

Create方法中,我使用ValueInjector

将DTO映射到POCO
public void Create(BookDto bookDTO)
{
    Book book = new Book();
    book.InjectFrom<DeepCloneInjection>(bookDTO);
    bookRepository.Add(book);
    unitOfWork.Commit();
}

它在Genaric Repository Base中调用Add方法

public virtual void Add(T entity)
{
    dbset.Add(entity);
}

这会适当地将数据插入Books表和BookAuthors表但是即使我通过Authors现有Authors,也会在AuthorIds表中插入新记录来自控制器的Book.Authors

任何想法如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

您缺少将现有作者附加到上下文。你可以这样做:

public void Create(BookDto bookDTO)
{
    Book book = new Book();
    book.InjectFrom<DeepCloneInjection>(bookDTO);
    foreach (var author in book.Authors)
        authorRepository.Attach(author);
    bookRepository.Add(book);
    unitOfWork.Commit();
}

通常调用Attach实现通用dbset.Attach(entity);方法。我假设所有存储库(authorRepositorybookRepository)共享相同的上下文实例。否则上述情况将无效。

数据库中已存在AuthorId并不重要。 EF不首先通过查询检查Id是否存在。如果在分离实体的对象图上调用Add,它会尝试通过为父项和所有子项生成INSERT语句来插入整个图。通过附加子项,您可以有效地关闭INSERT语句。