使用实体框架模型键入安全密钥
本文关键字:安全 密钥 模型 实体 框架 | 更新日期: 2023-09-27 18:19:52
这是我今天的完美想法:实体框架中的强类型id。
动机:
- 比较ModelTypeA.ID和ModelTypeB.ID(至少几乎)总是一个错误。为什么compiletime不处理它
- 如果您使用的是每个请求的示例DbContext,那么它很容易实现,可以直接从id获取模型。"id.Value.ProductNumber"
- 代码将更加自我声明
- 它们只是自然键入的,为什么不呢
好的,这是我的实现。我希望它能很好地说明我的意思。
//Optional interface may be handy on some scenarios
public interface Identifiable<T> where T : class, Identifiable<T>
{
DbId<T> ID { get; set; }
}
public class TestModel1 : Identifiable<TestModel1>
{
[Key]
public DbId<TestModel1> ID { get; set; }
public string Data1 { get; set; }
}
public class TestModel2 : Identifiable<TestModel2>
{
[Key]
public DbId<TestModel2> ID { get; set; }
public string Data2 { get; set; }
public DbId<TestModel1> TestModel1ID { get; set; }
public virtual TestModel1 TestModel1 { get; set; }
}
[Serializable]
public class DbId<T> where T : class
{
public int ID { get; set; }
public static implicit operator DbId<T>(int id)
{
var c = new DbId<T>() { ID = id };
return c;
}
public static implicit operator int (DbId<T> id)
{
return id.ID;
}
}
在创建迁移时,其司法机构抱怨没有钥匙。当尝试在fluent api上设置密钥时,会出现更严重的错误:属性"ID"不能用作实体"MyNs.Models.TestModel1"的密钥属性,因为该属性类型不是有效的密钥类型。只有标量类型、字符串和byte[]是受支持的键类型。
Ok理解的键不能是任何类型,但我的类型的数据只是一个int开关,甚至有隐式转换。在这种情况下继承int是非常诱人的,但正如我们所知,这是不可能的。
主要问题:如何完成这个并告诉EF将我的DbId转换为int并返回不是火箭科学。
第二个问题:这个主意好吗?为什么?如果目前无法实现,您是否建议功能请求?
我相信我理解您的目标:您的目标是封装每个模型的主键,使两个不同模型的主键不能直接比较。因此,例如,您可能希望在编译时避免比较Customer.ID == Order.ID
。
然而,在您的代码示例中,int <-> DbId<T>
的implicit operator
不符合您的目标,因为此代码编译:
var model1 = new TestModel1() {ID = 1};
var model2 = new TestModel2() {ID = 2};
Console.WriteLine(model1.ID == model2.ID);
所以,如果我遵循你的推理,即使EF6+允许类(而不是string
)上的[Key]
,它也不会起作用
回到基础,如果您认为名称ID
太模糊,为什么不遵循实体框架主键约定,即类名后跟"ID"?
示例:
public class Customer
{
// [Key] is implicit by convention
public int CustomerID { get; set; }
public string Name { get; set; }
}
public class Order
{
// [Key] is implicit by convention
public int OrderID { get; set; }
public DateTime SubmittedDate { get; set; }
// [ForeignKey("Customer")] is implicit by convention
public int CustomerID{ get; set; }
public virtual Customer Customer { get; set; }
}
这种命名约定(以及普通的ID
)是我在实体框架代码中看到最多的约定。因此,它的主要好处是允许其他人介入并无缝地适应和维护您的代码(这是一个我们修补匠有时都会忽视的好处!)
看看你的动机。。。
比较ModelTypeA.ID和ModelTypeB.ID(至少几乎)总是一个错误。
你在解决一个实际上不是问题的问题吗?程序员多久真正搞砸一次Order.CustomerID == Customer.CustomerID
?
代码将更加自我声明。
要辩论吗?如果我在某人的代码中发现DbId<Customer> id = Customer.ID
,它真的比int id = Customer.CustomerID
更具声明性吗?
话虽如此,我为你的努力鼓掌!解决问题是我们程序员喜欢做的事。祝你好运!