2014-01-27 3 views
2

У меня есть приложение сфальсифицированы следующим образом ...MVC 5 EF 6 TPT и ViewModels

модели и подмодели

public class BaseModel 
{ 
    public int Id { get; set; }   
    // Other required properties 
} 

public class SubModel : BaseModel 
{ 
    public string SomeString { get; set; } 
    // Other SubModel properties 
} 

В контексте

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    base.OnModelCreating(modelBuilder); 
    modelBuilder.Entity<SubModel>().ToTable("SubModel"); 
} 

Model Binder, которая принимает строку определенный в моем представлении Create и возвращает соответствующий SubModel.

public class BaseModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     if (modelType.Equals(typeof(BaseModelBinder))) 
     { 
      string typeValue = bindingContext.ValueProvider.GetValue("ModelType").AttemptedValue; 
      Type type = Type.GetType(modelType.Namespace + "." + typeValue, true); 
      object model = Activator.CreateInstance(type); 

      bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type); 
      return model; 
     } 

     return base.CreateModel(controllerContext, bindingContext, modelType); 
    } 
} 

Контроллер

[Route("Create"), HttpGet] 
public ActionResult Create(string modelType) 
{ 
    // Get Model Type from modelType and convert into appropriate type 
    // to retrieve the proper editor template. 
    Type type = Type.GetType("MyApp.Models." + modelType); 
    object model = Activator.CreateInstance(type); 
    return View(model); 
} 

[Route("Create"), HttpPost] 
public ActionResult Create(BaseModel baseModel) 
{ 
    if (ModelState.IsValid) 
    { 
     var userId = Convert.ToInt32(IdentityExtensions.GetUserId(User.Identity)); 
     baseModel.UserId = userId; 
     baseModel.DatePosted = DateTime.UtcNow; 
     // If this is a SubModel, an insert is made into table BaseModel as well 
     // as an insert into the SubModel table for SubModel specific properties 
     // linked by the Id of the BaseModel as the SubModel Id 
     db.BaseModel.Add(baseModel); 
     db.SaveChanges(); 
     return RedirectToAction("List"); 
    }   
    return View(baseModel); 
} 

Создать Посмотреть

@model MyApp.Models.BaseModel 

@using (Html.BeginForm()) 
{ 
    @Html.AntiForgeryToken() 
    <div class="form-horizontal"> 
     @Html.ValidationSummary(true) 
     @Html.Hidden("ModelType", Model.GetType()) 
     @Html.EditorForModel() 
    </div> 
} 

редактор шаблонов для подмодели

@model MyApp.Models.SubModel 
// Form Stuff 

Это все работает нормально, и денди. Я могу вытащить Create View и отобразить правильный шаблон для запрошенной SubModel, и когда я его опубликую, действие Create HttpPost принимает его так же, как и тип BaseModel, и вставляет его как в таблицу SubModel, так и в таблицу BaseModel. Теперь то, что я хотел бы сделать, это создать ViewModels для моей BaseModel и SubModels, чтобы чистые модели домена.

ВЫПУСКА

Если я изменить мой контроллер для возврата ViewModel, когда я отправляю к Create действий, это не правильный тип, так как он не наследует от BaseModel.

Как создать ViewModel для BaseModel, который предоставляет только определенные свойства, которые я могу аннотировать Data для проверки на стороне клиента, а также создавать SubViewModels для SubModels и иметь SibViewModel также типа SubModel, который также будет иметь тип BaseModel, поскольку SubModels наследуются от BaseModel?

Я также хочу, чтобы SubViewModels наследовали свойства BaseModelViewModel, поскольку каждой SubModel потребуются части BaseModel.

Глядя на это link, ответ, который говорит о дженериках, возможно, путь, который я ищу, но не знаю, как его правильно реализовать.

Мне нужно взять ViewModel, передать его контроллеру Create [HttpPost] и вставить его в таблицу BaseModel (или SubModel и BaseModel в зависимости от ViewModel).

Долгий пост и может быть путаным, как я это сформулировал, так как мне трудно описать вещи, которые я иногда пытаюсь выполнить. Я тратил часы на часовые чтения на ASP.NET MVC, и, похоже, чем больше я читаю, тем больше я сомневаюсь в своих шаблонах дизайна, потому что существует так много альтернатив для выполнения той же задачи, что у каждого есть плюсы и минусы, зависящие от этого многие факторы ... Мой ум перегружен. Пожалуйста, помогите:]

ответ

3

