【问题标题】:[EF Core]: Set property value after entity creation[EF Core]:实体创建后设置属性值
【发布时间】:2021-04-09 13:21:17
【问题描述】:

我有一个实体存储在数据库中,但其中一些实体属性应该从另一个配置源设置。
示例:

public class Character {
     public Item[] Inventory { get; set; }
}
...
public class Item {
    public string Name { get; set; }
    public ItemUISize UISize { get; set; } /* <- should not be stored in DB and also  
    should be set from another config source on entity creation (fetching from db) */
}

问题是我不能在Item的构造函数中创建大量抽象,因为这个类被不同的库使用,这些库具有所需配置的自定义实现。
我发现的唯一类似的东西是HasConversion,但在那个谓词中,根对象是不可访问的。 我该如何实现?

【问题讨论】:

  • 将属性标记为 [NotMapped] 并延迟加载 getter 中的值?
  • @NicholasHunter 据我了解,这种方法需要在类中使用 ef 核心对象。但不允许在使用此类的另一个库中的依赖项。
  • 如果这些类型在不同的域之间共享,为什么不为您的域定义自己的模型来表示数据库中的数据?然后,您可以使用一些逻辑来创建共享类型的实例,其中的数据来自您的模型(数据库)和其他来源(配置)。这样您就可以将数据库模型与跨域域对象分离。

标签: c# .net entity-framework entity-framework-core


【解决方案1】:

只是为了发布 Fluent 方法来实现这一点。

public class MyDbContext : DbContext
{
   protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
     modelBuilder.Entity<Item>.Ignore(c => c.UISize);
   }
}

取决于您的用例以及其他配置对象的存储位置。您想要实现的目标可以通过多种方式完成。但是如果一个属性被设置为被忽略。显然不会在查询 DbSets 时指定。 EF Core 需要一个空的构造函数,尽管它不必是公共的

  1. 对被忽略的属性使用访问方法
public class Person 
{
  // It doesn't have to be public though. So you can still put some encapsulation
  // on your application logic. 
  protected Person()
  {
     // EF Core will use this. 
     // But since name only exists in database. Shoesize won't be set.
  }

  // Descriptive constructor to use for instantiating outside of the Database logic.
  public Person(string name)
  {
    Name = name; 
    ShoeSize = 1 // some value prefetched from configuration object ? 
  }
    

  public string Name { get; private set; }

  public int ShoeSize { get; private set; }

  public void SpecifyShoeSize(int shoeSize)
  {
     ShoeSize = shoeSize; 
  }
  
}

public MyDbContext : DbContext
{
  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Person>.Ignore(person => person.ShoeSize);
  }
}

如果你想完全确定你不会弄乱该类的其他消费者

  1. 使用继承的扩展实体类。注意:此实体未在任何数据库集中映射或使用。
public PersonwithShoeSize() : Person
{
  
  public int ShoeSize {get; set;}

  public PersonwithShoeSize(Person person, int shoeSize): base(person.Name)
  {
    ShoeSize = shoeSize;
  }
}

// you can ignore entity classes entirely through the fluid api as well
public class MyDbContext : DbContext
{
   protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
     modelBuilder.Ignore<PersonWithShoeSize>();
   }
}

例如链接到文章
https://www.learnentityframeworkcore.com/configuration/fluent-api/ignore-method

-------------- 更新 -------- -----
对于执行此操作的自动方式,在获取数据后。 你可以像你提到的那样,尝试使用价值转换器

.HasConversion(
fromprovider: ()=> {  /* since property is not mapped, this line doesn't matter  */ }, 
toprovider()=>{ /* set the not mapped property here */  })

我个人并不是这种方法的忠实拥护者,因为您必须将其他数据存储注入 DbContext 才能被允许这样做。

如果您使用的是 EF Core 5,更简洁的方法是使用 EF Core 拦截器并标记您的查询,以便拦截器可以接收它。然后你就可以使用真正的 DI 并有足够的逻辑分离出来。

EF Core 拦截器链接: https://docs.microsoft.com/en-us/ef/core/logging-events-diagnostics/interceptors

【讨论】:

  • 那么从 DbSet 抓取后没有办法自动应用 ShoeSize 吗?
  • 我已经更新了我的答案,以分享一些关于自动化的有效方法的意见。
【解决方案2】:

实体框架生成公共部分类,所以你可以把这段代码放在一个单独的文件中,如果你重新生成EF类文件,它不会丢失。即使您使用 Code First,我也建议您使用这种方法,因为它将数据库元素与辅助元素分开。

public partial class Item
{
    // Private data member.
    private ItemUISize uiSize;

    // Public property mediates access to private data member.
    // NotMapped is used to indicate properties of an entity class for which 
    // there are no corresponding columns in the database. 
    [NotMapped]
    public ItemUISize UISize {
        // Lazy load UISize.
        get { 
            if(this.uiSize == null) {
                // load UI size here
            }
            return this.uiSize;
        }
        set {
            this.uiSize = value;
        }
    }
}

【讨论】:

  • 谢谢,我认为这可能是对的,但是...我什至不允许在 getter 或构造函数中加载数据,因为这是来自共享程序集的类,并且加载数据的实现不同 =(.所以我想我需要一种方法来使用流利的 api 或其他东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 2020-04-16
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
相关资源
最近更新 更多