LINQ, шаблон репозитория и отношения «многие ко многим» - PullRequest
0 голосов
/ 01 февраля 2010

У меня проблема с сохранением изменений в базе данных, я использую отображение LINQ2SQL. Я реализовал отношение M: M (User <= UserRole => Role) на основе учебника: http://www.codeproject.com/KB/linq/linqtutorial2.aspx#premain25

Все отлично работает, когда я использую один класс, который наследуется от DataContext и отвечает за все мои классы домена, например:

[База данных] открытый класс BookCatalog: DataContext { // Создать статический DataContext для удаления записей M: M Join приватный статический DataContext contextForRemovedRecords = null;

public BookCatalog() : base("Data Source=KO2\\SQLSERVER;Initial Catalog=Katalog;Integrated Security=True") { }

public Table<User> Users;
public Table<Role> Roles;
public Table<UserRole> UserRoles;

public static void RemoveRecord<T>(T recordToRemove) where T : class
{
    // Use the static contextForRemovedRecords
    if (contextForRemovedRecords == null)
        contextForRemovedRecords = new BookCatalog();

    Table<T> tableData = contextForRemovedRecords.GetTable<T>();
    var deleteRecord = tableData.SingleOrDefault(record => record == recordToRemove);
    if (deleteRecord != null)
    {
        tableData.DeleteOnSubmit(deleteRecord);
    }
}

// NEW method (not part of LINQ to SQL) to cancel changes
public void CancelChanges()
{
    if (contextForRemovedRecords != null)
    {
        contextForRemovedRecords = null;
    }
}

// Override DataContext's SubmitChanges() to handle any removed records
public new void SubmitChanges()
{
    if (contextForRemovedRecords != null)
    {
        contextForRemovedRecords.SubmitChanges();
    }
    base.SubmitChanges();
}

}

К сожалению, по некоторым причинам мне нужно хранить отдельные репозитории в моем проекте. Один из них пример:

открытый класс SqlRolesRepository: IRolesRepository {

private Table<Role> rolesTable;

public SqlRolesRepository(string connectionString)
{
    rolesTable = (new DataContext(connectionString)).GetTable<Role>();
}

public IQueryable<Role> Roles
{
    get { return rolesTable; }
}

public void SaveRole(Role role)
{
    bool ins = false;

    if (rolesTable.Any(m => m.RoleID == role.RoleID))
    {
        rolesTable.Context.Refresh(RefreshMode.KeepCurrentValues, role);
    }
    else
    {
        try { rolesTable.InsertOnSubmit(role); ins = true; }
        catch (Exception ex)
        {
            throw ex;

        }
    }

    try
    {
        rolesTable.Context.SubmitChanges();
    }
    catch (SqlException ex)
    {
        if (ins) rolesTable.DeleteOnSubmit(role);

        List<ErrorInfo> errors = new List<ErrorInfo>();

        if (ex.Message.Contains("UNQ_RoleName"))
            errors.Add(new ErrorInfo("RoleName", "Rola o takiej nazwie już istnieje", role));
        if (errors.Any()) throw new RulesException(errors);

        throw;
    }
}

public void SaveChanges()
{
    rolesTable.Context.Refresh(RefreshMode.OverwriteCurrentValues);
    rolesTable.Context.SubmitChanges();
}
public void DeleteRole(Role role)
{
    rolesTable.DeleteOnSubmit(role);
    rolesTable.Context.SubmitChanges();
}

public void DeleteRole(string roleName)
{
    rolesTable.DeleteOnSubmit(rolesTable.FirstOrDefault(m => m.Name == roleName));
    rolesTable.Context.SubmitChanges();
}

public Role GetRoleByName(string name)
{
    return rolesTable.Single(m => m.Name == name);
}

public string[] GetAllRoles(){
    return (from rola in rolesTable
           select rola.Name).ToArray();
}

}

Дело в том, что когда я пытаюсь сохранить изменения:

(...)
                foreach (string roleName in roleNames)
                {
                    Role rola = _RolesRepository.GetRoleByName(roleName);
                    if (rola != null)
                    {
                        foreach (string userName in usernames)
                        {
                            User usr = _UsersRepository.GetUserByName(userName);
                            if (usr != null)
                            {
                                if (!rola.Users.Contains(usr))
                                {
                                    rola.Users.Add(usr);               
                                }
                            }

                        }
                        _RolesRepository.SaveChanges();
                   } 
                }
(...)

Вместо сохранения экземпляра класса ассоциации (UserRole) LINQ пытается сохранить экземпляр класса User еще раз, появляется ошибка SqlExcepiton (уникальный ключ в столбце имени пользователя). В режиме отладки я заметил, что пользовательские экземпляры как-то удвоились ...

Мои классы LINQ отображаются как в учебнике (ссылка указана выше), пример проекта доступен здесь: http://www.codeproject.com/KB/linq/linqtutorial2/linqtutorial2_src.zip

Может быть, у кого-нибудь возникнет идея, как использовать его с шаблоном репозитория (несколько репозиториев). Я читаю статью MSDN (http://msdn.microsoft.com/en-us/library/bb425822.aspx), и кажется, что вызов SubmitChanges () из моего SqlRolesRepository должен правильно обновить базу данных, но это не ...

1 Ответ

6 голосов
/ 01 февраля 2010

Вы нарушаете шаблон единицы работы, заставляя каждый репозиторий инкапсулировать свой экземпляр экземпляра контекста / ссылку на таблицу. Для корректного обновления отношений необходимо использовать один и тот же экземпляр контекста данных для всех операций.

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

public SqlRoleRepository(DataContext context)
{
    rolesTable = context.GetTable<Role>();
}

Затем используйте эти конструкторы для создания экземпляров ваших репозиториев в том же контексте данных, когда им нужно участвовать в одной и той же единице работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...