7

私は数日間これに頭を悩ませようとしました、そして仕事の単位とTransactionScopeの周りにたくさんのチュートリアルがあります、しかし私は2つについて一緒に話すものを見つけることができません。どんな助けでも大歓迎です!

UnitOfWorkパターンとタイプごとのリポジトリを備えたEntityFrameworkを使用しています。以下の簡単なコードに従って、MemberとMembershipDefinitionエンティティがあります。2つをリンクするMembershipエンティティを作成したいのですが、Membershipオブジェクトを作成するときに、ビジネスロジックに基づいてDBに最大値を照会したいと思います。したがって、ある種のDBトランザクションを使用して、スレッドがMembershipオブジェクトをDBに書き戻す前に、別のスレッドがデータベース内の値をインクリメントしないようにする必要があります。

ストアドプロシージャを使用している場合、これは非常に簡単ですが、純粋なC#を使用してそれを行う方法を理解することはできません...

以下のコードは、重複したMembershipNumbersを使用してデータベースに100の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 に答える