EF&;MVC:如何避免将继承的值传递给视图
本文关键字:继承 值传 视图 何避免 amp MVC EF | 更新日期: 2023-09-27 17:59:47
我的模型中有很多实体,它们继承自一个名为BaseEntity的抽象类。然后是一个"编辑"控制器,它接收一个Person对象作为参数并保存更改。在这个"编辑"控件的视图中,用户显然可以编辑实体的一些字段。视图仅包含作为隐藏字段的PersonId
和作为文本框的Name
。
我的实体看起来像这样:
public abstract class BaseEntity
{
public DateTime DateCreated { get; set; }
public DateTime DateLastModified { get; set; }
public int? UserIdLastModified { get; set; }
}
public class Person : BaseEntity
{
int PersonId { get; set; }
string Name { get; set; }
}
这就是控制器:
[HttpPost]
public ActionResult Edit(Person person, FormCollection collection)
{
/* ... do something with the FormCollection */
db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
}
我还覆盖数据库。SaveChanges()方法,因此它将自动设置DateLastModified
字段。但是由于DateCreated
将是DateTime.MinValue
,SaveChanges()将抛出异常。
为了隐私和简单起见,我不想将BaseEntity的字段作为隐藏字段添加到视图中。我知道我可以从控制器中的数据库加载实体,只更新Name
,但我认为这不是最好的解决方案,因为我必须在很多"编辑"控制器中这样做。每次模型发生变化时,我都必须更改控制器和视图。
在保存DateCreated
之前,有什么好方法可以将其返回到控制器?
编辑:谢谢你的回答。不过,这是我的SaveChanges方法。为了回答一些评论并进一步解释:问题是,如果我只像下面描述的那样设置DateLastModified
,那么基数。SaveChanges()将尝试用"1/1/0001 12:00:00 AM"覆盖DateCreated
(因为从未设置过)。这正确地抛出了异常。
我现在想做的是添加一些逻辑,以便在SaveChanges方法中获得BaseEntity以前的值。显然,我需要在某个地方进行另一个数据库调用,这样我就只能在一个地方而不是在每个控制器中使用逻辑。如果这种方法有什么问题,请告诉我。
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
//Find all Entities that are Added/Modified that inherit from my EntityBase
var objectStateEntries =
(from e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where e.IsRelationship == false && e.Entity != null && typeof(BaseEntity).IsAssignableFrom(e.Entity.GetType())
select e).ToList();
foreach (var entry in objectStateEntries)
{
var entityBase = (BaseEntity)entry.Entity;
if (entry.State == EntityState.Added)
{
entityBase.DateCreated = DateTime.UtcNow;
}
entityBase.DateModified = DateTime.UtcNow;
//new code for getting the previous value
if (entityBase.DateCreated == DateTime.MinValue)
{
//this is not working. just to show you my idea
var currentDBItem = this.Entry(entry.Entity).Entity as BaseEntity; //get previous value from database
entityBase.DateCreated = currentDBItem.DateCreated;
}
}
return base.SaveChanges();
}
当您需要在视图中支持ViewModels而不是实体时,这听起来像是一个经典的案例。
但是,假设您不打算更改您的体系结构,您只需要不更改DateCreated
字段,除非它处于"已添加"状态,而DateLastModified
仅处于"已修改"状态。类似于:
public override void SaveChanges()
{
foreach (var entry in this.ChangeTracker.Entries<BaseEntity>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.DateCreated = DateTime.Now;
break;
case EntityState.Modified:
entry.Entity.DateLastModified = DateTime.Now;
break;
}
}
base.SaveChanges();
}
此外,最好将DateLastModified
属性设置为可为null的DateTime?
,因为它只有在第一次更新后才有值。
根据您的更新:
试试这个:
if (entry.State == EntityState.Added)
entityBase.DateCreated = DateTime.UtcNow;
else
entry.Property(x => x.DateCreated).IsModified = false;
我认为您的最佳选择实际上是根据存储在隐藏字段中的id从数据库中检索原始实体,并且只更新可能更改的值。基本上就是你提出的解决方案。
我知道这看起来很无聊,但这是一种常见的做法。
顺便说一句,我还建议研究视图模型。
没有"简单"的解决方案(例如,将DateCreated添加为隐藏字段)。最好只是再次从数据库加载数据,或者您可以使用视图模型并编写自己的ModelBinder。