Немного озадачен тем, куда положить вещи в ASP.NET MVC - PullRequest
4 голосов
/ 10 января 2010

Я работаю над своим первым приложением ASP.NET MVC, и у меня возникает небольшая путаница при создании / обновлении определенных данных.

У меня есть таблица базы данных User, сгенерированный LinqToSql частичный класс User и мой собственный пользовательский частичный класс User.

Я использую [Bind(Exclude = "Id, InsertDateTime, UpdateDateTime")] в моей версии User, потому что я не хочу, чтобы пользователи редактировали эти поля.

У меня также есть поле PhoneNumber, которое я делаю , чтобы пользователи могли его редактировать, но оно требует преобразования. Я сохраняю это в базе данных как 10 чисел, но когда я отображаю это пользователям через представление, я преобразовываю это в читаемый номер телефона в представлении как это:

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

Проблема в том, что когда пользователь нажимает кнопку Сохранить, номер телефона всегда будет в неправильном формате. Где-то мне нужно удалить все нечисловые символы (скобки, тире, косые черты и пробелы).

Вопросы

Как мне обработать действия Create и Edit для каждого из перечисленных ниже полей?

  1. Id - Я полагаю, что SQL-Server позаботится об этом автоматически, потому что все мои поля Id установлены как IDENTITY (1, 1). Я не тестировал подробно, но это, кажется, "просто работает". Пожалуйста, подтвердите.

  2. InsertDateTime - я хочу, чтобы для этого параметра было установлено значение DateTime.Now только для действий Создать, а не для действий Редактировать. Итак, где будет подходящее место для установки этого значения: User, UserController, UserFormViewModel или что-то еще?

  3. UpdateDateTime - Я хочу, чтобы это было установлено на DateTime.Now для действий «Создать» и «Редактировать», но опять же, куда мне поместить код, который выполняет это назначение?

  4. PhoneNumber - В отличие от трех приведенных выше полей, это поле доступно для редактирования пользователем, но его необходимо преобразовать из (888) 123-4567 в 8881234567, прежде чем произойдет обновление. Пара вопросов здесь: (1) Где подходящее место для этого преобразования? Я преобразовываю номер телефона в «читаемый пользователем» формат в представлении, где я должен преобразовать его обратно в формат «хранилище базы данных»? (2) Должен ли я добавить PhoneNumber к моему атрибуту [Bind(Exclude...)]?

Обновление

Из ответов до сих пор, я думаю, уточнить некоторые вещи, по крайней мере, для себя.

Прежде всего, вот список мест, где что-то происходит с User данными:

  1. User таблица в базе данных - обрабатывает присвоение идентификатора. Может предоставить значения по умолчанию для InsertDateTime и UpdateDateTime.

  2. User class - обрабатывает проверку с использованием метода GetRuleViolations().

  3. UserRepository class - абстрагирует функции сохранения данных (получить, получить все, добавить, удалить и сохранить).

  4. UserController class - обрабатывает пользовательские запросы и попытки публикации (индекс, детали, редактирование, публикация, редактирование, создание, публикация, создание и удаление).

  5. UserFormViewModel class - предоставляет строго типизированные данные для просмотра (объект User плюс вспомогательные данные для выпадающих меню).

  6. Views/User/Create.aspx и Views/User/Edit.aspx - генерирует HTML-код для отображения пользовательского интерфейса, комбинируя статические данные с динамическими данными (которые хранятся в модели представления).

В настоящее время я думаю, что ответственность за настройку Id, UpdateDateTime и InsertDateTime концептуально лежит на модели. База данных определенно ответственна за установку Id на вставке, но мне все еще немного неясно, где должны быть установлены поля даты и времени. Кажется, есть два варианта: хранилище (как предложено @Aaronaught) или класс User (который уже обрабатывает проверку).

Что касается вопроса преобразования PhoneNumber между ########## и (###) ### - ####, то это концептуально больше похоже на функцию "просмотра". Мне нравится идея @ Aaronaught иметь выделенный класс PhoneNumberConverter, и я, вероятно, пойду с этим, но все еще остается вопрос о том, кто вызывает методы для этого класса. Для этого я склоняюсь к своему UserFormViewModel классу.

Это приводит меня к двум последующим вопросам ...

Ответы на вопросы

  1. Должны ли поля UpdateDateTime и InsertDateTime быть присвоены в классе UserRepository или User?

  2. Имеет ли смысл вызывать методы преобразования телефонных номеров (в классе PhoneNumberConverter) из UserFormViewModel?

Ответы [ 2 ]

1 голос
/ 11 января 2010

Обычно у вас есть уровень бизнес-логики, который 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 и некоторый тип тонкого слоя CRUD, называемый IDatabase. Это не важно , они просто для иллюстрации рабочего процесса:

  1. Иметь некоторый тип класса «хранилище», который обрабатывает «бизнес-логику» - то есть все, что происходит между тем, когда пользователь нажимает «сохранить» и когда он фактически входит в базу данных. Вы можете реализовать отдельные методы Add и Update или один метод Save, как я сделал.

  2. Выполните любое преобразование данных, которое вам нужно сделать в методах Add / Update / Save. Это не заменяет необходимость проверки на уровне пользовательского интерфейса; причина, по которой я ссылался на PhoneNumberConverter выше, состоит в том, что вы можете захотеть, чтобы этот метод предоставлял оба метода Validate и Convert, чтобы и ваш репозиторий, и ваш пользовательский интерфейс могли полагаться на одну и ту же центральную логику проверки / преобразования , Конечно, в MVC 2.0 вы можете просто использовать аннотации данных для этого - на самом деле в перечислении DataType есть член PhoneNumber.

  3. Ваш метод Save (или метод Add или Update) берет неприкрепленную сущность и сохраняет ее в базе данных. Этот метод проверяет идентификатор и выбирает, вставлять или обновлять на основе этого. В любом случае он обновляет исходный User объект, переданный ему после успешного завершения транзакции базы данных . Это также должно ответить на ваш вопрос № 1 - если у вас есть столбец IDENTITY в вашей базе данных, то ваша база данных отвечает за генерацию идентификаторов; вы не генерируете их в своем приложении.

Альтернативный подход заключается в том, чтобы метод Save возвращал совершенно новые User экземпляры, инициализированные из того, что фактически было сохранено в базе данных. Другими словами, это SELECT после INSERT или UPDATE. Хотя это, как правило, более надежно, существует значительный компромисс между производительностью.

Технически, репозиторий является частью вашей модели, которая должна ответить на вопрос «где» на фундаментальном уровне, хотя я склонен думать о нем как о отдельном слое.

Я не уверен, насколько хорошо это отвечает на ваш вопрос - немного сложно ответить на подобные вопросы о дизайне, но я считаю, что этот дизайн работает довольно хорошо для большинства целей, он следует принципу СУХОЙ и довольно прост поддерживать.

1 голос
/ 10 января 2010

вот мой ответ на это:

1 - Да, вы правы, это делается с помощью столбца спецификации идентификатора сервера SQL «Автоинкрементный столбец»

2- Вы можете установить значение по умолчанию для этого поля в БД для функции getdate() sql, чтобы оно получило это значение в первый раз, когда оно будет вставлено в БД, и приняло значение datetime сервера. 1006 *

3 - это также может быть то же самое для значения по умолчанию, но в функции вы сохраняете данные в ex. Чтобы в строке, которую вы называете, отправлять изменения, установите это значение Datetime.Now.

4- первая часть Я думаю, что подходящее место будет в версии метода [Post], и я не думаю, что вы должны исключить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...