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

Kot*_*otu 0 linq asp.net-mvc orm many-to-many repository-pattern

我在保存对数据库的更改方面存在问题,我正在使用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();
}
Run Code Online (Sandbox Code Playgroud)

}

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

公共类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();
}
Run Code Online (Sandbox Code Playgroud)

}

关键是当我想要保存更改时:

(...)
                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();
                   } 
                }
(...)
Run Code Online (Sandbox Code Playgroud)

LINQ尝试再次保存类User的实例,而不是保存关联类的实例(UserRole),出现SqlExcepiton错误(用户名列上的唯一键).在调试模式中,我注意到用户实例似乎以某种方式加倍...

我的LINQ类映射如教程(上面列出的链接),示例项目可在此处获得:http://www.codeproject.com/KB/linq/linqtutorial2/linqtutorial2_src.zip

也许有人会知道如何将它与存储库模式(多个存储库)一起使用.我正在阅读MSDN文章(http://msdn.microsoft.com/en-us/library/bb425822.aspx),似乎从我的SqlRolesRepository调用SubmitChanges()应该正确更新数据库,但它不是.. .

Sam*_*Sam 6

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

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

public SqlRoleRepository(DataContext context)
{
    rolesTable = context.GetTable<Role>();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 依赖注入框架也可以使该部分自动化. (2认同)