gpt4 book ai didi

asp.net-mvc - Entity Framework 不更新模型的复杂集合属性

转载 作者:行者123 更新时间:2023-12-04 00:03:57 28 4
gpt4 key购买 nike

之前可能已经以多种形式提出过这个问题,但我仍然认为他们对这种情况没有明确的解决方案。

我有以下实体类。

public class Project
{
public int ProjectId { get; set; }
[Required(ErrorMessage="please enter name")]
public string Name { get; set; }
public string Url { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public bool isFeatured { get; set; }
public bool isDisabled { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
[Required(ErrorMessage="Please select atleast one tag")]
public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}

public class Group
{
public int GroupId { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}

我有项目实体的 View 模型和这个 View 模型的自定义模型绑定(bind)器。
public class NewProjectModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ProjectNewViewModel model = (ProjectNewViewModel)bindingContext.Model ??
(ProjectNewViewModel)DependencyResolver.Current.GetService(typeof(ProjectNewViewModel));
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string searchPrefix = (hasPrefix) ? bindingContext.ModelName + ".":"";

//since viewmodel contains custom types like project make sure project is not null and to pass key arround for value providers
//use Project.Name even if your makrup dont have Project prefix

model.Project = model.Project ?? new Project();
//populate the fields of the model
if (GetValue(bindingContext, searchPrefix, "Project.ProjectId") != null)
{
model.Project.ProjectId = int.Parse(GetValue(bindingContext, searchPrefix, "Project.ProjectId"));
}

//
model.Project.Name = GetValue(bindingContext, searchPrefix, "Project.Name");
model.Project.Url = GetValue(bindingContext, searchPrefix, "Project.Url");
model.Project.CreatedOn = DateTime.Now;
model.Project.UpdatedOn = DateTime.Now;
model.Project.isDisabled = GetCheckedValue(bindingContext, searchPrefix, "Project.isDisabled");
model.Project.isFeatured = GetCheckedValue(bindingContext, searchPrefix, "Project.isFeatured");
model.Project.GroupId = int.Parse(GetValue(bindingContext, searchPrefix, "Project.GroupId"));
model.Project.Tags = new List<Tag>();

foreach (var tagid in GetValue(bindingContext, searchPrefix, "Project.Tags").Split(','))
{
var tag = new Tag { TagId = int.Parse(tagid)};
model.Project.Tags.Add(tag);
}

var total = model.Project.Tags.Count;

return model;
}

private string GetValue(ModelBindingContext context, string prefix, string key)
{
ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key);
return vpr == null ? null : vpr.AttemptedValue;
}

private bool GetCheckedValue(ModelBindingContext context, string prefix, string key)
{
bool result = false;
ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key);
if (vpr != null)
{
result = (bool)vpr.ConvertTo(typeof(bool));
}

return result;
}
}

//My project controller edit action defined as under:
[HttpPost]
[ActionName("Edit")]
public ActionResult EditProject( ProjectNewViewModel ProjectVM)
{
if (ModelState.IsValid) {
projectRepository.InsertOrUpdate(ProjectVM.Project);
projectRepository.Save();
return RedirectToAction("Index");
}
else {
ViewBag.PossibleGroups = groupRepository.All;
return View();
}
}


//Group Repository
public void InsertOrUpdate(Project project)
{
if (project.ProjectId == default(int)) {
// New entity
foreach (var tag in project.Tags)
{
context.Entry(tag).State = EntityState.Unchanged;
}
context.Projects.Add(project);
} else {
context.Entry(project).State = EntityState.Modified;
}
}

现在,当我在编辑 View 中有一个项目并为项目选择新标签并提交表单编辑操作参数时,使用模型绑定(bind)器并设置项目对象的所有属性,包括标签。但是当项目对象被传递给 grouprepository 的 insertorupdate 方法时,我们所做的所有更改都会在数据库中存储,除了 Tags 集合属性现在我对这件事感到非常沮丧。

请向我提供到目前为止已经开发出不会改变结构的解决方案。

最佳答案

你的 else 这样的东西InsertOrUpdate 中的案例(我认为 if 案例很好)可能有效:

//...
else {
// Reload project with all tags from DB
var projectInDb = context.Projects.Include(p => p.Tags)
.Single(p => p.ProjectId == project.ProjectId);

// Update scalar properties of the project
context.Entry(projectInDb).CurrentValues.SetValues(project);

// Check if tags have been removed, if yes: remove from loaded project tags
foreach(var tagInDb in projectInDb.Tags.ToList())
{
// Check if project.Tags collection contains a tag with TagId
// equal to tagInDb.TagId. "Any" just asks: Is there an element
// which meets the condition, yes or no? It's like "Exists".
if (!project.Tags.Any(t => t.TagId == tagInDb.TagId))
projectInDb.Tags.Remove(tagInDb);
}

// Check if tags have been added, if yes: add to loaded project tags
foreach(var tag in project.Tags)
{
// Check if projectInDb.Tags collection contains a tag with TagId
// equal to tag.TagId. See comment above.
if (!projectInDb.Tags.Any(t => t.TagId == tag.TagId))
{
// We MUST attach because tag already exists in the DB
// but it was not assigned to the project yet. Attach tells
// EF: "I know that it exists, don't insert a new one!!!"
context.Tags.Attach(tag);
// Now, we just add a new relationship between projectInDb and tag,
// not a new tag itself
projectInDb.Tags.Add(tag);
}
}
}

// context.SaveChanges() somewhere later

由于 EF 更改检测,SaveChanges 实际上将使用标记列表保存以前重新加载的项目。传入该方法的项目甚至没有附加到上下文中,只是用于更新重新加载的项目及其标签列表。

编辑
context.Tags.Attach(tag);添加到代码中,否则 SaveChanges将在数据库中创建新标签。

关于asp.net-mvc - Entity Framework 不更新模型的复杂集合属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7489342/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com