无法使用 EFCore 将类的内部属性保存到数据库中 [英] Unable to save internal properties of a class into DB using EFCore

查看:14
本文介绍了无法使用 EFCore 将类的内部属性保存到数据库中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经历了以下 - stackoverflow 问题,它对我不起作用,而且我没有使用导航属性.

I have been through the following - stackoverflow question, it did not work for me and I am not using navigational properties.

Entity,位于 - Component.Shared.csproj(所有内容都是公开的)

Entity, lies in - Component.Shared.csproj (which has everything public)

public class Entity
{
    [Key]
    public Guid Id { get; set; }
    public Guid CreatedBy { get; set; }
    public Guid UpdatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
    public DateTime UpdatedOn { get; set; }
}

User,位于 - Component.User.csproj 并继承 Entity 类.

User, lies in - Component.User.csproj and inherits Entity class.

internal class User : Entity
{
    internal string FirstName { get; set; }
    internal string MiddleName { get; set; }
    internal string LastName { get; set; }
    internal string EmailId { get; set; }
    internal DateTime DateOfBirth { get; set; }
}

UserDbContext 在于 - Component.User.csproj.

internal sealed class UserDbContext : DbContext
{
    public UserDbContext(DbContextOptions<UserDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        //Remove pluralizing table name convention (Install package - Microsoft.EntityFrameworkCore.Relational)
        foreach (var entity in builder.Model.GetEntityTypes())
        {
            entity.SetTableName(entity.DisplayName());
        }

        base.OnModelCreating(builder);
    }

    internal DbSet<User> Users { get; set; }
}

UserRepository.cs (Component.User.csproj).

internal class UserRepository : IUserRepository
{
    #region Private Fields
    // To detect redundant calls
    private bool _disposed = false;
    private readonly IUnitOfWorkWithDbContext<UserDbContext, User> _uow;        
    #endregion Private Fields

    public UserRepository(IUnitOfWorkWithDbContext<UserDbContext, User> uow)
    {
        _uow = uow;
    }

    bool IRepository<User>.Create(User user)
    {
        var userEntry = _uow.DbContext.Users.Add(user);
        return userEntry.IsAdded(); // IsAdded is an extension method - return EntityState.Added == entityEntry.State;
    }
}

问题 - 如何强制 EF(目前,但将来可能是 Dapper/Raw ADO.NET 等)保存 User 或任何类的内部属性值重要的是,不要公开暴露它们,以避免对 Components.User.csproj 之外的代码进行任何直接更改?

Question - How do I force EF (for now, but it could be Dapper/Raw ADO.NET etc. in future) to save the values of internal properties of User or any class for that matter, without publicly exposing them, to avoid any direct changes from code outside of Components.User.csproj?

推荐答案

您可以通过这种方式设置保存实体的内部属性:

You can set internal properties on saving entities in this way:

public class ApplicationDbContext : DbContext
{
    private readonly IHttpContextAccessor _contextAccessor;

    public AuditTrail(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public void SaveChanges()
    {
        SetAuditInfo();
        base.SaveChanges();
    }

    public Task SaveChangesAsync()
    {
        SetAuditInfo();
        return base.SaveChangesAsync();
    }

    private void SetAuditInfo()
    {
        var entries = context.ChangeTracker
            .Entries<Entity>()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)
            .ToList();

        var claim = _contextAccessor?.HttpContext?.User.Claims.FirstOrDefault(c => c.Type == "UserId")?.Value;
        var userId = claim != null ? Guid.Parse(claim) : Guid.Empty;

        foreach (var entry in entries)
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    entry.Entity.CreatedOn = DateTime.Now;
                    entry.Entity.CreatedBy = userId;
                    break;

                case EntityState.Modified:
                    entry.Entity.UpdatedOn = DateTime.Now;
                    entry.Entity.CreatedBy = userId;
                    break;
            }
        }
    }
}

并且为了防止更改,您可以创建另一个对象,例如 UserDto,其内部属性只有 getter 或从 DTO 对象中删除它们.

And to prevent change you can create another object like UserDto that internal properties only have getter or remove them from DTO object.

另一个选项是在数据库上设置日期:

Another option is setting the date on the database:

entity.Property(e => e.CreatedOn)
    .HasDefaultValueSql("(getdate())")
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw;

您还可以使用阴影属性:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
        .Property<DateTime>("CreatedOn");
}

并设置值:

context.Entry(user).Property("CreatedOn").CurrentValue = DateTime.Now;

这篇关于无法使用 EFCore 将类的内部属性保存到数据库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