为什么在UpdateAsync上设置CreationTime和CreatorUserId?

时间:2017-11-13 05:02:31

标签: c# entity-framework audit aspnetboilerplate change-tracking

我正在呼叫UpdateAsync,但即使我没有传递这些值,它也会更新CreationTimeCreatorUserId列。它应该只更新所需的列。

{
  "testCode": "string",
  "testName": "string",
  "testDesc": "string",
  "id": 1
}
public async Task UpdateTest(TestDetailsDTO input)
{
    var classobj = ObjectMapper.Map<Test>(input);
    await UpdateAsync(classobj);
}
public class TestDetailsDTO : FullAuditedEntityDto
{
    public string TestCode { get; set; }
    public string TestName { get; set; }
    public string TestDesc { get; set; }
}

参数inputCreationTime服务方法中获得UpdateTest

public class Test : FullAuditedEntity
{
    public const int NVarcharLength20 = 20;
    public const int NVarcharLength30 = 30;
    public const int NVarcharLength50 = 50;

    [Required]
    [MaxLength(NVarcharLength20)]
    public virtual string TestCode { get; set; }

    [Required]
    [MaxLength(NVarcharLength30)]
    public virtual string TestName { get; set; }

    [MaxLength(NVarcharLength50)]
    public virtual string TestDesc { get; set; }
}

1 个答案:

答案 0 :(得分:1)

Current flow:

  1. ObjectMapper.Map<Test>(input) creates a new Test object.
  2. CreationTime and CreatorUserId are default(DateTime) and default(long?).
  3. ABP sets those values.

Correct flow:

  1. Get classobj from database.
  2. Restore CreationTime and CreatorUserId.
  3. Map input to classobj.

var classobj = repository.GetEntity(input.id); // 1
input.CreationTime = classobj.CreationTime;    // 2
input.CreatorUserId = classobj.CreatorUserId;  // 2
ObjectMapper.Map(input, classobj);             // 3

Better design:

  • Don't inherit FullAuditedEntityDto for input → skip step 2.

It's working, any other way around? Because it's calling extra GetEntity method.

The other way is to attach. The trade-off is that you have to map explicitly, not ObjectMapper.Map.

// Create new stub with correct id and attach to context.
var classobj = new Test { Id = input.Id };
repository.As<EfRepositoryBase<MyDbContext, Test>>().Table.Attach(classobj);

// Now the entity is being tracked by EF, update required properties.
classobj.TestCode = input.TestCode;
classobj.TestName = input.TestName;
classobj.TestDesc = input.TestDesc;

// EF knows only to update the properties specified above.
_unitOfWorkManager.Current.SaveChanges();