abp vnext 事务,多表查询,自定义仓储 电脑版发表于:2022/7/24 17:44 [TOC] abp vnext 中的通用仓储主要是封装的单表操作,如果是实现事务的话最好还是封装一个自定义仓储。 ### 自定义仓储大概的结构如下: ![](https://img.tnblog.net/arcimg/aojiancc2/afc4ec09297847f2811c0fa4bb6d51f9.png) #### 然后使用事务的方式和使用ef就完全一样了 我们这里是在数据库访问层用的ef ``` /// <summary> /// 事务示例 /// </summary> /// <param name="landInfo"></param> /// <param name="userInfo"></param> /// <returns></returns> public async Task<int> UpdateTrans(LandInfo landInfo, UserInfo userInfo) { var getDbContext = await GetDbContextAsync(); using (var transaction = getDbContext.Database.BeginTransaction()) { try { getDbContext.LandInfo.Update(landInfo); getDbContext.SaveChanges(); userInfo.UserDetailsId = landInfo.Id; getDbContext.UserInfo.Add(userInfo); getDbContext.SaveChanges(); transaction.Commit(); return 1; } catch (Exception) { transaction.Rollback(); return -1; } } } ``` #### 自定义仓储下多表查询的话,也是和使用ef一样了 ``` /// <summary> /// 多表查询示例 /// </summary> public async void JoinTemp() { var dbContext = await GetDbContextAsync(); /*表1:UserInfo ; 表2:UserDetails ; 关联条件 UserInfo.UserDetailsId = UserDetails.Id 返回结果表1的UserName字段,表2的avatar字段 */ //方法1 dbContext.UserInfo.Join(dbContext.UserDetails, a => a.UserDetailsId, b => b.Id, (a, b) => new { userName = a.UserName, avatar = b.avatar }); //方法2: var query = from u in dbContext.UserInfo join p in dbContext.UserDetails on u.UserDetailsId equals p.Id select new { username = u.UserName, avatar = p.avatar }; //方法3:直接执行sql语句返回结果 } ``` 整体点的代码贴一下 ``` using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using WY.JBLand.Domain.Land; using WY.JBLand.Domain.User; namespace WY.JBLand.EntityFrameworkCore.Land { public class LandInfoRepository : EfCoreRepository<WyJBLandDbContext, LandInfo, int>, ILandInfoRepository { public LandInfoRepository(IDbContextProvider<WyJBLandDbContext> dbContextProvider) : base(dbContextProvider) { } /// <summary> /// 多表查询示例 /// </summary> public async void JoinTemp() { var dbContext = await GetDbContextAsync(); /*表1:UserInfo ; 表2:UserDetails ; 关联条件 UserInfo.UserDetailsId = UserDetails.Id 返回结果表1的UserName字段,表2的avatar字段 */ //方法1 dbContext.UserInfo.Join(dbContext.UserDetails, a => a.UserDetailsId, b => b.Id, (a, b) => new { userName = a.UserName, avatar = b.avatar }); //方法2: var query = from u in dbContext.UserInfo join p in dbContext.UserDetails on u.UserDetailsId equals p.Id select new { username = u.UserName, avatar = p.avatar }; //方法3:直接执行sql语句返回结果 } /// <summary> /// 事务示例 /// </summary> /// <param name="landInfo"></param> /// <param name="userInfo"></param> /// <returns></returns> public async Task<int> UpdateTrans(LandInfo landInfo, UserInfo userInfo) { var getDbContext = await GetDbContextAsync(); using (var transaction = getDbContext.Database.BeginTransaction()) { try { getDbContext.LandInfo.Update(landInfo); getDbContext.SaveChanges(); userInfo.UserDetailsId = landInfo.Id; getDbContext.UserInfo.Add(userInfo); getDbContext.SaveChanges(); transaction.Commit(); return 1; } catch (Exception) { transaction.Rollback(); return -1; } } } public async Task<LandInfo> FindByNameAsync(string name) { var dbSet = await GetDbSetAsync(); return await dbSet.FirstOrDefaultAsync(author => author.landName == name); } public async Task<List<LandInfo>> GetListAsync(int skipCount, int maxResultCount, string filter = null) { var dbSet = await GetDbSetAsync(); return await dbSet .WhereIf( !filter.IsNullOrWhiteSpace(), author => author.landName.Contains(filter) ) .OrderBy(a => a.Id) .Skip(skipCount) .Take(maxResultCount) .ToListAsync(); } } } ``` ### 当然使用通用仓储也可以实现多表查询,比如通过通用仓储拿到上下文对象后在去join,但不建议这么去使用 比如连表查询join,可以这样: ``` public async void JoinTemp() { WyJBLandDbContext dbContext = await _landInfoRepository.GetDbContextAsync() as WyJBLandDbContext; dbContext.UserInfo.Join(dbContext.UserDetails, a => a.UserDetailsId, b => b.Id, (a, b) => new { userName = a.UserName, avatar = b.avatar }); } ``` 但是这种直接在应用层使用上下文对象的方法是不科学的,依赖性过于强了 ### 我们建议使用的方法是通过通用仓储拿到GetQueryableAsync()后实现join 如下: ``` public async void TestJoin() { var queryable = (from fileManager in await _fileManagerRepository.GetQueryableAsync() join fileType in await _fileTypeRepository.GetQueryableAsync() on fileManager.FileTypeId equals fileType.Id select new { fileName = fileManager.FileName, fileTypeName = fileType.FileTypeName }); var reuslt = queryable.ToList(); } ``` 这个和直接使用原生ef实现join其实是一个意思,原生ef通过上下文点出来的实体是一个DbSet: ![](https://img.tnblog.net/arcimg/aojiancc2/e8ba8602c4a04815b37363d4120f9a14.png) 而DbSet其实本身也是IQueryable,所以通过GetQueryableAsync()获取到实体的IQueryable对象当然也可以直接join了 ![](https://img.tnblog.net/arcimg/aojiancc2/3438c88930ed413eac2627f55d3d1bef.png)