我有以下代码:
ICommand _navigateAddNewAddress;
public ICommand NavigateAddNewAddress => _navigateAddNewAddress ?? (_navigateAddNewAddress = new Command(async (sender, args) =>
{
try
{
App.PushPage(AppPage.PROFILE_ADD_NEW_RESIDENTIAL_ADDRESS);
}
catch (Exception ex)
{
App.LogError(ex);
}
}));
我为Host设置了一个属性:if (await TryUpdateModelAsync<Host>(
hostToUpdate,
"Host",
s => s.Name, s => s.Description, s => s.Address, s => s.Postcode, s => s.Suburb,
s => s.State))
{
try
{
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
catch (DbUpdateConcurrencyException ex)
{
var exceptionEntry = ex.Entries.Single();
var clientValues = (Host)exceptionEntry.Entity;
var databaseEntry = exceptionEntry.GetDatabaseValues();
if (databaseEntry == null)
{
ModelState.AddModelError(string.Empty, "Unable to save. " +
"The host was deleted by another user.");
return Page();
}
var dbValues = (Host)databaseEntry.ToObject();
await setDbErrorMessage(dbValues, clientValues, _context);
// Save the current RowVersion so next postback
// matches unless an new concurrency issue happens.
Host.RowVersion = (byte[])dbValues.RowVersion;
// Must clear the model error for the next postback.
ModelState.Remove("Host.RowVersion");
}
}
和LastDateModified
,该属性是计算得出/预定义的值
即{{1}的LastModified
和DateTime.Now
的{{1}}。
那么如何将其传递给此代码?
LastDateModified
答案 0 :(得分:2)
您可以在保存对象之前设置(替代)值:
var hostToUpdate = await _context.Host.FindAsync(s => s.Id == id);
if (await TryUpdateModelAsync(
hostToUpdate,
"host", // empty with MVC
s => s.Name, s => s.Description, s => s.Address,
s => s.Postcode, s => s.Suburb, s => s.State))
{
try
{
hostToUpdate.LastModified = DateTime.Now;
hostToUpdate.LastDateModifiedBy = _userManager.GetUserId(User);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
// ...
}
请注意,LastModified
和LastDateModifiedBy
不是TryUpdateModelAsync
语句的一部分。但是如果是的话,这些值将被操作覆盖。
从剃须刀页面documentation:
DB上下文跟踪内存中的实体是否同步 以及它们在数据库中的对应行。数据库上下文同步 信息确定调用SaveChangesAsync时会发生什么。
通过Mvc documentation(不再更新):
实体框架的自动更改跟踪设置了已修改 在由表单输入更改的字段上标记。当。。。的时候 调用SaveChanges方法后,实体框架创建SQL 语句以更新数据库行。
要解释为什么这样做,首先TryUpdateModelAsync更新用户更新的字段,然后该操作更新其他字段。所有这些都由实体框架进行跟踪和保存。这是默认的实体框架行为。
请注意,您可以选择添加自动更新字段的代码。在那种情况下,您不会忘记设置它们,并且节省了几行代码。而且您根本不必更改代码。
该策略是实体实现基本字段并在保存更改时对其进行更新。这是更扩展的版本:
public interface IBaseEntity
{
DateTime LastDateModified { get; set; }
string LastDateModifiedBy { get; set; }
DateTime DateCreated { get; set; }
string DateCreatedBy { get; set; }
}
public class Host : IBaseEntity
{
// the other fields
// ...
public DateTime LastDateModified { get; set; }
public string LastDateModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public string DateCreatedBy { get; set; }
}
上下文:
public partial class MyContext : DbContext
{
// Reference to the name of the current user.
private readonly string _userName;
public MyContext(DbContextOptions<MyContext> options, IHttpContextAccessor httpContext)
: base(options)
{
// Save the name of the current user so MyContext knows
// who it is. The advantage is that you won't need to lookup
// the User on each save changes.
_userName = httpContext.HttpContext.User.Identity.Name;
}
public virtual DbSet<Host> Host { get; set; }
// You'll only need to override this, unless you are
// also using non-async SaveChanges.
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
UpdateEntries();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
// You can move this to another partial class.
private void UpdateEntries()
{
// Modified
var modified = ChangeTracker.Entries().Where(v => v.State == EntityState.Modified && typeof(IBaseEntity).IsAssignableFrom(v.Entity.GetType())).ToList();
modified.ForEach(entry =>
{
((IBaseEntity)entry.Entity).LastDateModified = DateTime.UtcNow;
((IBaseEntity)entry.Entity).LastDateModifiedBy = _userName;
});
// Added
var added = ChangeTracker.Entries().Where(v => v.State == EntityState.Added && typeof(IBaseEntity).IsAssignableFrom(v.Entity.GetType())).ToList();
added.ForEach(entry =>
{
((IBaseEntity)entry.Entity).DateCreated = DateTime.UtcNow;
((IBaseEntity)entry.Entity).DateCreatedBy = _userName;
((IBaseEntity)entry.Entity).LastDateModified = DateTime.UtcNow;
((IBaseEntity)entry.Entity).LastDateModifiedBy = _userName;
});
}
// ...
}
在启动中添加HttpContextAccessor:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
现在,每次保存实现IBaseEntity的对象时,这些字段都会自动更新。
请注意,我没有在此处注入UserManager。如果用户包含名称声明,则可以使用该名称声明。这将保存对数据库的调用。
作为一项改进,您可以编写一个新服务来解决用户名并注入用户名。