Сохранение входных данных из формы с использованием viewModel из другого объекта - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть представление Модель, которая отображает всю необходимую мне информацию в моей форме.

Как вы можете видеть ниже, мой ViewModel использует CustomerEntities.Я хочу сохранить информацию в таблице, которая использует CalendarEntities.Я думал о том, чтобы у Календаря была своя собственная сущность за пределами Customer, однако мне нужно использовать CustomerEntities, чтобы получить информацию от зарегистрированного пользователя для ввода в форму.Когда я помещаю элементы в HttpPost, он говорит, что CustomerEntities не содержит определения для событий.Есть ли способ обойти это, не перемещая События из своей собственной сущности в CustomerEntities?

Вот CalendarController

    private CalendarEntities customer = new CalendarEntities();

    private CustomerEntities db = new CustomerEntities();

    // GET: ServiceCalendar
    public ActionResult Index(string UserId)
    {
        if (UserId == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        AddEventViewModel modelInstance = AddEventViewModel.GetCustomerInfo(UserId, db);

        return View(modelInstance);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index([Bind(Include = "CustomerId,CustomerName,AllDay,Location,Title,Description,StartDate,EndDate")] EventModels.Entities.Events calendarEvent)
    {
        if (ModelState.IsValid)
        {
            db.Events.Add(calendarEvent);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(calendarEvent);
    }

Вот viewModel

public class AddEventViewModel
{
    public static AddEventViewModel GetCustomerInfo(string userId, CustomerEntities db)
    {
        var QCustInfo = from ad in db.Addresses
                        join ua in db.UserToAddresses on ad.AddressId equals ua.AddressId
                        join cus in db.CustomerNames on ad.CustomerId equals cus.CustomerId
                        where (ua.UserId == userId)
                        select new AddEventViewModel
                        {
                            CustomerId = cus.CustomerId,
                            CustomerName = cus.CustomerName,
                            //Location = ad.LocationName,
                            CustomerNames = cus
                        };
        var result = QCustInfo.SingleOrDefault();

        if (result != null)
        {
            result.Addresses = db.Addresses.Where(a => a.CustomerId == result.CustomerNames.CustomerId);

        };

        return result;
    }

    public int CustomerId { get; set; }
    [Display(Name = "Location Name")]
    public string Location { get; set; }
    public bool AllDay { get; set; }
    [Display(Name ="Title")]
    public string Title { get; set; }
    [Display(Name = "Description")]
    public string Description { get; set; }
    [DataType(DataType.DateTime), Required]
    [DisplayFormat(DataFormatString = "{0:dd/mm/yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "Start Date")]
    public DateTime StartDate { get; set; }
    [DataType(DataType.DateTime), Required]
    [DisplayFormat(DataFormatString = "{0:dd/mm/yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "End Date")]
    public DateTime EndDate { get; set; }
    [Display(Name = "Customer Name")]
    public string CustomerName { get; set; }

    public virtual CustomerNames CustomerNames { get; set; }
    public virtual IEnumerable<Addresses> Addresses { get; set; }
}

Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 07 декабря 2018

Что именно вы подразумеваете под "Есть ли способ обойти это, не перемещая События из своей собственной сущности в CustomerEntities?"Исходя из того, что вы показали, похоже, что вы создаете один DbContext для каждой сущности или для сущности верхнего уровня, которая действительно выделяет неприятный запах, если эти сущности являются частью одной и той же базы данных.DbContext не является сущностью, это контейнер для многих сущностей.Для небольших систем в нем легко размещаются все сущности или, по крайней мере, все сущности верхнего уровня, к которым необходимо обращаться напрямую.«Сущность» - это класс, представляющий строку в таблице в базе данных.

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

public class CalendarEntry
{
    public int CalendarEntryId { get; private set; }
    // .. Other properties...

    public virtual Customer Customer { get; private set; }
    public virtual List<CalendarEvent> Events { get; private set; } = new List<CalendarEvent>();
}

С аналогичными определениями сущностей для клиента и событий.

Был бы один единственный DbContext, который мог бы иметь:

public DbSet<CalendarEntry> CalendarEntries { get; }
public DbSet<Customer> Customers { get; }

Модели представления, с другой стороны, являются простыми, классы POCO, чьи данные копируются из сущностей, и не содержат сущности.Контроллер управляет областью действия DbContext для чтения сущностей, затем выбирает или отображает данные сущностей в модели представлений для передачи в представление.Он получает модели представлений из вида, загружает сущности и изменяет сущности на основе данных в модели представлений.

Таким образом, действие, которое получает событие календаря для обновления, я хотел бы получить метод, который бы принялмодель представления для представления нового события календаря, включая идентификатор записи календаря.Запись не будет создаваться в индексе события календаря, а скорее до этого, тогда индекс просто отображает модель представления для новой записи.Поэтому, возможно, на контроллере календаря будет действие для создания нового события, которое передаст CalendarEntryID, создаст модель представления CalendarEvent для записи и затем перенаправит на представление события календаря.ViewModel - это POCO, а не объект, еще ничего не передано в базу данных.В представлении CalendarEvent будет кнопка «Сохранить», которая принимает эту модель представления и управляет созданием сущности ...

public ActionResult Save(CalendarEventViewModel viewModel)
{
    if (!ModelState.IsValid)
        return View(viewModel);

    var calendarEntry = db.CalendarEntries.Include(x => x.Events)
        .Single(x => x.CalendarEntryId = viewModel.CalendarEntryId);

    var calendarEvent = new CalendarEvent
    {
        CalendarEntry = calendarEntry,
        EventName = viewModel.EventName,
        // .. etc.
    };
    calendarEntry.Events.Add(calendarEvent);
    db.SaveChanges(); 
    return RedirectToAction("Index");
}

Разница в том, что модели представления полностью независимы отсущности, которые их населяют.Они представляют данные, которые нужны представлению, и то, что контроллеру потребуется для определения местоположения соответствующих объектов, не более того.Вы можете использовать такие инструменты, как Automapper, чтобы эффективно копировать детали между объектами и просматривать модели.Обратите внимание, что в этом примере DbContext (db) не ссылается на DbSet для CalendarEvents?События являются дочерними для CalendarEntry, и контексту не нужен DbSet для каждой сущности, только те, которые нам нужны для непосредственного запроса.(сущности верхнего уровня) Я не хочу отдельных DbContexts для каждой сущности, потому что вы не можете использовать отношения между сущностями.В этом случае модель представления CalendarEvent будет иметь идентификатор CalendarEntry, который я могу использовать для нахождения записи.Затем я заполняю новую сущность для события из остальных деталей модели представления, затем добавляю эту новую запись в событие и вызываю SaveChanges.EF отслеживает изменения, внесенные в загруженный мной CalendarEntry, который распространяется на коллекцию событий.Мне не нужно отслеживать отдельный набор событий DbSet для добавления в контекст.

Другие вопросы, которые необходимо учитывать, это область действия DbContext (db).Вы хотите убедиться, что Контекст введен в ваш контроллер, а его срок действия ограничен сроком действия запроса.(Используя контейнер IoC, такой как Autofac, Unity и т. Д.), Вы хотите быть очень уверенными, что он не статичен и не работает дольше, чем запрос, потому что это приведет к проблемам с ресурсами / производительностью и потенциально к ошибкам / исключениям при одновременных запросах.

В худшем случае, если вы не уверены в том, как определяется область действия DbContext, или если он настроен как статический, вы должны изменить его использование на область действия внутри метода, а затем прочитать контейнеры Dependency Injection и IoC, чтобы охватить его дозапросить и внедрить его с помощью конструктора.

Например:

public ActionResult Save(CalendarEventViewModel viewModel)
{
    if (!ModelState.IsValid)
        return View(viewModel);

    using( var db = new myDbContext())
    {
        var calendarEntry = db.CalendarEntries.Include(x => x.Events)
            .Single(x => x.CalendarEntryId = viewModel.CalendarEntryId);

        var calendarEvent = new CalendarEvent
        {
            CalendarEntry = calendarEntry,
            EventName = viewModel.EventName,
            // .. etc.
        };
        calendarEntry.Events.Add(calendarEvent);
        db.SaveChanges(); 
    }
    return RedirectToAction("Index");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...