I like to add some data to a column, from a method instead of a property. Is this somehow possible in EF Core?
For example, the config code could look like this:
internal class MyEntityTypeConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.ToTable("Table1");
// Add column "Value1" and set it with the return value of myEntity.GetValue()
builder.Property<string>("Value1").WithValue(myEntity => myEntity.GetValue()); // TODO create WithValue
builder.HasKey(o => o.Id);
}
}
in this case, the WithValue
method won't exist.
For example, I will save 2 entities.
GetValue()
for entity 1 returns "I am Entity 1"
GetValue()
for entity 2 returns "I am Entity 2"
Then I like store "I am Entity 1"
and "I am Entity 2"
in the column Value1
Jairo's solution with the ValueGenerator
worked perfect for me! I made the WithValue
like this:
internal class ValueRetriever<TEntityEntry, TResult> : Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator<TResult>
{
private readonly Func<TEntityEntry, TResult> _retrieve;
public ValueRetriever(Func<TEntityEntry, TResult> retrieve)
{
_retrieve = retrieve;
}
public override bool GeneratesTemporaryValues => false;
public override TResult Next(EntityEntry entry) => _retrieve((TEntityEntry)entry.Entity);
}
WithValue
extension:
public static void WithValue<TEntityEntry, TResult>(this PropertyBuilder<TResult> propertyBuilder, Func<TEntityEntry, TResult> retrieve)
{
propertyBuilder.HasValueGenerator((property, type) => new ValueRetriever<TEntityEntry, TResult>(retrieve));
}
Usage:
builder
.Property<string>("Value1")
.WithValue<MyEntity, string>(myEntity => myEntity.GetValue());
I think shadow properties can help you.
EF Core shadow properties let you define & persist non-domain data, data that are not defined in your classes. You define shadow properties in your DbContext, and you use the DbContext to set their values.
To define them:
modelBuilder.Entity<MyEntity>().Property<String>("Value1");
To set their values:
dbContext.Entry(myEntity).Property("Value1").CurrentValue = myEntity.GetValue();
Also, you can use the HasValueGenerator extension method to set a value generator that can get the value from your entity:
modelBuilder.Entity<MyEntity>().Property<string>("Value1").HasValueGenerator<ValueGenerator>();
The Value Generator:
class ValueGenerator : Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator
{
public override bool GeneratesTemporaryValues => false;
protected override object NextValue(EntityEntry entry) => ((MyEntity) entry.Entity).GetValue();
}
The entity:
class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string GetValue() => $"My Name: {Name}";
}