Вопрос о ASP.NET MVC 2 Custom ViewModels - PullRequest
0 голосов
/ 12 июля 2010

В моем проекте есть мой dbml-файл Linq To SQL, слой репозитория для каждой таблицы БД и уровень сервиса для каждого репозитория.

В моем сервисе у меня есть несколько метаданных для проверки, а также я расширяюКаждый (табличный) класс для добавления некоторой пользовательской информации к объекту (вы увидите это в приведенном ниже коде).

Мой вопрос заключается в том, следует ли мне рассмотреть возможность создания пользовательского ViewModal для каждого (табличного) класса вместоиспользовать расширенный класс в слое обслуживания?

Ниже приведен пример того, что у меня сейчас.

Репозиторий

Namespace Domain 
#Region "Interface" 
    Public Interface IUserRepository 
        Sub AddUser(ByVal openid As OpenID) 
        Function GetUsers() As IQueryable(Of User) 
        Sub UpdateUser(ByVal user As User) 
        Sub SubmitChanges() 
    End Interface 
#End Region 
#Region "Repository" 
    Public Class UserRepository : Implements IUserRepository 
        Private dc As MyDatabaseDataContext 
        Public Sub New() 
            dc = New MyDatabaseDataContext 
        End Sub 

        Public Sub AddUser(ByVal openid As OpenID) Implements IUserRepository.AddUser 
            Dim user As New User 
            user.MemberSince = DateTime.Now 
            openid.User = user 

            dc.OpenIDs.InsertOnSubmit(openid) 
        End Sub 

        Public Function GetUsers() As IQueryable(Of User) Implements IUserRepository.GetUsers 
            Dim users = (From u In dc.Users 
                        Select u) 
            Return users.AsQueryable 
        End Function 

        Public Sub UpdateUser(ByVal user As User) Implements IUserRepository.UpdateUser 
            Dim _user = (From u In dc.Users 
                Where u.ID = user.ID 
                Select u).Single 

            With _user 
                .About = user.About 
                .BirthDate = user.BirthDate 
                .Email = user.Email 
                .isClosed = user.isClosed 
                .isProfileComplete = user.isProfileComplete 
                .RegionID = user.RegionID 
                .Reputation = user.Reputation 
                .UserName = user.UserName 
                .WebSite = user.WebSite 
            End With 

        End Sub 

        Public Sub SubmitChanges() Implements IUserRepository.SubmitChanges 
            dc.SubmitChanges() 
        End Sub 
    End Class 
#End Region 
End Namespace 

Служба

Imports System.ComponentModel.DataAnnotations 

Namespace Domain 
#Region "Validation" 
    <MetadataType(GetType(UserMetaData))> _ 
    Partial Public Class User 
        Public Property UserRegion As String 
        Public Property LastSeen As DateTime 
        Public ReadOnly Property Slug(ByVal user As User) As String
           Get
              Return Replace(user.UserName, " ", "-")
           End Get
        End Property
    End Class 


    ''' <summary> 
    ''' Validation for all User data. 
    ''' </summary> 
    ''' <remarks>All validation is done at the Service Layer</remarks> 
    Public Class UserMetaData 

        <DisplayName("name")> _ 
        <Required(ErrorMessage:="Username is required.")> _ 
        <StringLength(30, ErrorMessage:="Username cannot exceed 30 characters.")> _ 
        <RegularExpression("^\w{3,30}$", ErrorMessage:="Not a valid username.")> _ 
        Public Property UserName As String 

        <DisplayName("email")> _ 
        <StringLength(50, ErrorMessage:="Email Address cannot exceed 50 characters.")> _ 
        <RegularExpression("^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})$", ErrorMessage:="Not a valid email address.")> _ 
        Public Property Email As String 

        <DisplayName("website")> _ 
        <StringLength(256, ErrorMessage:="Web Address cannot exceed 256 characters.")> _ 
        <RegularExpression("^http(s?)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$", ErrorMessage:="Not a valid website address.")> _ 
        Public Property WebSite As String 

        <DisplayName("about")> _ 
        <StringLength(2000, ErrorMessage:="Profile cannot exceed 2000 characters.")> _ 
        Public Property About As String 

        <DisplayName("region")> _ 
        <Required(ErrorMessage:="Region is required.")> _ 
        Public Property UserRegion As Integer 

        <DisplayName("birthdate")> _ 
        <DisplayFormat(ApplyFormatInEditMode:=True, ConvertEmptyStringToNull:=True, DataFormatString:="{0:MM/dd/yyyy}")> _ 
        Public Property BirthDate As DateTime 

    End Class 
