I'm having a difficult time figuring out how to update my entities and their related data. Using Lazyloading..
我很难搞清楚如何更新我的实体及其相关数据。使用Lazyloading ..
I have the following entity models
我有以下实体模型
public class Config
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int32 Id { get; set; }
[Required]
[MaxLength(100)]
public String Name { get; set; }
public virtual IList<DataField> DataFields { get; set; }
}
public class DataField
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int32 Id { get; set; }
[ForeignKey("Config")]
public Int32 ConfigId { get; set; }
public virtual Config Config { get; set; }
[Required, MaxLength(1000)]
public String Name { get; set; }
}
With the corresponding view models. I've stripped them down, removed validations and such.
具有相应的视图模型。我已将它们剥离,删除了验证等。
public class ConfigViewModel
{
public Int32 Id { get; set; }
public String Name { get; set; }
public IList<DataFieldViewModel> DataFields { get; set; }
public ConfigModel()
{
DataFields = new List<DataFieldViewModel>();
}
}
public class DataFieldViewModel
{
[Required]
public Int32 Id { get; set; }
public String Name { get; set; }
}
In my Edit.cshtml form I dynamically add new datafields, and when I post the form, they are properly deserialised to ConfigViewModel.DataFields. So long everything is working. But how do I convert these models, and update the entitymodels? If I post new datafields, their id's will be 0, and they should be added, but the ones that already have an Id, should be updated.. I don't know how to do this, and can't find anything related, or that I could understand.
在我的Edit.cshtml表单中,我动态添加新的数据字段,当我发布表单时,它们被正确地反序列化为ConfigViewModel.DataFields。一切都在运作。但是,我如何转换这些模型,并更新实体模型?如果我发布新的数据字段,他们的id将为0,并且应该添加它们,但是已经有Id的那些应该被更新..我不知道怎么做,并且找不到任何相关的,或者我能理解。
I have the following in my ConfigController.
我的ConfigController中有以下内容。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ConfigViewModel model)
{
try
{
if (!ModelState.IsValid)
return View();
var config = uow.Repository<Entity.Models.Config>().FindById(model.Id);
config.Name = model.Name;
// Do something with the datafields
// config.DataFields
uow.Repository<Entity.Models.Config>().Edit(config);
uow.Save();
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("Error", ex.Message);
return View(model);
}
}
In my repository I have:
在我的存储库中,我有:
public void Edit(TEntity entity)
{
var entry = Context.Entry<TEntity>(entity);
entry.State = EntityState.Modified;
}
My Edit.cshtml form looks like
我的Edit.cshtml表单看起来像
@for(var i = 0; i < Model.DataFields.Count; i++)
{
<tr>
<td>@Html.HiddenFor(m => m.DataFields[i].Id)</td>
<td>@Html.TextBoxFor(m => m.DataFields[i].Name)</td>
<td>@Html.EnumDropDownListFor(m => m.DataFields[i].Type)</td>
</tr>
}
1 个解决方案
#1
0
It looks like a couple of things are happening here.
看起来这里发生了一些事情。
If I understand your data structures correctly, you have a Config
object that has zero or more DataField
objects associated with it.
如果我正确理解了您的数据结构,那么您有一个Config对象,该对象具有与之关联的零个或多个DataField对象。
The Edit page of your application for editing Config
objects allows you to add new DataField
items or modify existing DataField
items.
用于编辑Config对象的应用程序的“编辑”页面允许您添加新的DataField项或修改现有的DataField项。
I'm assuming that in the commented section of your example:
我假设在你的例子的评论部分:
// Do Something with the DataFields
// config.DataFields
that you're translating the View Models back to your domain objects.
您正在将视图模型转换回域对象。
Now I'm going to assume that you are using a per-request lifetime for the DbContext
, as that's most typical in these scenarios. So, on each web request, a new DbContext
is instantiated as part of the instantiation chain of the MVC Controller and its dependencies (e.g. services, repositories, unit of work, etc.). So on this new request for editing Config
objects, the DbContext
is empty—it has no knowledge of any objects because it's a brand new DbContext
.
现在我将假设您正在使用DbContext的每请求生命周期,因为这在这些场景中是最典型的。因此,在每个Web请求上,新的DbContext被实例化为MVC控制器的实例化链及其依赖性(例如,服务,存储库,工作单元等)的一部分。因此,在这个编辑Config对象的新请求中,DbContext是空的 - 它不知道任何对象,因为它是一个全新的DbContext。
At this point, you need to Attach
the Config
entity to the DbContext
so that the DbContext
will start tracking it. If anything changed about the Config
entity (e.g. was the name changed, or were new DataField
objects added to the collection?), you will need to set the state of the entity within the DbContext
to Modified
(this you have done in your example above).
此时,您需要将Config实体附加到DbContext,以便DbContext将开始跟踪它。如果有关Config实体的任何更改(例如名称已更改,或者是否将新的DataField对象添加到集合中?),则需要将DbContext中的实体状态设置为Modified(这是您在上面的示例中所做的) )。
Attaching the Config
entity to the DbContext
will also result in attaching all the related DataField
objects that are referenced by the edited Config
entity. But there's a slight wrinkle. You will need to tell the DbContext
which entities are new, and which are modified. You can easily tell new entities from modified entities because the DataField.Id
property will be 0. But how do you tell if an existing DataField
entity has been returned unchanged? This is important, because simply attaching the DataField
entities to the DbContext
puts them in an Unmodified
state within the context. So, if there were any changes on an existing entity, those changes would not be persisted when committing the context.
将Config实体附加到DbContext还将导致附加由编辑的Config实体引用的所有相关DataField对象。但是有轻微的皱纹。您需要告诉DbContext哪些实体是新的,哪些是被修改的。您可以轻松地从修改后的实体中告诉新实体,因为DataField.Id属性将为0.但是,如何判断现有DataField实体是否未更改?这很重要,因为简单地将DataField实体附加到DbContext会使它们在上下文中处于未修改状态。因此,如果现有实体有任何更改,则在提交上下文时不会保留这些更改。
A naive approach to solve this problem would entail setting all DataField
entities whose Id
property is non-zero to the Modified
state. This will increase load on the database (but for a small application, this will be negligible). However, if you have any triggers or some other mechanism for auditing when records are created or updated, this is not a good solution. Assuming you are not performing auditing, the naive approach may work well:
解决此问题的简单方法是将所有Id属性为非零的DataField实体设置为Modified状态。这将增加数据库的负载(但对于小型应用程序,这将是可以忽略不计的)。但是,如果在创建或更新记录时有任何触发器或其他一些审核机制,则这不是一个好的解决方案。假设您没有执行审计,那么天真的方法可能会很好:
public void Edit(TEntity config)
{
Context.Attach<TEntity>(config);
Context.Entry<TEntity>(config).State = EntityState.Modified;
foreach(var df in config.DataFields)
{
Context.Entry<DataField>(df).State = EntityState.Modified;
}
// I noticed you never saved the changes to the DbContext. Do you need
// to do this here, or are you doing it with your UOW somewhere else??
Context.SaveChanges();
}
Again, this is a naive approach that should generally work well for small applications. At the very least, it should give you a better idea of the kinds of things you need to be aware of when working with Entity Framework in a disconnected N-Tier scenario.
同样,这是一种天真的方法,通常应该适用于小型应用程序。至少,它应该让您更好地了解在断开连接的N层方案中使用Entity Framework时需要注意的事项。
Also, I highly recommend you check out the following books:
此外,我强烈建议您查看以下书籍:
- Programming Entity Framework
- Programming Entity Framework: DbContext
- Programming Entity Framework: Code First
编程实体框架
编程实体框架:DbContext
编程实体框架:代码优先
Each of those books discusses the scenario you're talking about. You may want to start with the Code First book since you are using code first.
每本书都讨论了你所谈论的场景。您可能希望从Code First书开始,因为您首先使用代码。
HTH
#1
0
It looks like a couple of things are happening here.
看起来这里发生了一些事情。
If I understand your data structures correctly, you have a Config
object that has zero or more DataField
objects associated with it.
如果我正确理解了您的数据结构,那么您有一个Config对象,该对象具有与之关联的零个或多个DataField对象。
The Edit page of your application for editing Config
objects allows you to add new DataField
items or modify existing DataField
items.
用于编辑Config对象的应用程序的“编辑”页面允许您添加新的DataField项或修改现有的DataField项。
I'm assuming that in the commented section of your example:
我假设在你的例子的评论部分:
// Do Something with the DataFields
// config.DataFields
that you're translating the View Models back to your domain objects.
您正在将视图模型转换回域对象。
Now I'm going to assume that you are using a per-request lifetime for the DbContext
, as that's most typical in these scenarios. So, on each web request, a new DbContext
is instantiated as part of the instantiation chain of the MVC Controller and its dependencies (e.g. services, repositories, unit of work, etc.). So on this new request for editing Config
objects, the DbContext
is empty—it has no knowledge of any objects because it's a brand new DbContext
.
现在我将假设您正在使用DbContext的每请求生命周期,因为这在这些场景中是最典型的。因此,在每个Web请求上,新的DbContext被实例化为MVC控制器的实例化链及其依赖性(例如,服务,存储库,工作单元等)的一部分。因此,在这个编辑Config对象的新请求中,DbContext是空的 - 它不知道任何对象,因为它是一个全新的DbContext。
At this point, you need to Attach
the Config
entity to the DbContext
so that the DbContext
will start tracking it. If anything changed about the Config
entity (e.g. was the name changed, or were new DataField
objects added to the collection?), you will need to set the state of the entity within the DbContext
to Modified
(this you have done in your example above).
此时,您需要将Config实体附加到DbContext,以便DbContext将开始跟踪它。如果有关Config实体的任何更改(例如名称已更改,或者是否将新的DataField对象添加到集合中?),则需要将DbContext中的实体状态设置为Modified(这是您在上面的示例中所做的) )。
Attaching the Config
entity to the DbContext
will also result in attaching all the related DataField
objects that are referenced by the edited Config
entity. But there's a slight wrinkle. You will need to tell the DbContext
which entities are new, and which are modified. You can easily tell new entities from modified entities because the DataField.Id
property will be 0. But how do you tell if an existing DataField
entity has been returned unchanged? This is important, because simply attaching the DataField
entities to the DbContext
puts them in an Unmodified
state within the context. So, if there were any changes on an existing entity, those changes would not be persisted when committing the context.
将Config实体附加到DbContext还将导致附加由编辑的Config实体引用的所有相关DataField对象。但是有轻微的皱纹。您需要告诉DbContext哪些实体是新的,哪些是被修改的。您可以轻松地从修改后的实体中告诉新实体,因为DataField.Id属性将为0.但是,如何判断现有DataField实体是否未更改?这很重要,因为简单地将DataField实体附加到DbContext会使它们在上下文中处于未修改状态。因此,如果现有实体有任何更改,则在提交上下文时不会保留这些更改。
A naive approach to solve this problem would entail setting all DataField
entities whose Id
property is non-zero to the Modified
state. This will increase load on the database (but for a small application, this will be negligible). However, if you have any triggers or some other mechanism for auditing when records are created or updated, this is not a good solution. Assuming you are not performing auditing, the naive approach may work well:
解决此问题的简单方法是将所有Id属性为非零的DataField实体设置为Modified状态。这将增加数据库的负载(但对于小型应用程序,这将是可以忽略不计的)。但是,如果在创建或更新记录时有任何触发器或其他一些审核机制,则这不是一个好的解决方案。假设您没有执行审计,那么天真的方法可能会很好:
public void Edit(TEntity config)
{
Context.Attach<TEntity>(config);
Context.Entry<TEntity>(config).State = EntityState.Modified;
foreach(var df in config.DataFields)
{
Context.Entry<DataField>(df).State = EntityState.Modified;
}
// I noticed you never saved the changes to the DbContext. Do you need
// to do this here, or are you doing it with your UOW somewhere else??
Context.SaveChanges();
}
Again, this is a naive approach that should generally work well for small applications. At the very least, it should give you a better idea of the kinds of things you need to be aware of when working with Entity Framework in a disconnected N-Tier scenario.
同样,这是一种天真的方法,通常应该适用于小型应用程序。至少,它应该让您更好地了解在断开连接的N层方案中使用Entity Framework时需要注意的事项。
Also, I highly recommend you check out the following books:
此外,我强烈建议您查看以下书籍:
- Programming Entity Framework
- Programming Entity Framework: DbContext
- Programming Entity Framework: Code First
编程实体框架
编程实体框架:DbContext
编程实体框架:代码优先
Each of those books discusses the scenario you're talking about. You may want to start with the Code First book since you are using code first.
每本书都讨论了你所谈论的场景。您可能希望从Code First书开始,因为您首先使用代码。
HTH