简体   繁体   English

[EF Core]:实体创建后设置属性值

[英][EF Core]: Set property value after entity creation

I have an entity stored in DB, but some of this entity properties should be set from another configuration source.我有一个存储在 DB 中的实体,但其中一些实体属性应该从另一个配置源设置。
Example:例子:

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) */
}

The problem is that I can't do it in Item 's constructor without creating a lot of abstractions, because this class is used by different libraries that have custom implementation of required configuration.问题是我不能在Item的构造函数中执行此操作而不创建大量抽象,因为此 class 由具有所需配置的自定义实现的不同库使用。
The only similar thing I've found is HasConversion , but in that predicate root object isn't accessible.我发现的唯一类似的东西是HasConversion ,但在那个谓词根 object 是不可访问的。 How can I implement this?我该如何实施?

Entity framework generates public partial class, so you can put this code in a separate file and it will not be lost if you regenerate the EF class files.实体框架生成公共部分 class,因此您可以将此代码放在单独的文件中,如果您重新生成 EF class 文件,它不会丢失。 I would suggest you use this approach even if you use Code First because it separates the database elements from the helper elements.即使您使用 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;
        }
    }
}

Just to post the Fluent method to achieve this as well.只是为了发布流畅的方法来实现这一点。

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

Depending on your usecase, and where the other configuration object is stored.根据您的用例,以及其他配置 object 的存储位置。 What you're trying to achieve can be done in several ways.您想要实现的目标可以通过多种方式完成。 But if a property is set to be ignored.但是如果一个属性被设置为被忽略。 Obviously will not be specified when you query the DbSets.显然不会在查询 DbSets 时指定。 EF Core requires an empty constructor, though it doesn't have to be public . EF Core 需要一个空的构造函数,尽管它不必是 public

  1. using access methods on ignored properties在被忽略的属性上使用访问方法
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);
  }
}

If you want to be fully sure that you don't mess up other consumers of the class如果您想完全确定不会弄乱 class 的其他消费者

  1. extended entity class using inheritance.使用 inheritance 的扩展实体 class。 NB: this entity is not mapped or used in any dbsets.注意:此实体未在任何数据库集中映射或使用。
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>();
   }
}

link to article for example例如文章链接
https://www.learnentityframeworkcore.com/configuration/fluent-api/ignore-method https://www.learnentityframeworkcore.com/configuration/fluent-api/ignore-method

-------------------------- UPDATE ------------------------- - - - - - - - - - - - - - 更新 - - - - - - - - - - - - --
For an automated way of doing this, after data have been fetched.对于执行此操作的自动方式,在获取数据后。 you could as you mentioned, try using value converters你可以像你提到的那样,尝试使用价值转换器

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

I'm personally not really a big fan of this approach, because you'd then have to inject your other data store into the DbContext to be allowed to do this.我个人并不是这种方法的忠实拥护者,因为您必须将其他数据存储注入 DbContext 才能被允许执行此操作。

IF you are using EF Core 5, a much cleaner way would be to use the EF Core Interceptors and tagging your query so the interceptor can pick it up.如果您使用的是 EF Core 5,一种更简洁的方法是使用 EF Core 拦截器并标记您的查询,以便拦截器可以接收它。 Then you are able to use real DI and have logic separated out enough.然后您就可以使用真正的 DI 并充分分离出逻辑。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM