Can we use enums as typesafe entity ids?

六眼飞鱼酱① 提交于 2019-12-03 05:15:19

It's an interesting approach, but the question is: is it worth it and what are the consequences?

You could still do something like

 if ((int)blog.BlogId == (int)comment.CommentId) { }

Personally I would invest more time in educating people, writing good tests, and code reviews, instead of trying to add some form of extra complexity that influences the way you use and query your entities.

Think - for example:

  • What effect does this casting have on performance in LINQ queries?
  • How would you enforce this if you expose your operations through Web API of WCF?
  • Does this work with navigation properties??
  • Also, you are limited in the types you could use as primary key; I don't believe this works with Guids.

A way of additional protection is to have your domain layer handle these kinds of things by accepting entity instances instead of ID's.

I was not even familiar with this usage, but did a little digging and even the EF team says it's do-able. From their initial blog post on enum support in EF, this is listed:

Enums as keys In addition, properties of enum types can participate in the definition of primary keys, unique constraints and foreign keys, as well as take part in concurrency control checks, and have declared default values.

source: http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx

I have not ever done this myself, but that quote gives me confidence. So it's possible, but as L-Three suggests: really consider if it's what you want (pros & cons .. but sounds like you have already done that) and test test test!

I really don't try to bash you, but how can one mix up Ids of Type X with Ids of Type Z? I never met anybody who did stuff like myBlog.Id++ either (or at least not without getting fired).

Anyhow, here is a solution which seams to be less work and better maintainable (especiall for the db-admins):

-In the TypeConfiguration, create an Id through the fluent API (you'll see why later)

-Create an abstract base-class for all your entities with:

*property: proteced int Id

*method: public int getIdValue()

*method: public bool isSameRecord(T otherEntity) where T: EntityBaseClass

I guess the first method are self-explanatory, the isSameRecord will take the other instance of your base-class, does a type-check first and if it passes it, it will do a id-checkup, too.


This is an untested approach, there's a good chance you can't create protected identifiers.

If it doesn't work, you could create public int _id and just tell your team to not use it directly.

Not sure that this will work in EF but one thing you could do is to have your entities implement IEquatable<T>:

For example your Blog class:

public class Blog : IEquatable<Blog>
{
    // other stuff
    public bool Equals(Blog other)
    {
        return this.Id.Equals(other.Id);
    }
}

Alternatively you could use a more flexible ORM such as NHibernate. If this is of interest, let me know and I'll expand my answer.

I know I'm a bit late to this party, but I've used this technique and it definitely works!

Type safety works exactly as you suggest. Compiler will catch mistakes such as

from c in ctx.Comments where c.ParentPost.Blog.Id == currentUser.Id

And it prevents silly maths.

currentUser.Id++;
currentUser.Id * 3;

Navigation properties still work fine too, as long as both ends of the navigation are the same enum type.

And the SQL queries work just as they do with an int.

It's certainly an interesting idea!

Can you use typesafe entity IDs? - Yes!

Should you? I'm not sure. It doesn't seem that this is how EF was designed and feels a little hacky.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!