Обновить объект с отношением «один ко многим»

#c# #.net #entity-framework #linq-to-entities

#c# #.net #entity-framework #linq-to-entities

Вопрос:

Я столкнулся с проблемой, когда существует отношение «один ко многим», и я пытаюсь обновить данные в одной из таблиц и таблице ссылок.

  • У меня есть две таблицы (User, роли) и одна таблица ссылок (UserRoles).
  • У пользователя много ролей.
  • Роли предопределены, и есть только 3 строки, как показано ниже.

Я хочу обновить пользователя с помощью ролей. Я не могу выполнить следующий код. Пожалуйста, поделитесь своими вводными данными.

 Original
User : John
Roles : Admin, User

Update to
User : John
Roles : User
 

Это структура таблицы

 User
UserID : Pk
Name

Roles //Data is not added in this table, Data already exists in this table
RoleID : Pk
Name

RoleID   Name
1        Admin
2        User
3        None

UserRoles
UserID  : PK
RoleID : Pk
 

Соответствующие объекты

 User
UserId
Name
EntityCollection<Role> Roles

Role
RoleId
Name
EntityCollection<User> Users
 

Я попытался со следующим кодом

 public void update(int userId, string newusername, list<int> roleList)
{
    using (DBEntites context = new DBEntites())
    {
        User objUserInDb = new User();
        objUserInDb.UserID = userId;
        Context.Users.Attach(objUserInDb);
        objUserInDb.Name = newusername;
        objUserInDb.Roles.Clear(); 

        // TRIED TO USE The remove method objUserInDb.Roles.Remove(entity), 
        // is returning false

        foreach (long pkIDToAdd in roleList)
        {
            Role objRoleInDb = new Role();
            objRoleInDb.RoleId = pkIDToAdd;

            // GIVES EXCEPTION 
            //An object with the same key already exists in the ObjectStateManager. 
            //The ObjectStateManager cannot track multiple objects with the same    
            //
            context.Roles.Attach(objRoleInDb);
            objUserInDb.Roles.Add(objRoleInDb);
        }
    }
}
 

Ответ №1:

Исключение связано с тем, что некоторые роли уже загружены в контекст. Вы можете сделать так,

   foreach (long pkIDToAdd in roleList)
        {
            var role=  context.RiskTypes.FirstOrDefault(r=>r.id==pkIDToAdd );
            objUserInDb.Roles.Add(role);
        }
 

Комментарии:

1. Спасибо, Джаянта. На самом деле я пытаюсь избежать вызова базы данных, используя метод FirstOrDefault и, следовательно, используя метод Attach . Я попытался использовать метод TryGetObjectByKey с вновь созданным типом риска, используя Role objRole = new Role(); objRole . RoleId = 1; но я вижу, что ключ объекта для objRole равен нулю, а EntityState отсоединен. когда я пытаюсь использовать метод Attach, он выдает исключение объекта с ключом, который уже существует. Я хочу избежать использования жестко запрограммированной строки для создания нового ключа объекта и проверки его наличия. Надеюсь, я понял

2. Да, я понял. Вы можете проверить context.Entry(role).State , и если это Detached так, вы можете прикрепить его снова.