【问题标题】:CRUD Edit operation using a ViewModel with unit testing使用带有单元测试的 ViewModel 进行 CRUD 编辑操作
【发布时间】:2017-12-21 09:43:57
【问题描述】:

首先:我找到了this post,但是我不是很明白,所以请不要把它锁成重复。

我正在尝试使用 ViewModel 进行编辑操作。

我的问题是由于某种原因adds 表的新行而不是editing 它。在我去测试之前,这一切都可以正常工作。

我相信我错过了一些愚蠢的事情,但我不知道我做错了什么。

如果有什么不同,我正在使用code-first

我的视图模型:

public class CreateViewModel
{
    public string Title { get; set; }

    [Display(Name = "Author")]
    public int AuthorId { get; set; }
    public DateTime? PublicationDate { get; set; }
    public float? Edition { get; set; }
    public SelectList Authors { get; set; }
}

我的控制器功能:

    // GET: Books/Edit/5
    public ViewResult Edit(int? id)
    {
        if (id == null)
        {
            return View("Error");
        }
        Book book = db.Books.FirstOrDefault(a => a.Id == id);

        var vm = new CreateViewModel()
        {
            AuthorId = book.AuthorId,
            Authors = new SelectList(db.Authors, "Id", "Name"),
            PublicationDate = book.PublicationDate,
            Title = book.Title,
            Edition = book.Edition
        };

        if (book == null)
        {
            return View("Error");
        }
        return View(vm);
    }

    // POST: Books/Edit/5
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(CreateViewModel vm)
    {
        if (ModelState.IsValid)
        {
            var repo = new EFLibraryRepository();
            repo.Save(new Book(){
                AuthorId = vm.AuthorId,
                PublicationDate = vm.PublicationDate,
                Title = vm.Title,
                Edition = vm.Edition
            });
            return RedirectToAction("Index");
        }
        return View("Edit", vm);
    }

我的模拟仓库:

public class EFLibraryRepository : ILibraryRepository
{
    AuthorAndBookDbModel db = new AuthorAndBookDbModel();
    public IQueryable<Author> Authors { get { return db.Authors; } }

    public IQueryable<Book> Books { get { return db.Books; } }

    public void Delete(Book book)
    {
        db.Books.Remove(book);
        db.SaveChanges();
    }

    public void Delete(Author author)
    {
        db.Authors.Remove(author);
        db.SaveChanges();
    }

    public Book Save(Book book)
    {
        if (book.Id == 0)
        {
            db.Books.Add(book);
        }
        else
        {
            db.Entry(book).State = System.Data.Entity.EntityState.Modified;
        }
        db.SaveChanges();
        return book;
    }
    public Author Save(Author author)
    {
        if (author.Id == 0)
        {
            db.Authors.Add(author);
        }
        else
        {
            db.Entry(author).State = System.Data.Entity.EntityState.Modified;
        }
        db.SaveChanges();
        return author;
    }
}

ILibraryRepository:

public interface ILibraryRepository
{
    IQueryable<Book> Books { get; }
    IQueryable<Author> Authors { get; }

    Book Save(Book book);
    Author Save(Author author);

    void Delete(Book book);
    void Delete(Author author);
}

【问题讨论】:

  • 你的视图模型没有Id属性,当你保存Book时,你没有设置它的Id属性,所以它总是0你总是叫@ 987654333@
  • 但无论如何你的设计都是错误的。您应该基于Id 从数据库中获取原始数据模型(只需将public int? Id { get; set } 属性添加到您的视图模型,使其自动绑定),然后您从视图模型更新其属性。
  • OK 现在完美运行。你想添加一个答案,以便我选择最好的吗?
  • 把它放在这里,我明天去取。感谢您的帮助!
  • 当你在虚拟机中获取编辑方法的信息时,也只需获取书籍的 id,然后从数据库中获取书籍对象,编辑它,将其标记为EntityState.Modified,然后保存它.它肯定会起作用。

标签: c# asp.net asp.net-mvc unit-testing


【解决方案1】:

在您的 POST 方法中,您从不设置 Book 的 Id 属性的值,因此它始终为 0int 的默认值),因此您始终执行代码以添加新的 @987654324 @。

您首先需要在您的视图模型中为id 包含一个属性,以便将其值绑定到 POST 方法中。

public class CreateViewModel
{
    public int? Id { get; set; } // add this
    ....

请注意,假设您使用默认路由,则无需在视图中为其添加隐藏输入(其值将与表单action 属性中的路由值绑定)。

然后在POST方法中,根据视图模型设置BookId

repo.Save(new Book() {
    Id = vm.Id, // add
    AuthorId = vm.AuthorId,
    ....

但是,在编辑现有记录时,正确的做法是从基于Id 的存储库中获取原始数据模型并更新其属性,例如

Book book = db.Books.FirstOrDefault(a => a.Id == vm.Id);
book.AuthorId = vm.AuthorId;
....
repo.Save(book);

而不是创建一个新的Book 实例。这种方法的一些好处包括

  1. 您的数据模型通常会包含不应包含的属性 视图(例如,用于指示记录日期的属性 创建,由谁创建)。创建数据模型的新实例并 保存它意味着这些属性将被覆盖并设置为 它们的默认值。
  2. 您可以进行并发检查,例如,您可以检查 TIMESTAMP 值,如果它们不同,你知道另一个 用户同时修改了记录(您可能会采取 不同的行动方案,而不是仅仅覆盖以前 使用更改)

【讨论】:

    猜你喜欢
    • 2021-05-23
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多