使用Entity Framework模型键入安全密钥 [英] Type safe keys with Entity Framework model

查看:112
本文介绍了使用Entity Framework模型键入安全密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我完美的一天:Entity Framework中的强类型ids。



动机:


  1. 比较ModelTypeA.ID和ModelTypeB.ID(至少几乎)总是一个错误。为什么没有compiletime处理它?<​​/ li>
  2. 如果您正在使用每个请求的示例DbContext它容易实现从id直接获取模型。 id.Value.ProductNumber

  3. 代码将更自我声明。

  4. 他们只是自然键入,为什么不这样?

这里是我的实现。我希望它的漂亮的自我声明我的意思。

  //可选接口可能在某些情况下很方便
public interface识别< T>其中T:class,Identifiable< T>
{
DbId< T> ID {get;组; }
}

public class TestModel1:Identifiable< TestModel1>
{
[Key]
public DbId< TestModel1> ID {get;组; }
public string Data1 {get;组; }
}

public class TestModel2:可识别< TestModel2>
{
[Key]
public DbId< TestModel2> ID {get;组; }
public string Data2 {get;组; }
public DbId< TestModel1> TestModel1ID {get;组; }
public virtual TestModel1 TestModel1 {get;组;
}

[Serializable]
public class DbId< T>其中T:class
{
public int ID {get;组; }

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;
}
}

创建迁移时,jus抱怨没有关键字。当尝试设置流畅api的密钥时,它会给出更宝贵的错误:属性ID不能用作实体MyNs.Models.TestModel1上的关键属性,因为属性类型不是有效的密钥类型。只有标量类型,字符串和字节[]是支持的键类型。



Ok了解键不能是任何类型,但是我的类型的数据只是一个int witch甚至有隐式转换。在这种情况下继承int是非常诱人的,但是我们知道它是不可能的。



主要问题:如何完成此操作并告诉EF将DbId转换为int和back并不是火箭科学。


$ b $第二个问题:这是个好主意吗?为什么?您是否建议功能请求,如果目前无法使用此功能?

解决方案

我相信我了解您的目标:您的目标是封装每个模型的主键,使得两个不同模型的主键不能直接比较。所以,例如,您将希望在编译时避免比较 Customer.ID == Order.ID



然而,在你的代码示例中,隐式运算符 int< - > DbId< T> 符合您的目标,因为此代码编译

  var model1 = new TestModel1(){ID = 1}; 
var model2 = new TestModel2(){ID = 2};
Console.WriteLine(model1.ID == model2.ID);

所以,如果我遵循你的推理,即使EF6 +允许 [Key] 在课程上(除了 string 。)



基础知识,如果你相信名字 ID 太含糊了,为什么不遵循实体框架主键公约 类名称后跟ID



示例:

  public class Customer 
{
// [Key]由约定隐含
public int CustomerID {get;组; }
public string Name {get;组;
}

public class Order
{
// [Key]由约定隐含
public int OrderID {get;组; }
public DateTime SubmittedDate {get;组; }
// [ForeignKey(Customer)]由约定隐含
public int CustomerID {get;组; }
public virtual Customer Customer {get;组; }
}

这个命名约定(以及简单的 ID )是我在Entity Framework代码中看到最多的约定。所以,它有主要的好处,允许其他人进入,并无缝适应和维护你的代码(一个好处,我们的修补者都有责任忽略有时!)



看看你的动机...


比较ModelTypeA.ID和ModelTypeB.ID(至少几乎)总是一个错误。 >

您是否解决了实际上并不是问题的问题?程序员真的搞错了多少钱code Order.CustomerID == Customer.CustomerID ?


代码将更自我声明。


辩论?如果我发现 DbId< Customer> id = Customer.ID 在某人的代码中,它是否比 int id = Customer.CustomerID 更有声明?


那么说,我赞扬你的努力!解决问题是我们程序员喜欢做的事情。祝你好运!


This is my perfect idea of day: Strong typed ids in Entity Framework.

Motivation:

  1. Comparing ModelTypeA.ID and ModelTypeB.ID is (at least almost) always an error. Why not compiletime handle it?
  2. If you are using example per request DbContext its easy to implement get directly model from id. "id.Value.ProductNumber"
  3. Code will be more self declarative.
  4. They are just naturally typed so why not?

Ok here is my implementation. I hope its pretty self declarative what I mean.

//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;
    }       
}

When creating migration its jus complain that there is no key. When trying to set key on fluent api it give more precious error: The property 'ID' cannot be used as a key property on the entity 'MyNs.Models.TestModel1' because the property type is not a valid key type. Only scalar types, string and byte[] are supported key types.

Ok understood key cannot be any type but data of my type is just one int witch even has implicit conversions. Inheriting int in this situation is very tempting but like we know its impossible.

Primary question: How to finish this and tell to EF that converting my DbId to int and back is not rocket science.

Secondary question: Is this good idea? Why? Do you suggest feature request if this is not currently possible?

解决方案

I believe I understand your goal: your aim is to encapsulate the primary key of each model such that primary keys of two different models cannot be compared directly. So, for example, you would want to avoid the comparison Customer.ID == Order.ID at compile time.

However, in your code example, the implicit operator for int <-> DbId<T> works against your goal because this code compiles:

var model1 = new TestModel1() {ID = 1};
var model2 = new TestModel2() {ID = 2};
Console.WriteLine(model1.ID == model2.ID);

So, if I follow your reasoning, it would not work even if EF6+ allowed [Key] on a class (other than string.)

Getting back to basics, if you believe the name ID is too ambiguous, why not follow the Entity Framework Primary Key Convention of class name followed by "ID"?

Example:

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; }
}

This naming convention (along with plain ID) is the convention I see the most in Entity Framework code. So, it has the major benefit of allowing other people to step in and seamlessly acclimate and maintain your code (a benefit that we tinkerers are all guilty of overlooking sometimes!)

Looking at your motivations...

Comparing ModelTypeA.ID and ModelTypeB.ID is (at least almost) always an error.

Are you solving a problem that isn't actually a problem? How often do programmers really screw up Order.CustomerID == Customer.CustomerID?

Code will be more self declarative.

Up to debate? If I spot DbId<Customer> id = Customer.ID in someone's code, is it really more declarative than int id = Customer.CustomerID?

That said, I applaud your effort! Solving problems is what we programmers love to do. Good luck!

这篇关于使用Entity Framework模型键入安全密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