Линк к объектам: смешанный график объектов, ключей объектов, вложенных и новых объектов - PullRequest
0 голосов
/ 27 октября 2009

В моей модели данных есть довольно распространенное деление между моими объектами / таблицами / данными:

  • «Транзакционные» объекты, представляющие работу, выполняемую системой. Эти объекты создаются системой и важны только в определенных контекстах. Они регулярно создаются на лету. (Помимо: есть ли правильное имя для этого типа сущности?)
  • Сущности «словаря данных», которые представляют общие свойства транзакционных сущностей. Они определяются нерегулярно (в основном в начале проекта) и имеют гораздо более статичный жизненный цикл. Они обычно создаются мной.

Так, например, у меня может быть сущность User (транзакционный) и сущность UserType (словарь данных).

Я хочу (жестко) кодировать ссылки на экземпляры сущностей словаря данных в мой код. Это дает мне возможность кодировать бизнес-логику на простом для понимания языке. (Так, например, у меня может быть UserType «Простой» и UserType «Admin», а затем правило «разрешить доступ, только если UserType пользователя равен Admin»).

Я использую LINQ-to-Entities в качестве технологии доступа к данным / ORM. Для реализации ссылок на словарь данных я храню EntityKeys. Я понимаю, что они отделены от контекста объекта и поэтому подходят для этой цели. (Поскольку они не содержат состояния сущности, мне также не нужно беспокоиться о том, что это состояние устареет.)

Однако это вызывает у меня проблемы, когда я пытаюсь добавить новую транзакционную сущность с DD-EntityKey-ссылкой. Продолжая мой пример, я делаю это:

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

... и это дает мне следующую ошибку:

System.InvalidOperationException: объект не может быть добавлен в ObjectStateManager, потому что у него уже есть EntityKey. Используйте ObjectContext.Attach, чтобы прикрепить объект с существующим ключом.

Если я пытаюсь вызвать userEntities.Attach (пользователь) вместо AddToUser, я получаю это:

System.InvalidOperationException: объект с нулевым значением EntityKey не может быть присоединен к контексту объекта.

Обе эти ошибки имеют смысл, учитывая смешение новых и уже существующих сущностей, которые я делаю. В чем я не уверен, так это в том, как обойти эту проблему. Есть ли какой-то способ, которым я могу иметь отдельные ссылки на DD-сущности и назначать их новым присоединенным объектам, не требуя от меня загрузки всего состояния DD-сущности?

1 Ответ

1 голос
/ 27 октября 2009

Я попытаюсь объяснить, почему вы получаете эти исключения:

System.InvalidOperationException: объект не может быть добавлен в ObjectStateManager, поскольку у него уже есть EntityKey. Используйте ObjectContext.Attach, чтобы прикрепить объект, который имеет существующий ключ.

Созданы новые объекты User и UserType. EntityKey для UserType был установлен, но когда вы передаете его userEntities.Add () EF пытается установить для них статус ADDED. Поскольку UserType имеет EntityKey, EF понимает, что что-то не так, и выдает исключение.

System.InvalidOperationException: объект с нулевым значением EntityKey не может быть присоединен к контексту объекта.

В этом исключении все в порядке с UserType, но исключение выдается, потому что пользовательский объект - у него нет EntityKey и, следовательно, не может быть присоединен.

Вот как я бы решил эту проблему (если, как вы говорите, жесткое кодирование ссылок на словарь данных в порядке):

В сущности UserType я бы создал статические ссылки на идентификаторы UserType:

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

В сущности User было бы свойство extender для более легкого доступа к внешнему ключу 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()
}
...