Как я могу создать ViewModel для BaseModel, который предоставляет только определенные свойства, которые я могу Annotate данных для проверки на стороне клиента и, а также создать SubViewModels для подмодели и имеют SibViewModel быть также типа подмодели который также будет иметь тип BaseModel, поскольку SubModels наследуются от BaseModel?

Если я вас правильно понимаю, то вы не можете. Это потребует, чтобы ваш SubViewModel наследовал от BaseViewModel и от SubModel, что потребовало бы множественного наследования. И это невозможно в .NET.

Я также не рекомендовал бы его, даже если бы это было возможно. Я считаю, что причина, по которой вы хотите это сделать, - это использовать как можно больше кода и не поддерживать SubViewModel как «зеркало» вашей модели домена. Но действительно ли это правильный путь?

Рассмотрите это: предположим, что ваш SubViewModel наследовал от вашей модели домена. Это приведет к тому, что все свойства и методы будут доступны в вашей модели viewmodel и, следовательно, в ваших представлениях. Это также привело бы ко всем будущим свойствам и методам, которые будут доступны в ваших представлениях. Вы не можете больше контролировать, какие свойства и методы доступны для ваших представлений, без изменения модели домена. Вы можете добавить новые свойства и методы в свою модель просмотра, не добавляя их в свою модель домена, но вы не можете удалить те, которые унаследованы от модели домена. Я бы рассматривал это как недостаток. В идеале вы хотите, чтобы модели просмотра отображали именно те данные, которые нужно выполнить для выполнения своей задачи, а не больше. Помните, что идея «модели представлений» заключается в том, чтобы иметь модель, которая полезна для конкретного вида и задачи, которую они должны выполнить.

Существует также еще один недостаток. Чтобы включить проверку на стороне клиента, вам необходимо украсить свойства атрибутами Data Annotations. Если ваш SubViewModel наследует от вашей модели домена, чтобы повторно использовать свойства, такие как Name, ZipCode и т. Д., Тогда вам нужно поместить эти атрибуты в свойства модели домена. Итак, теперь у вас есть атрибуты, связанные с проверкой на стороне клиента MVC в вашей модели домена. Если позже вы решили повторно использовать свою модель домена в другом проекте, который использовал другую технологию, где вы не использовали MVC, то эти свойства были бы почти бесполезны. (Я говорю почти, потому что в конкретном сценарии вам может быть повезло и найти альтернативную структуру проверки, которая могла бы использовать атрибуты Data Annotations, но это не гарантировано) Фактически вы бы «загрязнили» вашу модель домена чем-то что не имеет отношения к домену.

Теперь я не говорю, что валидация не имеет отношения к домену, потому что это, безусловно, не так. Но я бы рассмотрел использование более общего способа проверки на уровне домена, чем использование атрибутов Data Annotations. (Например, для проверки правильности проверки)

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

Кроме того, если вы в дальнейшем выясните, что вам необходимо использовать другую структуру проверки в MVC, которая не использует атрибуты Data Annotations, то вам необходимо изменить модель домена, чтобы удалить атрибуты.

Вы видите рисунок здесь? Вы хотите что-то изменить в пользовательском интерфейсе (MVC), и из-за этого вам нужно что-то изменить в модели домена. Это действительно не идеально. Вы хотите, чтобы уровень домена и уровень пользовательского интерфейса были как можно более развязаны.

Я знаю, что, возможно, я пошёл по тангенсу здесь, и, возможно, прямо не ответил на ваш вопрос. Но моя точка зрения заключается в том, что я думаю, вам следует пересмотреть связь вашей модели домена и вашего приложения MVC вместе, получив модели вашего наследования от вашей модели домена.

И в самом деле, если вы это сделали, проблема, описанная выше, исчезнет.

1

Disclaime это только авансовый Комментарий

Как Рене отметил, что не выглядит как ваша проблема является реальной проблемой здесь

Поскольку ViewModel должна инкапсулировать модель и не наследует Это. Это в основном, как VM-M-часть MVVM работает

обычно ВМ должен быть похож на этот

public class VM 
{ 
    M model; 

    public M Model 
    { 
     get { return model; } 
     set { model = value; } 
    } 

    public int ID 
    { 
     get { return model.ID; } 
     set { model.ID = value; } 
    } 

    #region cTor 
    public VM(M m) 
    { 
     this.Model = m; 
    } 
    #endregion 
} 

но отделить Model-умывальницы ViewModle-слоя можно использовать интерфейс
так M может быть Class или Interface в зависимости от ваших потребностей.

+0

Я вижу, куда вы идете сюда, я собираюсь исследовать это больше. Спасибо за помощь. –

Смежные вопросы