我们可以使用枚举作为类型安全的实体 ID 吗? [英] Can we use enums as typesafe entity ids?

查看:15
本文介绍了我们可以使用枚举作为类型安全的实体 ID 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用 EF 6.1 代码优先设置中的一个相当大的模型,并且我们使用整数作为实体 ID.

We are working with a rather large model in a EF 6.1 code first setup and we are using ints for entity ids.

不幸的是,这并不像我们希望的那样类型安全,因为很容易混淆 id,例如比较不同类型实体的 id (myblog.Id == somePost.Id) 或类似的.甚至更糟:myBlog.Id++.

Unfortunately, this is not as typesafe as we would like, since one can easily mix up ids, for example comparing ids of entities of different types (myblog.Id == somePost.Id) or similar. Or even worse: myBlog.Id++.

因此,我提出了使用类型化 id 的想法,因此您不能混淆 id.所以我们的博客实体需要一个 BlogId 类型.现在,显而易见的选择是使用包装在结构中的 int,但不能使用结构作为键.而且你不能扩展 int... - 等等,你可以!使用枚举!

Therefore, I came up with the idea of using typed ids, so you cannot mix up ids. So we need a BlogId type for our blog entity. Now, the obvious choice would be to use an int wrapped in a struct, but you cannot use structs as keys. And you cannot extend int... - wait, you can! Using enum!

所以我想出了这个:

public enum BlogId : int { } 
public class Blog
{
    public Blog() { Posts = new List<Post>(); }
    public BlogId BlogId { get; set; }
    public string Name { get; set; }
    public virtual List<Post> Posts { get; set; }
}
internal class BlogConfiguration : EntityTypeConfiguration<Blog>
{
    internal BlogConfiguration()
    {
        HasKey(b => b.BlogId);
        Property(b=>b.BlogId)
           .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

所以现在我们有了类型安全的 id - 比较 BlogId 和 PostId 是编译时错误.而且我们不能将 3 添加到 BlogId.空枚举可能看起来有点奇怪,但这更多的是实现细节.而且我们必须在映射中明确设置 DatabaseGeneratedOption.Identity 选项,但这是一次性的工作.

So now we have typesafe ids - comparing a BlogId and a PostId is a compile time error. And we cannot add 3 to a BlogId. The empty enums may look a bit strange, but that is more of an implementation detail. And we have to set the DatabaseGeneratedOption.Identity option explicitly in our mapping, but that's a one-time effort.

在我们开始将所有代码转换为这种模式之前,是否有任何明显的问题?

Before we start converting all our code to this pattern, are there any obvious problems?

我可能需要澄清为什么我们必须首先使用 id 而不是完整的实体.有时我们需要匹配 EF Linq 查询中的实体 - 并且比较实体在那里不起作用.例如(以博客示例为基础,并假设一个更丰富的域模型):查找当前用户博客条目的评论.请记住,我们想在数据库中进行(我们有很多数据)并且我们假设没有直接的导航属性.并且 currentUser 没有附加.一种天真的方法是

I probably need to clarify why we must work with ids instead of full entities in the first place. Sometimes we need to match entities in EF Linq queries - and comparing entities doesn't work there. For example (building on the blog example and assuming a somewhat richer domain model): Find comments on the current users blog entries. Remember, that we want to do it in the database (we have lots of data) and we assume there are no direct navigational properties. And the currentUser is not attached. A naive approach would be

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

这不起作用,因为您无法在 EF Linq 中比较实体.所以我们尝试

This doesn't work, since you cannot compare entities in EF Linq. So we try

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

这编译并运行但错误 - 它应该是

This compiles and runs but is wrong - it should have been

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

Typesafe id 会发现它.我们有比这更复杂的查询.尝试查找当前用户以后没有评论过的特定其他用户对当前用户博客条目的评论".

Typesafe ids would have caught it. And we have much more complex queries than this. Try "find comments to current users blog entries made by specific other user which the current user has not himself commented on later".

问候,尼尔斯

推荐答案

这是一个有趣的方法,但问题是:它是否值得,后果是什么?

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.

想想——例如:

  • 这种转换对 LINQ 查询的性能有什么影响?
  • 如果您通过 WCF 的 Web API 公开您的操作,您将如何执行此操作?
  • 这是否适用于导航属性?
  • 此外,您可以用作主键的类型受到限制;我认为这不适用于 Guid.

一种额外保护的方法是让您的域层通过接受实体实例而不是 ID 来处理这些类型的事情.

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

这篇关于我们可以使用枚举作为类型安全的实体 ID 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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