初始化实体的通用属性

时间:2018-11-12 12:58:29

标签: c# .net inheritance asp.net-core-2.0

我有很多实体模型,其中所有的实体模型都有一些共同的属性,如下所示。

  1. CreatedOn
  2. CreateBy
  3. LastModifiedon
  4. LastmodifiedBy

每次我需要将对象保存在数据库中时,都必须手动初始化这些属性。 我想要一个方法或一些基类,在这些类中我可以初始化这些属性,从而避免了一次又一次编写相同代码的麻烦。 注意:我想要没有基本构造函数的基类的泛型实现。 预先谢谢你

2 个答案:

答案 0 :(得分:3)

由于多种原因,您不能对您的实体类执行此操作。 public async Task<TwiMLResult> MyMethodName() { var response = new VoiceResponse(); var message = await _logic.GetMyLongText(); // This test I get from BL, it is an async method response.Say(message); var gather = new Gather(new [] {Gather.InputEnum.Speech}.ToList(), Url.ActionUri(nameof(AnotherMethodName), ControllerName), speechTimeout: "auto"); response.Append(gather); response.Redirect(Url.ActionUri(nameof(IncorrectOrNoInputMethod), ControllerName)); return TwilioResultFrom(response); } 可以通过默认值进行处理,但是其余的则需要实体类永远不会拥有的知识,例如CreatedOn或仅仅是实体类是否正在被修改或创建。

相反,您需要将此功能构建到上下文中。首先,您应该让所有实体类都实现一个特定的接口,以从特定的基类继承。无论哪种情况,您都希望在其中添加这些属性,以便可以确保任何实现/派生类都将具有所述属性。

然后,您可以将一个私有方法添加到您的上下文类中,例如:

HttpContext.User

然后,您需要在上下文中覆盖private void PopulateAuditTrailProperties() { var httpContextAccessor = this.GetService<IHttpContextAccessor>(); var username = httpContextAccessor?.HttpContext.User.Identity.Name; foreach (var entry in ChangeTracker.Entries<IEntity>().Where(x => x.State == EntityState.Added)) { entry.Entity.CreatedOn = DateTimeOffset.UtcNow; entry.Entity.CreatedBy = username; } foreach (var entry in ChangeTracker.Entries<IEntity>().Where(x => x.State == EntityState.Modified)) { entry.Entity.ModifiedOn = DateTimeOffset.UtcNow; entry.Entity.ModifiedBy = username; } } SaveChanges,以使每个方法在保存之前都调用此方法:

SaveChangesAsync

最后,您需要在public override int SaveChanges(bool acceptAllChangesOnSuccess) { PopulateAuditTrailProperties(); return base.SaveChanges(acceptAllChangesOnSuccess); } public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) { PopulateAuditTrailProperties(); return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); } 中添加一些内容:

Startup.cs

并且:

services.AddDbContext<MyContext>(o =>
    o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
        .UseInternalServiceProvider()); // Add this line

答案 1 :(得分:0)

我个人将使用接口定义。您的实体都将实现一个称为IAuditedEntity的接口(或您认为合适的任何名称)。该接口将声明您的四个属性(CreatedOn,CreateBy,LastModifiedOn,LastModifiedBy)为get和set。任何需要这些字段的实体都需要实现该接口。

然后在将记录更新到数据库时,检查对象是否实现IAuditEntity接口,例如如果(myRecord是IAuditedEntity)。如果确实实现了该接口,则将属性设置为适当的值。

在这种情况下,最好将对象强制转换为接口,以确保类型安全。

例如(((IAuditedEntity)myObj).CreatedOn = DateTime.Now。

此实现将允许您将创建和修改的字段拆分为两个单独的接口-create可以被视为修改,但是修改不一定是create操作。

从理论上讲,使用接口实现,您将能够将接口应用于不同的实体类型,但是将用于初始化这些字段的代码保留在一个地方。