我一直在開發一個數據庫的框架,該框架將支持EF 4.3.1中使用Code First的數據版本控制。Code First導航屬性被保留但未加載
幾天前,我有模型持久和加載正確,但我打破了一些事情,因爲我無法弄清楚什麼是錯的。所有類都被映射並創建表,數據也被保存。所以一切順利,一切正常!但是,當我嘗試加載一個Registration
實體時,這些值都是默認構造函數設置它們的值。我想也許在調用Registration
構造函數之後數據沒有被加載,但是我正在結束當前的能力來弄清楚發生了什麼!
基本面這兩個類,從我的優化版本,能夠類派生...派生類的
public abstract class VersionBase<T> {
[Key]
public Int64 Id { get; protected set; }
public DateTime CreationDateTime { get; protected set; }
// Value is virtual to support overriding to let deriving classes specify attributes for the property, such as [Required] to specify a non-nullable System.String
public virtual T Value { get; internal set; }
protected VersionBase() {
CreationDateTime = DateTime.Now;
}
protected VersionBase(T value)
: this() {
Value = value;
}
}
public abstract class VersionedBase<TVersion, TBase>
where TVersion : VersionBase<TBase>, new() {
[Key]
public Int64 Id { get; protected set; }
public virtual ICollection<TVersion> Versions { get; protected set; }
protected VersionedBase() {
Versions = new List<TVersion>();
}
[NotMapped]
public Boolean HasValue {
get {
return Versions.Any();
}
}
[NotMapped]
public TBase Value {
get {
if (HasValue)
return Versions.OrderByDescending(x => x.CreationDateTime).First().Value;
throw new InvalidOperationException(this.GetType().Name + " has no value");
}
set {
Versions.Add(new TVersion { Value = value });
}
}
}
例子...
public class VersionedInt32 : VersionedBase<VersionedInt32Version, Int32> { }
public class VersionedInt32Version : VersionBase<Int32> {
public VersionedInt32Version() : base() { }
public VersionedInt32Version(Int32 value) : base(value) { }
public static implicit operator VersionedInt32Version(Int32 value) {
return new VersionedInt32Version { Value = value };
}
}
......還有......
public class VersionedString : VersionedBase<VersionedStringVersion, String> { }
public class VersionedStringVersion : VersionBase<String> {
public VersionedStringVersion() : base() { }
public VersionedStringVersion(String value) : base(value) { }
public static implicit operator VersionedStringVersion(String value) {
return new VersionedStringVersion { Value = value };
}
/// <summary>
/// The [Required] attribute tells Entity Framework that we want this column to be non-nullable
/// </summary>
[Required]
public override String Value { get; internal set; }
}
我的調用代碼是這樣...
static void Main(String[] args) {
using (var db = new VersionedFieldsContext()) {
Registration registration = new Registration();
registration.FirstName.Value = "Test";
registration.FirstName.Versions.Add("Derp");
db.Registration.Add(registration);
db.SaveChanges();
}
using (var db = new VersionedFieldsContext()) {
Registration registration = db.Registration.First();
// InvalidOperationException at next line: "VersionedString has no value"
String asdf = registration.FirstName.Value;
}
}
public class Registration {
[Key]
public Int64 Id { get; set; }
public DateTime CreationDateTime { get; set; }
public VersionedString FirstName { get; set; }
public Registration() {
CreationDateTime = DateTime.Now;
FirstName = new VersionedString();
}
}
public class VersionedFieldsContext : DbContext {
public DbSet<Registration> Registration { get; set; }
public VersionedFieldsContext() {
Database.SetInitializer<VersionedFieldsContext>(new DropCreateDatabaseIfModelChanges<VersionedFieldsContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
感謝您的任何見解!
與問題沒有直接關係,但我很好奇......這是非常聰明的代碼,但是您不擔心在加載/加載數據庫時會遇到的連接數/往返數的性能影響最簡單的事情?想象一下你想要加載一個帶有5個字符串(你的類型爲'VersionedString')的實體:sql必須通過兩個表連接5次才能得到字符串。而且你必須指定一個巨大的'Include'鏈或者將有多個延遲加載循環,並且在過濾掉內存中的最新內容之前始終加載所有版本的集合。 – Slauma 2012-04-19 17:42:39
我還沒有想太多,但因爲你問我一直在思考一些方法來提高性能。 – 2012-04-19 18:20:27
我的第一個想法是在'VersionedBase'中創建'Value'屬性,該屬性保存最近的值以及代表當前值的'CreationDateTime'的'UpdateDateTime'列。這樣你只需'.Include()'Versioned [Type]'屬性來有效地獲取最新值。問題在於'Versions'屬性不能正確表示數據的版本。 –
2012-04-19 18:26:48