#End Region 
#Region "Interface" 
    Public Interface IUserService 
        Sub AddUser(ByVal claimedidentifier As String, ByVal notes As String) 
        Function GetAllUsers() As IList(Of User) 
        Function GetUserByID(ByVal id As Integer) As User 
        Sub UpdateUser(ByVal user As User) 
        Sub SubmitChanges() 
    End Interface 
#End Region 
#Region "Service" 
    Public Class UserService : Implements IUserService 
        Private _UserRepository As IUserRepository 
        Public Sub New(ByVal UserRepository As IUserRepository) 
            _UserRepository = UserRepository 
        End Sub 

        Public Sub AddUser(ByVal claimedidentifier As String, ByVal notes As String) Implements IUserService.AddUser 
            Dim openid As New OpenID 
            openid.ClaimedIdentifier = claimedidentifier 
            openid.UserNotes = notes 
            _UserRepository.AddUser(openid) 
        End Sub 

        Public Function GetAllUsers() As System.Collections.Generic.IList(Of User) Implements IUserService.GetAllUsers 
            Return _UserRepository.GetUsers().Where(Function(u) (Not u.isClosed)).ToList 
        End Function 

        Public Function GetUserByID(ByVal id As Integer) As User Implements IUserService.GetUserByID 
            Return _UserRepository.GetUsers().Where(Function(u) (Not u.isClosed And u.ID = id)).SingleOrDefault 
        End Function 

        Public Sub UpdateUser(ByVal user As User) Implements IUserService.UpdateUser 
            _UserRepository.UpdateUser(user) 
        End Sub 

        Public Sub SubmitChanges() Implements IUserService.SubmitChanges 
            _UserRepository.SubmitChanges() 
        End Sub 

    End Class 
#End Region 

End Namespace 

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

    Dim user As Domain.User = UserService.GetUserByID(id) 
    Return View(user) 

Теперь я столкнулся с необходимостью отправить объект пользователяк свойству Slug всякий раз, когда мне нужно использовать Slug

    Dim user As Domain.User = UserService.GetUserByID(id) 
    user.Slug = user.Slug(user)  ''# this seems like a bit of a pain in the ass
    Return View(user) 

. Поэтому из-за этого лучше создать собственный ViewModal для каждого (табличного) класса и просто выполнить следующее

    Dim user As Domain.UserViewModal = New Domain.UserViewModal(UserService.GetUserByID(id))
    ''# The UserViewModal will automatically do all the work to create the 
    ''# Slug as well as other pertinent information
    Return View(user) 

Мне кажется, чтоРазделение это хорошая вещь, но все же требует много времени для сборки.Просто интересуетесь компромиссной выгодой или есть ли лучший способ сделать то же самое?

1 Ответ

1 голос
/ 12 июля 2010

Вероятно, вы обнаружите, что ваши классы моделей не всегда соответствуют 1: 1 с представлениями.Только по этой причине имеет смысл создавать объекты ViewModel и использовать их для взаимодействия с вашими представлениями, поскольку объект Viewmodel может быть составной частью различной информации о модели.

Это дает дополнительное преимущество, гарантируя, что ваши объекты Viewmodelспециально подходят для пользовательского интерфейса и могут содержать специфичные для экрана списки или другие свойства, которые не имеют никакого отношения к обычному объекту модели.Это позволяет вам реализовать преимущества и наоборот, потому что ваши объекты модели представления не должны быть загромождены / раздуты чем-либо, кроме их предназначения в жизни.(Объекты Linq to SQL должны отслеживать состояние и выполнять целый ряд вещей, совершенно не связанных с пользовательским интерфейсом.)

Хотя разделение является хорошей практикой, это, как вы говорите, может быть «болью в заднице».Чтобы упростить передачу информации между вашими экземплярами классов, загляните в Automapper , который делает это очень хорошо и позволяет вам исключить бесчисленные строки утомительного, но необходимого кода.

Удачного кодирования!

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