在我的数据模型中,我的对象/表/数据之间有一个相当常见的划分:

  • 代表系统正在完成的工作的“事务”实体。这些实体是由系统创建的,仅在特定上下文中才重要。它们通常是即时创建的。(在旁边:这种类型的实体有合适的名称吗?)
  • 代表事务实体的公共属性的“数据字典”实体。它们的定义不规则(主要是在项目开始时),并且具有更加静态的生命周期。它们通常是由我创建的。

例如,我可能有一个 User (事务)实体和一个 UserType (数据字典)实体。

我想将对数据字典实体实例的引用(硬)编码到我的代码中。这使我能够使用易于理解的语言编写业务逻辑。(例如,我可能有一个 UserType 为“Plain”和一个 UserType 为“Admin”,然后有一条规则“仅当用户的 UserType 等于 Admin 时才允许访问”)。

我使用 LINQ-to-Entities 作为我的数据访问技术/ORM。为了实现数据字典引用,我存储了 EntityKey。我的理解是它们与对象上下文分离,因此适合此目的。(因为它们不包含实体状态,所以我也不必担心该状态会过时。)

然而,当我尝试使用 DD-EntityKey-reference 添加新的事务实体时,这给我带来了问题。继续我的例子,我正在这样做:

UserEntities userEntities = new UserEntitites()
User user = new User()
user.UserType = new UserType()
user.UserType.EntityKey = adminEntityKey
userEntities.AddToUser(user)

...这给了我以下错误:

系统.InvalidOperationException:该对象无法添加到 ObjectStateManager,因为它已经具有 EntityKey。使用 ObjectContext.Attach 附加具有现有键的对象。

如果我尝试调用 userEntities.Attach(user) 而不是 AddToUser,我会得到以下结果:

系统.InvalidOperationException:EntityKey 值为空的对象无法附加到对象上下文。

考虑到我正在做的新实体和现有实体的混合,这两个错误都是有道理的。我不确定如何解决这个问题。有什么方法可以分离对 DD 实体的引用并将它们分配给新的附加对象,而不需要我加载整个 DD 实体状态?

有帮助吗?

解决方案

我将尝试解释为什么您会遇到这些异常:

系统.InvalidOperationException:该对象无法添加到 ObjectStateManager,因为它已经具有 EntityKey。使用 ObjectContext.Attach 附加具有现有键的对象。

创建新的 User 和 UserType 实体。UserType 上的 EntityKey 已设置,但当您将其传递给 userEntities.Add() 时,EF 会尝试将它们设置为 ADDED 状态。由于 UserType 有 EntityKey EF 意识到出现了问题并抛出异常。

系统.InvalidOperationException:EntityKey 值为空的对象无法附加到对象上下文。

在此异常中,UserType 一切正常,但抛出异常是因为 User 实体 - 它没有 EntityKey,因此无法附加。

这就是我解决这个问题的方法(如果,正如你所说,数据字典引用的硬编码是可以的):

在 UserType 实体上,我将创建对 UserType id 的静态引用:

public partial class UserType
    {
        public const int AdminUserTypeID = 1;
        public const int PlainUserTypeID = 2;
    }  

在 User 实体上,将有扩展器属性,以便更轻松地访问 UserType 外键:

public partial class User
{
    public int? UserTypeID
    {
        set
        {
           UserTypeReference.EntityKey = new EntityKey("UserEntities.UserType", "UserTypeID", value);
        }
        get
        {
            if (UserTypeReference.EntityKey == null)
                return null;

            if (UserTypeReference.EntityKey.EntityKeyValues.Count() > 0)
                return (int)UserTypeReference.EntityKey.EntityKeyValues[0].Value;
            else
                return null;
        }
    }
}

最后,创建新用户的用例如下所示:

using(UserEntities userEntities = new UserEntitites())
{
    User user = new User();
    user.UserTypeID = UserType.AdminUserTypeID;
    userEntities.AddToUser(user);
    userEntities.SaveChanges()
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top