2

我目前正在尝试将实体框架应用程序与大约十年左右的旧数据库集成。这个数据库存在的许多问题之一(除了没有关系或约束之外)几乎每一列都被设置为空,即使在几乎所有情况下,这都是没有意义的。在实体框架中将可空值透明地转换为不可空值

不变的是,我会遇到一个异常沿着这些线路:

上“MyRecord”的“SortOrder的”属性不能被设置为“空”值。您必须将此属性设置为“Int32”类型的非空值。

我已经看到很多提及上述例外的问题,但这些都似乎是真正的错误,其中开发人员没有编写正确表示数据库中数据的类。我想故意编写一个不能正确表示数据库中数据的类。我完全意识到这是违反实体框架的规则,而这很可能是为什么我这么做很困难。

现在不可能改变模式,因为它会破坏现有的应用程序。修复数据也是不可能的,因为新数据将被旧应用程序插入。我想用实体框架来映射数据库,在接下来的几年中慢慢地移动所有的应用程序,依靠它来进行数据访问,然后才能进入数据库重新设计阶段。我已经使用来解决这个问题

一种方法是透明的代理变量:

internal int? SortOrderInternal { get; set; } 

public int SortOrder 
{ 
    get { return this.SortOrderInternal ?? 0; } 
    set { this.SortOrderInternal = value; } 
} 

我可以现场再映射CodeFirst:

entity.Ignore(model => model.SortOrder); 
entity.Property(model => model.SortOrderInternal).HasColumnName("SortOrder"); 

在此方法中使用internal关键字确实让我能够很好地封装这种缺陷,所以我至少可以防止它泄漏到我的数据访问程序集之外。

但不幸的是我现在无法使用在查询代理字段作为NotSupportedException会抛出:

指定的类型成员“SortOrder的”不支持LINQ到实体。仅支持初始化程序,实体成员和实体导航属性。

也许它可能会透明地重写表达式,一旦它被DbSet接收到了?我很想知道这是否会起作用。表达树说我不够熟练。到目前为止,我在DbSet中找不到一个可以重写的方法来操作表达式,但我并没有在上面创建一个实现IDbSet并传递给DbSet的新类,尽管这很可怕。

在调查堆栈跟踪时,我发现了一个名为Shaper的内部实体框架概念的引用,这个概念似乎是将数据输入并输入到它的东西的一个小技巧。任何事情,但用dotPeek调查System.Data.Entity.dll表明,这肯定会帮助我......假设Shaper<T>不是内部和密封。我几乎肯定会在这里咆哮错误的树,但我有兴趣知道是否有人以前遇到过这种情况。

+0

是否有你不想使用可空属性的原因?感觉有点像你试图“对抗”数据库模式,而不是接受它的限制并相应地编写你的代码。 – 2012-04-26 14:55:08

+0

出于兴趣,为什么不在CSDL /模型属性中使实体属性为null = false?虽然底层的SSDL可以为空,但它会正确映射非空值,但是如果数据库中有空值,您需要处理ConstraintException(yyy上的XXX属性不能设置为空属性) – StuartLC 2012-04-26 15:03:00

+0

@ AndrewStephens我不想这样做,因为它不是应该如何设计数据库。例如,还有一种情况是两个不同的实体存储在我使用实体框架解决的同一个表中。我想重新解释应用程序层中的数据,然后在将来修复数据库。如果我在实体框架图层的类中允许可为空的值(并且它实际上几乎是每个字段,即使是外键),我都没有真正解决这个问题。 – 2012-04-26 15:12:46

回答