データベース ストレージに Entity Framework コード ファーストを使用して、ここで説明したのと同様のアプローチを使用して、一時的なプロパティを実装したいと考えています。
現在の値を取得するために最適化し、履歴の遅延読み込みを行いたいのですが、上記のリンクのアプローチのように、使用ごとに親エンティティにボイラープレート コードを追加する必要はありません。
現時点では、以下のコードのようなものがあります。慣例により、コードの下に示すデータベース スキーマになります。
これは必要に応じて機能しますが、パフォーマンス上の理由から、現在のプロパティ値を取得するために必要な結合を避けたい (つまり、代わりに TemporalStrings.CurrentValue DB 列を Entities.Name に移動したい)。
私が試したら
modelBuilder.Entity<Entity>().Property(o => o.Name.CurrentValue).HasColumnName("Name");
うまくいきません。次のような例外が発生します
The type 'ConsoleApplication1.TemporalString' has already been configured as an entity type. It cannot be reconfigured as a complex type.
このマッピングを実現する方法はありますか、またはこの機能を実現するためのより良いアプローチはありますか?
コード:
public class TemporalString
{
public int Id { get; set; }
public string CurrentValue { get; set; } // Setter would be customized to append to History.
public virtual List<TemporalStringValue> History { get; set; }
// Other methods such as string ValueAt(DateTime) would exist.
}
public class TemporalStringValue
{
public int Id { get; set; }
public DateTime EffectiveFrom { get; set; }
public string Value { get; set; }
}
public class Entity
{
public int Id { get; set; }
public virtual TemporalString Name { get; set; }
}
public class TestDbContext : DbContext
{
public DbSet<Entity> Entities { get; set; }
public DbSet<TemporalString> TemporalStrings { get; set; }
public DbSet<TemporalStringValue> TemporalStringValues { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.Entity<Entity>().Property(o => o.Name.CurrentValue).HasColumnName("Name");
// TODO: Map DB column TemporalStrings.CurrentValue to DB column Entities.Name?
}
}
internal class Program
{
private static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TestDbContext>());
using (var context = new TestDbContext())
{
var entity = new Entity
{
Name = new TemporalString
{
CurrentValue = "Current Value",
History = new List<TemporalStringValue>
{
new TemporalStringValue
{
EffectiveFrom = DateTime.UtcNow,
Value = "Current Value"
},
new TemporalStringValue
{
EffectiveFrom = DateTime.UtcNow.AddMonths(-1),
Value = "Old Value"
},
new TemporalStringValue
{
EffectiveFrom = DateTime.UtcNow.AddMonths(-2),
Value = "Older Value"
}
}
}
};
context.Entities.Add(entity);
context.SaveChanges();
}
Console.Write("Done.");
Console.ReadKey();
}
}
結果のスキーマ:
Entities
(PK) Id
(FK) Name_Id (references TemporalStrings.Id)
TemporalStrings
(PK) Id
CurrentValue
TemporalStringValues
(PK) Id
EffectiveFrom
Value
(FK) TemporalString_Id
望ましいスキーマ:
Entities
(PK) Id
(FK) Name_Id (references TemporalStrings.Id)
Name (formerly TemporalStrings.CurrentValue)
TemporalStrings
(PK) Id
TemporalStringValues
(no change)