域类型与数据类型差异的编译时安全性 - 使用实体框架

时间:2016-05-24 09:56:33

标签: c# entity-framework type-safety

想象一个简单的CRUD数据库应用程序,它使用bigint / Int64作为所有IDENTITY主键的标准类型。

在这种情况下,Foo和Bar参与多对一关系:

class Foo {
    Int64 FooId { get; set; }
    Int64 ParentBarId { get; set; }
}

class Bar {
    Int64 BarId { get; set; }
}

很明显,BarIdFooId属性的值虽然属于同一数据类型,但没有域名理由可以比较或相互分配,所以这没有意义:

Foo foo1 = ...
Foo foo2 = ...
Bar bar = ...
foo1.ParentBarId = bar.BarId; // ok...
foo2.ParentBarId = foo1.FooId; // programmer error!

这个问题类似于这个和其他语言中存在的“单位”问题,其中两个值被编译器认为是兼容的(例如,double值代表一个对象中的英寸,而厘米代表另一个对象),即使他们是不相容的。

我想知道是否存在针对此问题的惯用C#解决方案,即强制执行编译类型数据成员不兼容。

确实存在各种C#单元库(例如https://github.com/objorke/QuantityTypes/tree/master/Source/QuantityTypes/Quantities),它们通过使每个实际数量为struct并具有内部标准化表示(例如SI)来解决此问题。通过采用这种方法,我的域模型如下所示:

struct FooId { Int64 Value; }
struct BarId { Int64 Value; }

class Foo {
    FooId FooId { get; set; }
    BarId ParentBarId { get; set; }
}

class Bar {
    BarId BarId { get; set; }
}

问题是,这很快变得难以处理,因为您需要取消引用Int64 Value属性以对其执行任何操作(尽管您可以直接复制该值):

foo1.ParentBarId = bar.BarId; // okay...
foo2.ParentBarId = foo1.FooId; // this is now disallowed by the compiler, good!

databaseClient.GetBar( foo1.ParentBarId.Value ) // but this means extra typing if the `GetBar` method (perhaps generated by EF) expects `Int64` instead of `BarId`.

解决方法是添加implicit运算符,但由于.NET中的struct没有继承,因此必须在每个结构类型上手动定义它,这会使输入保存失败。允许隐式转换的另一个问题是,这意味着这成为可能(如果定义了to-Int64from-Int64隐式转换):FooId > Int64 > BarId - 这无法尝试引入域值安全性。< / p>

假设这些问题是可以克服的,是否可以将其与Entity Framework进行交互?这将要求EF同时支持使用struct复杂类型(不支持),将1个成员(“1-uple”?)复杂类型展平为持久层的单列值,最后支持这对于主键列(增加了复杂性)。

有没有人有幸使用这种或类似的方法来实现域值的编译时正确性?

0 个答案:

没有答案