LINQ,存储库模式和多对多关系

时间:2010-01-31 22:27:36

标签: asp.net-mvc linq many-to-many repository-pattern orm

我在保存对数据库的更改方面存在问题,我正在使用LINQ2SQL映射。我根据教程http://www.codeproject.com/KB/linq/linqtutorial2.aspx#premain25

实现了M:M关系(User< = UserRole => Role)

当我使用一个继承自DataContext并负责我所有域类的类时,一切正常:

[数据库] 公共类BookCatalog:DataContext {     //创建静态DataContext以删除M:M Join记录     private static 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();
}

}

不幸的是,由于某些原因,我需要在我的项目中保留单独的存储库。其中一个例子:

public class 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),似乎从我的SqlRolesRepository调用SubmitChanges()应该正确更新数据库,但它不是......

1 个答案:

答案 0 :(得分:6)

通过让每个存储库封装自己的数据上下文实例/表引用,您打破了工作单元模式。为了正确更新关系,您需要为所有操作使用相同的数据上下文实例。

执行此操作的最简单方法是使存储库类在创建时接受现有数据上下文实例,以便它们在共享实例上执行工作,而不是在单独的实例上执行。您可以通过在以下行中向每个存储库添加新构造函数来执行此操作:

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

然后使用这些构造函数在需要参与同一工作单元时针对相同的数据上下文实例化您的存储库。