Вычисляемое свойство в MVC 5 ViewModel вместо класса модели

1

Я искал StackOverflow и MSDN и нашел несколько страниц, которые, как я чувствовал, помогли бы мне, но как только я попытался реализовать решения, всегда было что-то немного отличающееся от того, что мне было нужно, поэтому теперь я здесь, после нескольких часов вытягивания волос.

Проблема: у меня есть расчетное свойство в моем классе модели. Имя класса - Render и представляет собой модель для Photo Renderings. Вычисленное свойство будет использоваться как имя для Zip файла, который я собираю вместе в ONE VIEW для пользователя, в зависимости от того, на какой странице Render Detail они находятся. Очевидно, мы не хотим делать это в модели, потому что не каждый взгляд или даже большинство представлений будут использовать его.

Вопрос: Как перенести это вычисляемое свойство в мой ViewModel?

Ниже вы увидите мой текущий и рабочий.

  • Класс рендера
  • Просмотр модели
  • Контроллер &
  • Применимый код бритвы

Класс рендера

public class Render
{
    public Render()
    {

    }

    public int RenderId { get; set; }
    public string ClientName { get; set; }
    public string Title { get; set; }
    public string JobId { get; set; }
    public string Comment { get; set; }

    public ICollection<Image> Images { get; set; }

    public string ZipFileName
    {
        get { return (ClientName + "-" + Title + "-" + JobId)
                .Replace(" ", string.Empty); }
    }
}

Просмотр модели

public class RenderDetailViewModel
{
    public IEnumerable<Render> AllRenders { get; set; }
    private readonly RenderLibContext _db = new RenderLibContext();

    public void PopulateRenderDetailModel(int id)
    {
        AllRenders = _db.Renders.Include("Images")
            .Where(r => r.RenderId == id)
            .ToList();
    }
}

контроллер

public ActionResult Detail(int id=1)
{

    var render = _db.Renders.Include("Images")
                    .Include(r => r.Comments.Select(c => c.CommentImages))
                    .Include("VenueType").Include("ScreenCount")
                    .FirstOrDefault(r => r.RenderId == id);

    var model = new RenderDetailViewModel()
    {
        RenderId = render.RenderId,
        ClientName = render.ClientName,
        Title = render.Title,
        JobId = render.JobId,
        RenderMonth = render.RenderMonth,
        RenderYear = render.RenderYear,
        Comment = render.Comment,
        Venue = render.Venue,
        Mapping = render.Mapping,
        DefaultImageId = render.DefaultImageId

    };

    return View(model);
}

Код бритвы (сокращенно)

@model RenderLib.ViewModels.RenderDetailViewModel
...
@foreach (var group in Model.Images.Select(i => i.Version).Distinct().ToList())
{
  <a href="?Set=@group">Set @counter</a>
  <a href="/Renders/Download/@[email protected]">Download</a>
  ...
}
@foreach (var images in Model.Images
.Where(i => i.RenderId == Model.RenderId && i.Version == Request.QueryString["Set"]))
{
   <li data-thumb="/ImageStore/@images.Path">
     <a href="javascript:void(0)">
       <img src="~/ImageStore/@images.Path" />
     </a>
   </li>
}

Все, что находится над этой строкой, отлично работает, но мое рассчитанное свойство находится не в том месте, я бы хотел, чтобы оно было в моей ViewModel

Я знаю, что многие из вас хотели бы видеть, что кто-то задает такой вопрос, чтобы показать все, что они уже пытались убедиться, что я не просто прошу ответа, не пытаясь чего-то сначала, поэтому ниже приведен пример одного из многие попытки создать рассчитанное свойство в моей модели ViewModel:

Просмотреть модель (Моя попытка)

public class RenderDetailViewModel
{
    public IEnumerable<Render> RenderById { get; set; }
    private static readonly RenderLibContext _db = new RenderLibContext();

    private readonly Render _model;
    public RenderDetailViewModel(Render r)
    { _model = r; }

    public string ClientName { get { return _model.ClientName; } }
    public string Title { get { return _model.Title; } }
    public string JobId { get { return _model.JobId; } }

    public string ZipFileName
    {
        get { 
            return (ClientName + "-" + Title + "-" + JobId)
                        .Replace(" ", string.Empty); 
        }
    }

    public void PopulateRenderDetailModel(int id)
    {
        RenderById = _db.Renders.Include("Images")
            .Where(r => r.RenderId == id)
            .ToList();
    }
}

Эта попытка накрутила мой контроллер и ожидала, что я передам аргумент. Это не то, что я хотел сделать. Любая помощь будет принята с благодарностью. Надеюсь, я включил все необходимое, чтобы помочь всем, кто может помочь.

  • 3
    Примечание: НИКОГДА .. НИКОГДА .. НИКОГДА ... не делайте статический DbContext в веб-приложении. Это опасно и может привести к повреждению данных, поскольку веб-страницы являются многопользовательскими, а dbcontexts не являются многопользовательскими или многопоточными.
Теги:
razor
asp.net-mvc
model
asp.net-mvc-viewmodel

1 ответ

2
Лучший ответ

Модель представления не должна содержать логики базы данных. Он должен иметь только простые свойства. Кроме того, вы не можете использовать это в любом сценарии редактирования, где вам нужно отправить сообщение, потому что: а) у вас нет конструктора без параметров (вызывается исключение), и у вас нет настроек. Просто скопируйте свойства из вашей модели данных в вашу модель просмотра и сделайте сопоставление в контроллере (а затем вы можете удалить ZipFileName в модели данных)

public class RenderViewModel
{
  public int RenderId { get; set; }
  public string ClientName { get; set; }
  ....
  public IEnumerable<Image> Images { get; set; }
  public string ZipFileName
  {
    get { return (ClientName + "-" + Title + "-" + JobId)
            .Replace(" ", string.Empty); }
  }
}

контроллер

public ActionResult Detail(int id)
{
  var render = db.Renders.Include("Images").Where(r => r.RenderId == id).FirstOrDefault();
  var model = new RenderViewModel()
  {
    RenderId = render.RenderId,
    ClientName = render.ClientName,
    ....,
    Images = render.Images.Select(...), // not sure what your trying to do here
  });
  return View(model);
}

Посмотреть

@model RenderViewModel
@Html.DisplayFor(m => m.ClientName)
....
@foreach (var group in renders.Images)
{
  // better to use helpers to generate the link
  @Html.ActionLink("Download", "Download", "Renders", new { ID = Model.RenderId, fn = Model.ZipFileName })
}

Заметьте, я смущен тем, что вы пытаетесь сделать, когда выбираете изображения, связанные с каждым рендерингом. Для каждого изображения вы создаете идентичную ссылку (на основе RenderId и ZipFileName рендеринга). Есть ли свойство в Image которое должно быть включено в параметры маршрута, поэтому каждая ссылка загружает что-то другое?

  • 0
    Не могли бы вы также включить модель для Image (ваше представление не показывает, что вы пытаетесь делать с коллекцией Image )
  • 0
    Все еще не получаю это даже после редактирования. Если вы хотите отображать только один Render в представлении, почему у вас есть @foreach (var renders in Model.AllRenders) ? Можете ли вы подтвердить, что _db.Renders.Include("Images").Where(r => r.RenderId == id) возвращает только один Render , тогда я могу обновить свой ответ.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню