我一直在开发一个数据库的框架,该框架将支持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