Я делаю веб-приложение MVC4, используя Entity Framework 5 (сначала база данных с сгенерированными POCO) для доступа к данным.
В приложении пользователь проходит через несколько экранов, создавая или редактируя документ (так называемый «тематическое исследование»). Когда они приходят к последнему экрану, их документ существует как POCO CaseStudy в памяти, и все в порядке, пока не пришло время сохранить эту структуру в базе данных.
Для хранения документа я определил несколько таблиц базы данных, которые, в свою очередь, сопоставляются с объектами EF POCO, используемыми бизнес-уровнем, которые затем используются контроллерами MVC. Таким образом, недолговечные DbContexts используются для получения POCO и сохранения их в сеансе между запросами.
В результате экран сохранения должен сохранять содержимое этого объекта POCO, который имеет свойства навигации, в существующие данные таблицы (таблицы категорий, макета и разделов), а также добавлять или обновлять данные (CaseStudySections и сам CaseStudy). Таким образом, все POCO либо новые, либо контекст, используемый для их извлечения, уже давно удален. Другими словами, все они «отстранены».
Что необычно в этом посте, так это то, что у меня уже есть рабочее решение. Проблема в том, что он громоздкий, хрупкий и неизящный. Я размещаю код ниже. Обратите внимание на итерацию по вложенным коллекциям, явное добавление и присоединение, необходимость получения объекта ввода и пометки отдельных свойств как измененных только для того, чтобы они были обновлены, а также ужасную песню и танец в конце, чтобы синхронизировать коллекцию AdditionalMaterials. Если это то, что требуется для работы с отдельными POCO в EF5, я буду разочарован.
Я что-то упустил? Соответствует ли это передовой практике? Есть ли более изящный и / или краткий способ прикрепить структуру POCO и вставить / обновить?
Код для сохранения тематического исследования:
public void SaveCaseStudy(CaseStudy caseStudy)
{
foreach (var s in caseStudy.CaseStudySections)
{
this.Entities.Sections.Attach(s.Section);
if (s.CreatedByRefId == default(Guid))
{
s.CreatedByRefId = this.UserRefId;
s.CreatedTime = DateTime.Now;
this.Entities.CaseStudySections.Add(s);
}
else
{
this.Entities.CaseStudySections.Attach(s);
var entry = this.Entities.Entry(s);
entry.Property(e => e.TextData).IsModified = true;
entry.Property(e => e.BinaryData).IsModified = true;
}
s.LastModifiedByRefId = this.UserRefId;
s.LastModifiedTime = DateTime.Now;
}
foreach (var m in caseStudy.AdditionalMaterials)
{
if (m.CreatedByRefId == default(Guid))
{
m.CreatedByRefId = this.UserRefId;
m.CreatedTime = DateTime.Now;
this.Entities.AdditionalMaterials.Add(m);
}
else
{
this.Entities.AdditionalMaterials.Attach(m);
}
m.LastModifiedByRefId = this.UserRefId;
m.LastModifiedByTime = DateTime.Now;
}
this.Entities.Layouts.Attach(caseStudy.Layout);
this.Entities.Categories.Attach(caseStudy.Category);
if (caseStudy.CreatedByRefId != default(Guid))
{
this.Entities.CaseStudies.Attach(caseStudy);
var entry = this.Entities.Entry(caseStudy);
entry.Property(e => e.CaseStudyName).IsModified = true;
entry.Property(e => e.CaseStudyTitle).IsModified = true;
}
else
{
this.Entities.CaseStudies.Add(caseStudy);
caseStudy.CreatedByRefId = this.UserRefId;
caseStudy.CreatedTime = DateTime.Now;
}
caseStudy.LastModifiedByRefId = this.UserRefId;
caseStudy.LastModifiedTime = DateTime.Now;
if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
{
caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
}
caseStudy.ApprovedByRefId = null;
caseStudy.ApprovedTime = null;
this.Entities.SaveChanges();
var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
.Select(m => m.AdditionalMaterialRefId)
.ToArray();
var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
.Where(m =>
m.CaseStudyRefId == caseStudy.CaseStudyRefId &&
!existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
.ToArray();
foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
{
this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
}
this.Entities.SaveChanges();
}