关于在ASP.NET MVC中放置内容的地方有点困惑

时间:2010-01-10 19:48:42

标签: c# asp.net sql-server asp.net-mvc linq-to-sql

我正在开发我的第一个ASP.NET MVC应用程序,而且我对创建/更新某些数据感到困惑。

我有一个数据库表User,一个LinqToSql生成的部分类User,以及我自己的自定义部分类User

我在[Bind(Exclude = "Id, InsertDateTime, UpdateDateTime")]版本上使用User,因为我不希望用户编辑这些字段。

我还有一个PhoneNumber字段,我希望用户编辑,但需要转换。我将其作为10个数字存储在数据库中,但当我通过视图将其显示给用户时,我将其转换为视图中的可读电话号码,如下所示:

string.Format("{0:(###) ###-####}", Convert.ToInt64(Model.User.PhoneNumber)).

问题是,当用户点击“保存”时,电话号码将始终采用错误的格式。某处,我需要删除所有非数字字符(括号,短划线,斜线和空格)。

问题

对于下面列出的每个字段,如何处理创建和编辑操作?

  1. Id - 我相信这是由SQL-Server自动处理的,因为我的所有Id字段都设置为IDENTITY (1, 1)。我没有进行过广泛的测试,但这似乎“只是工作”。请确认。

  2. InsertDateTime - 我希望将此设置为DateTime.Now 用于创建操作,而不是用于编辑操作。那么,设置此值的适当位置在哪里:User,UserController,UserFormViewModel或其他什么?

  3. UpdateDateTime - 我希望对于“创建”和“编辑”操作都设置为DateTime.Now,但同样,我应该在哪里放置执行此分配的代码?

    < / LI>
  4. PhoneNumber - 与上述三个字段不同,此字段可由用户编辑,但需要在更新发生之前从(888) 123-4567转换为8881234567。这里有几个问题:(1)这种转变的适当位置在哪里?我在视图中将电话号码转换为“用户可读”格式,我应该将其转换回“数据库存储”格式? (2)我应该在PhoneNumber属性中添加[Bind(Exclude...)]吗?

  5. 更新

    从答案到目前为止,我认为澄清一些事情,至少对我自己来说。

    首先,这里是User数据发生事件的位置列表:

      数据库中的
    1. User表 - 处理Id赋值。可以为InsertDateTime和UpdateDateTime提供默认值。

    2. User类 - 使用GetRuleViolations()方法处理验证。

    3. UserRepository class - 抽象出数据持久性函数(get,get all,add,delete和save)。

    4. UserController class - 处理用户请求和发布尝试(索引,详细信息,编辑,发布编辑,创建,发布创建和删除)。

    5. UserFormViewModel class - 提供要查看的强类型数据(User对象以及下拉菜单的后备数据。)

    6. Views/User/Create.aspxViews/User/Edit.aspx - 生成html,通过将静态数据与动态数据(存储在视图模型中)相结合,向用户显示UI。

      < / LI>

      我目前的想法是,在概念上设置IdUpdateDateTimeInsertDateTime的责任在于模型。数据库肯定负责在插入时设置Id,但我仍然不清楚应该在哪里设置日期时间字段。似乎有两种选择:存储库(由@Aaronaught建议)或User类(已经处理验证)。

      至于在##########和(###)### - ####之间转换PhoneNumber的问题,这在概念上更像是一个“视图”功能。我喜欢@Aaronaught关于拥有一个专门的PhoneNumberConverter课程的想法,我可能会考虑到这一点,但仍有一个问题是谁在这个课程上调用这些方法。为此,我倾向于我的UserFormViewModel课程。

      这引出了两个后续问题......

      跟进问题

      1. 是否应在UpdateDateTime班级或InsertDateTime班级中分配UserRepositoryUser字段?

      2. PhoneNumberConverter拨打电话号码转换方法(UserFormViewModel类)是否有意义?

2 个答案:

答案 0 :(得分:1)

这是我的答案:

1-是的,你是对的,它使用SQL服务器标识规范列“自动增量列”

完成

2-您可以在DB中将此字段的默认值设置为getdate() sql函数,以便它首次在db中插入该值,并获取服务器日期时间值

3-这对于默认值也可以是相同的,但是在函数中你可以在ex中保存数据。如果您调用的行提交更改,请将此值设置为Datetime.Now。

4-第一部分我认为合适的地方将在[Post]方法版本上,我不认为你应该排除它。

答案 1 :(得分:1)

通常你会有一个业务逻辑层,MVCers称之为存储库 - 介于你的控制器和DAL之间。这通常是处理时间戳和数据转换的理想位置。

public class UserRepository : IUserRepository
{
    private IDatabase db;

    public UserRepository(IDatabase db)
    {
        if (db == null)
        {
            throw new ArgumentNullException("db");
        }
        this.db = db;
    }

    public void SaveUser(User user)
    {
        int userID = user.ID;
        DateTime createDate = user.CreatedOn;
        DateTime updateDate = DateTime.Now;
        long phoneNumber = PhoneNumberConverter.Parse(user.PhoneNumber);
        using (TransactionScope tsc = new TransactionScope())
        {
            if (user.ID == 0)
            {
                createDate = updateDate;
                userID = db.InsertUser(user.Name, phoneNumber, createDate,
                    updateDate);
            }
            else
            {
                db.UpdateUser(user.ID, user.Name, phoneNumber, updateDate);
            }
            tsc.Complete();
        }
        user.ID = userID;
        user.CreatedOn = createDate;
        user.LastModified = updateDate;
    }
}

请注意,我在这里做了一堆“假设”,比如使用TransactionScope和某种名为IDatabase的精简CRUD图层类型。 这些并不重要,它们只是用来说明工作流程:

  1. 有一些处理“业务逻辑”的“存储库”类 - 即在用户点击“保存”和实际进入数据库之间发生的所有事情。您可以像我一样实施单独的AddUpdate方法,或单个Save方法。

  2. 您需要在Add / Update / Save方法中进行任何数据转换。这样做取代了在UI级别进行验证的需要;我之前提到PhoneNumberConverter的原因是您可能希望同时公开ValidateConvert方法,这样您的存储库和UI都可以依赖于相同的中央验证/转换逻辑。当然,在MVC 2.0中,您可以使用数据注释 - PhoneNumber枚举中实际上有一个DataType成员。

  3. 您的Save方法(或AddUpdate方法)采用未附加的实体并将其保存到数据库中。此方法检查ID并选择是否根据该ID插入或更新。无论哪种方式,它都会在数据库事务成功后更新传递给它的原始User对象 。这也应该回答您的问题#1 - 如果您的数据库中有IDENTITY列,那么您的数据库负责生成ID;你没有在你的应用程序中生成它们。

  4. 另一种方法是Save方法返回从实际存储在数据库中的任何内容初始化的全新User实例。换句话说,它在SELECTINSERT后执行UPDATE。虽然这确实有点可靠,但是存在显着的性能折衷。

    从技术上讲,存储库是模型的一部分,它应该从基本层面回答“where”问题,尽管我倾向于将其视为一个单独的层。

    我不确定这回答你的问题有多好 - 回答这样的“设计”问题有点棘手 - 但我发现这个设计在大多数情况下都能很好地工作,它遵循DRY原则并且很容易维持。

相关问题