我的数据库中有一个User
表和一个ClubMember
表。用户和俱乐部成员之间存在一对一的映射,因此每次插入ClubMember
时,我都需要先插入User
。这是通过ClubMember
(UserId REFERENCES User (Id)
)上的外键实现的。
在我的ASP.NET MVC应用程序中,我正在使用LinqToSql和Repository Pattern来处理我的持久性逻辑。我实现此方法的方式是,我的User
和ClubMember
事务由不同的存储库类处理,每个存储库类都使用自己的DataContext
实例。
如果没有数据库错误,这样可以正常工作,但我担心如果任何User
插入失败,我将留下孤立的ClubMember
条记录。
要解决此问题,我正在考虑切换到单个DataContext
,我可以使用这两个插入加载,然后只调用DataContext.SubmitChanges()
一次。但问题是,Id
的{{1}}在User
插入数据库之前未分配,我无法插入User
直到我知道ClubMember
。
问题:
是否可以将UserId
插入数据库,获取User
,然后将Id
全部作为单个事务插入(可以回滚,如果交易的任何部分出了什么问题)?如果是,怎么做?
如果没有,我唯一可以手动删除任何创建的孤立ClubMember
记录吗?或者有更好的方法吗?
答案 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对象开始并提交事务(如果当然有错误则回滚)