1

在使用自我跟踪实体和实体框架 4 时,我正在尝试建立使用辅助键的良好做法,但似乎有很多陷阱。

假设我有一个警报实体,它可以具有用户的 ConfirmingUser 导航属性。用户有一个 Id 作为主键,一个“登录”作为辅助键。在我的系统中的某个时刻,我将一个新的用户实体分配给警报的 ConfirmingUser。那时我只知道用户的登录名(辅助密钥),可以说它是一个 n 层架构,此时查找 Id 是不切实际的。警报随后被传输到将尝试存储警报的持久层。现在是棘手的部分。我需要确定 ConfirmingUser 是否已存在于数据库中并采取适当的措施。

这就是我现在的做法:

        using (var context = new PantoTestEntities())
        {
            if (alarm.ConfirmingUser != null && alarm.ConfirmingUser.ChangeTracker.State == ObjectState.Added)
            {
                var userIdQuery = from user in context.Users
                                  where user.Login == alarm.ConfirmingUser.Login
                                  select user.Id;
                if (userIdQuery.Any())
                {
                    // Disable cache or ApplyChanges will throw an exception, because the user already exists.
                    context.Alarms.MergeOption = MergeOption.NoTracking;

                    alarm.ConfirmingUser.Id = userIdQuery.First();

                    alarm.ConfirmingUser.MarkAsModified();
                }
            }

            context.Alarms.ApplyChanges(alarm);

            context.SaveChanges();

            // Accept changes in the full entity graph
            alarm.AcceptAllChanges();
        }

这种模式对我来说看起来相当丑陋和低效。有没有更好的方法来处理带有“外部”键的实体?

上述代码的一个有趣缺陷是无法用具有相同登录名的新用户替换 ConfirmingUser。即,当客户端应用程序想要将 ConfirmingUser 分配给警报时,它必须检查 ConfirmingUser 是否已经分配给具有相同登录属性的用户。原因是自跟踪实体的 ApplyChanges 将尝试将原始用户和新用户都复制到 EF 上下文中,但 EF 不允许原始值和新值是同一个实体(为什么它无法处理这对我来说没有明确的意义)。

4

0 回答 0