【问题标题】:How should I design my model/viewmodel for this application?我应该如何为这个应用程序设计我的模型/视图模型?
【发布时间】:2012-05-27 02:55:31
【问题描述】:

我正在使用带有 SQL Server 2008 的 II6 上的 ASP.Net-MVC3 开发一个 Web 应用程序。我无法提供有关该项目的详细信息,所以就这个问题而言,它是一个库。有书籍,人们可以查看这些书籍。我们希望保留过去结帐 CheckOuts 的记录。所以这里是数据模式:

Books                   Checkouts
-------------------     ----------------------------
| ID   (PK)        |    | ID(PK)                   |
| Title varchar(50)|    | BookId (FK Books.ID)     |
|                  |    | CheckoutDate (DateTime)  |
|  ...             |    | ExpirationDate (DateTime)|
|                  |    | Username (varchar(50)    |
|                  |    | ...                      |
-------------------     ----------------------------

这个想法是 Check Out 和 Books 之间的关系是多对一的,但只有一个 CheckOut 将永远是“活动的”或“未过期”,即每本书最多有一个 CheckOut 的过期日期会更长比当前时间。应用程序将强制执行此操作。

我的第一个问题是:您认为对于上述要求,这是一个好的数据库设计吗?或者我应该在 Check Outs 表中包含一个“Expired”布尔列吗?其他想法?

我们的 MVC 模型如下所示:

public class Book {
    public int ID { get; set; }
    public string Title{ get; set; }

    ...

}

public class Checkout {
    public int ID { get; set; }
    public int BookID { get; set; }
    public sting Username { get; set; }
    public DateTime CheckOutDate{ get; set; }
    public DateTime ExpirationDate { get; set; }

    ...

}

对于我们的数据访问层,我们只是使用 System.Data 类,例如 SqlCommand 和 SqlDataReader,因此没有 EF、LinqToSql 等的好处,例如关系和延迟加载。

现在我的问题是我们要搜索这些书并显示如下表格:

Title     Checked Out  Checked Out By  Check Out Expiration
--------  -----------  --------------  ----------------------
Book1          Yes         Username        01/01/1970

获取此信息的查询如下所示

SELECT *
FROM Books
LEFT JOIN Checkouts ON Checkouts.BookID = Book.Id
WHERE Checkouts.ExpirationDate <= GETDATE()

我该怎么做?

我会做这样的模型吗

public class BookSearchTableRow {
    public string Title { get; set;}
    public bool CheckedOut { get; set;}
    public string CheckedOutBy { get; set;}
    public DateTime CheckOutExpiration { get; set;}
}

并让我的视图成为一个列表?

或者我应该将 CheckOut 属性添加到我的 Book 模型中吗?

public class Book {
    public int ID { get; set; }
    public string Title{ get; set; }

    ... Other Book Fields ...

    public Checkout ActiveCheckout { get; set; }
}

【问题讨论】:

  • 为什么还需要关系数据库?为什么不将它存储在像 RavenDB 这样的无模式数据库中?
  • 不是一个选项。数据库和数据访问已经到位。它实际上不是图书馆。这只是我能想到的最相似的例子,没有给出太多细节。
  • 现在我真的很困惑。如果数据库已经就位,那么你为什么要问我们这是否是一个好的模式?如果你不能改变一些没有意义的事情,我们也无能为力。
  • 数据库已就位,SQL Server 2008。我无法更改,但架构可以更改。数据库访问已到位。我们使用 SqlCommands 和 SqlDataReaders。这不能(至少在短期内)更改为 EF、Linq2Sql 等。我只是问是否拥有具有多对一关系的 CheckOuts 表和 Books 表最有意义对于我所描述的。即您可以查看书籍,并且应该有过去结账的记录。我将编辑问题并在问题的那部分添加更多内容。不过这里的主要问题是我应该如何设计我的视图模型。

标签: asp.net-mvc-3 database-design model viewmodel database-schema


【解决方案1】:

您设计视图模型的方式不应影响您设计模型的方式,反之亦然。您的模型通常代表您的领域,而您的视图模型(通常)是这些模型的转换,适合显示特定部分。

如果我是你,我会向你的视图发送一个类似于 BookSearchTableRow 类的 IEnumerable。这类似于您要显示的内容。如果你的模型正确地代表了你的领域,你不应该因为视图需要而修改它们。这就是视图模型的用途。

【讨论】:

  • 我倾向于这种方法。最后一个问题。如果我走这条路,说我创建了一个 BookSearchTableRow 类。我可以看到以编程方式(即在数据库之外)投影搜索结果(List)非常困难或效率低下。它将涉及然后再次调用数据库以查看它是否已被签出。您认为让我的数据访问层有一个返回 List 的方法是否符合规定(就关注点分离而言)?
  • 我不会说。您的数据访问层不应该了解视图或视图模型。
  • 那你会怎么推荐呢。在我看来,要么 a) DataAccess 层返回一个 List,它需要一个数据库调用和 N 次迭代来将结果映射到域模型,或者 b) 它返回一个 List,然后我必须为每本书再次调用以使其处于活动结帐状态,然后最后将所有数据映射到 List。这是 N+1 次数据库调用和类似 3N+1 次迭代以获得 N BookSearchTableRows。另一种选择是让我的数据库访问返回一些聚合,例如 List>
  • 如果您在很多地方都需要这种聚合(带有结帐数据/状态的书籍),您始终可以在数据访问层中提供一些返回类似对象的内容。不过,这个对象不一定是视图的投影。另一种选择可能是更改您的数据库架构并将书籍的当前状态添加到 Books 表中:Books ------ ID, int (PK) Title, nvarchar(50) CheckoutDate, datetime, nullable ExpirationDate, datetime, nullable Username, nvarchar(50), nullable 然后您只能将_previous_checkouts 存储在表Checkouts 中。
猜你喜欢
  • 2011-05-12
  • 2011-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 2020-01-31
  • 2013-02-03
  • 1970-01-01
相关资源
最近更新 更多