需要使用LinqToSql和存储库模式的复杂插入方案的建议

时间:2010-02-21 19:23:25

标签: sql-server asp.net-mvc linq-to-sql repository repository-pattern

我的数据库中有一个User表和一个ClubMember表。用户和俱乐部成员之间存在一对一的映射,因此每次插入ClubMember时,我都需要先插入User。这是通过ClubMemberUserId REFERENCES User (Id))上的外键实现的。

在我的ASP.NET MVC应用程序中,我正在使用LinqToSql和Repository Pattern来处理我的持久性逻辑。我实现此方法的方式是,我的UserClubMember事务由不同的存储库类处理,每个存储库类都使用自己的DataContext实例。

如果没有数据库错误,这样可以正常工作,但我担心如果任何User插入失败,我将留下孤立的ClubMember条记录。

要解决此问题,我正在考虑切换到单个DataContext,我可以使用这两个插入加载,然后只调用DataContext.SubmitChanges()一次。但问题是,Id的{​​{1}}在User插入数据库之前未分配,我无法插入User直到我知道ClubMember

问题:

  1. 是否可以将UserId插入数据库,获取User,然后将Id全部作为单个事务插入(可以回滚,如果交易的任何部分出了什么问题)?如果是,怎么做?

  2. 如果没有,我唯一可以手动删除任何创建的孤立ClubMember记录吗?或者有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

您可以使用System.Transactions.TransactionScope在原子事务中执行此操作,但如果您使用的是不同的DataContext实例,则会导致分布式事务,这可能不是您真正想要的。

听起来,你并没有真正正确地实现存储库模式。存储库不应该创建自己的DataContext(或连接对象,或其他任何东西) - 这些依赖项应该通过构造函数或公共属性传递。如果您这样做,那么分享DataContext

就没有问题
public class UserRepository
{
    private MyDataContext context;

    public UserRepository(MyDataContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        this.context = context;
    }

    public void Save(User user) { ... }
}

ClubMemberRepository(或任何你称之为的)使用相同的模式,这变得微不足道:

using (MyDataContext context = new MyDataContext())
{
    UserRepository userRep = new UserRepository(context);
    userRep.Save(user);
    ClubMemberRepository memberRep = new ClubMemberRepository(context);
    memberRep.Save(member);
    context.SubmitChanges();
}

当然,即使这个也有点不确定。如果数据库中有外键,那么您甚至不需要两个存储库,因为Linq to SQL管理这种关系。要创建的代码应该如下所示:

using (MyDataContext context = new MyDataContext())
{
    User user = new User();
    user.Name = "Bob";
    user.ClubMember = new ClubMember();
    user.ClubMember.Club = "Studio 54";

    UserRepository userRep = new UserRepository(context);
    userRep.Save(user);
    context.SubmitChanges();
}

不要使用多个存储库 - 让Linq to SQL为您处理这种关系,这就是ORM的用途。

答案 1 :(得分:0)

是的,您可以在一次交易中完成。使用TransactionScope对象开始并提交事务(如果当然有错误则回滚)