7

几天来,我一直在努力解决这个问题,并且有很多关于工作单元和 TransactionScope 的教程,但我找不到任何关于这两者的内容。非常感谢任何帮助!

我正在使用具有工作单元模式的实体框架和每种类型的存储库。根据下面的简单代码,我有一个 Member 和 MembershipDefinition 实体。我想创建一个将两者联系起来的 Membership 实体,但是当我创建 Membership 对象时,我想根据一些业务逻辑查询 DB 的最大值。因此,在我的线程将 Membership 对象写回数据库之前,我需要使用某种数据库事务来防止另一个线程增加数据库中的值。

如果我使用存储过程,这将非常简单,但我无法弄清楚如何使用纯 c# 来做到这一点......

下面的代码在数据库中创建了 100 个具有重复 MembershipNumbers 的 Membership 实体。我需要使用事务来确保在 c# 代码中生成的所有会员编号都是唯一的。

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        p.Go();;
    }

    public void Go()
    {
        long memberId;
        long membershipDefId;

        using(var unitOfWork = new UnitOfWork())
        {
            // Setup - create test club and member entities

            var testUsername = ("TestUserName" + Guid.NewGuid()).Substring(0, 29);
            var member = new Member()
                             {
                                 UserName = testUsername
                             };

            var testmemebrshpDefName = ("TestMembershipDef" + Guid.NewGuid()).Substring(0, 29);
            var membershipDefinition = new ClubMembershipDefinition()
            {
                ClubId = 1,
                Name = testmemebrshpDefName
            };

            unitOfWork.MemberRepository.Add(member);
            unitOfWork.MembershipDefinitionRepository.Add(membershipDefinition);

            unitOfWork.Save();

            memberId = member.Id;
            membershipDefId = membershipDefinition.Id;
        }

        Task[] tasks = new Task[100];

        // Now try to add a membership to the Member object, linking it to the test Club's single Club Definition
        for (int i = 0; i < 100; i++)
        {
            var task = new Task(() => CreateMembership(memberId, membershipDefId));
            tasks[i] = task;
            task.Start();
        }
        Task.WaitAll(tasks);
    }

    private void CreateMembership(long memberId, long membershipDefId)
    {
        using (var unitOfWork = new UnitOfWork())
        {
            var member = unitOfWork.MemberRepository.GetById(memberId);
            var membershipDef = unitOfWork.MembershipDefinitionRepository.GetById(membershipDefId);

            var membership = new ClubMembership()
                                    {
                                        ClubMembershipDefinition = membershipDef
                                    };

            membership.MembershipNumber = (unitOfWork.MembershipRepository.GetMaxMembershipNumberForClub(membershipDef.ClubId) ?? 0) + 1;

            member.ClubMemberships.Add(membership);
            unitOfWork.Save();
        }
    }

}

public class UnitOfWork : IUnitOfWork, IDisposable
{
    internal ClubSpotEntities _dbContext = new ClubSpotEntities();
    internal MemberRepository _memberRepository;
    internal MembershipRepository _membershipRepository;
    internal MembershipDefinitionRepository _membershiDefinitionpRepository;

    public MemberRepository MemberRepository
    {
        get
        {
            if (_memberRepository == null)
                _memberRepository = new MemberRepository(_dbContext);

            return _memberRepository; ;
        }
    }

    public MembershipRepository MembershipRepository
    {
        get
        {
            if (_membershipRepository == null)
                _membershipRepository = new MembershipRepository(_dbContext);

            return _membershipRepository; ;
        }
    }

    public MembershipDefinitionRepository MembershipDefinitionRepository
    {
        get
        {
            if (_membershiDefinitionpRepository == null)
                _membershiDefinitionpRepository = new MembershipDefinitionRepository(_dbContext);

            return _membershiDefinitionpRepository; ;
        }
    }

    public virtual int Save()
    {
        return _dbContext.SaveChanges();

    }

    private bool _disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                _dbContext.Dispose();
            }
        }
        this._disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

public class MembershipRepository
{
    ClubSpotEntities _dbContext = new ClubSpotEntities();

    public MembershipRepository(){}

    public MembershipRepository(ClubSpotEntities dbContext)
    {
        _dbContext = dbContext;
    }

    public IEnumerable<ClubMembership> GetAll()
    {
        return _dbContext.Set<ClubMembership>().ToList<ClubMembership>();
    }

    public ClubMembership GetById(long id)
    {
        return _dbContext.ClubMemberships.First(x => x.Id == id);
    }

    public long? GetMaxMembershipNumberForClub(long clubId)
    {
        return _dbContext.ClubMemberships.Where(x => x.ClubMembershipDefinition.ClubId == clubId).Max(x => x.MembershipNumber);
    }

    public ClubMembership Add(ClubMembership entity)
    {
        return _dbContext.Set<ClubMembership>().Add(entity);
    }

    public void Delete(ClubMembership membership)
    {
        _dbContext.Set<ClubMembership>().Remove(membership);
    }

    public void Save()
    {
        _dbContext.SaveChanges();
    }
}


public partial class ClubMembership
{
    public long Id { get; set; }
    public long MembershipDefId { get; set; }
    public Nullable<long> MemberId { get; set; }
    public Nullable<long> MembershipNumber { get; set; }

    public virtual ClubMembershipDefinition ClubMembershipDefinition { get; set; }
    public virtual Member Member { get; set; }
}

public partial class ClubMembershipDefinition
{
    public ClubMembershipDefinition()
    {
        this.ClubMemberships = new HashSet<ClubMembership>();
    }

    public long Id { get; set; }
    public long ClubId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<ClubMembership> ClubMemberships { get; set; }
}

public partial class Member
{
    public Member()
    {
        this.ClubMemberships = new HashSet<ClubMembership>();
    }

    public long Id { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<ClubMembership> ClubMemberships { get; set; }
}
4

1 回答 1

2

您可以在实例化新的 UnitOfWork 时创建事务范围,并在完成时提交它。这不是完整的例子:

class UnitOfWork
{
     ClubSpotEntities _dbContext;
     TransactionScope _transaction;

     public UnitOfWork()
     {
         _dbContext = new ClubSpotEntities();
         _transaction = new TransactionScope();
     }

     public void Complete()
     {
         _dbContext.SaveChanges();
         _transaction.Complete();
     }

     ...
}

UPD: 正如史蒂文所说,这不是您问题的解决方案。而且 UnitOfWork 帮不了你,在这种情况下,TransactionScope 也不是解决方案。EF 不支持你想使用的悲观锁,但是你可以试试这个解决方案

于 2012-08-16T08:29:58.413 回答