在进行规模比较大的项目开发时,我们根据领域驱动设计的原则将系统划分为若干独立的子系统,单独进行开发,在ABP项目中,我们可以划分为不同的模块,模块之间相对独立。这种情况下,每个模块有各子的DbContext,负责对本模块中实体的持久化操作。这样做可以降低系统的复杂程度,可以多模块并行开发,并且不互相干扰。这样做的问题是如果模块之间需要进行联合查询,会出现问题,因为DbContext之间不能进行联合查询。这种情况下,我们可以为跨界查询定义一个新的DbContext,由于这个DbContext只用于查询,其中定义的实体不一定与数据库中的表完全一致。比如,我们需要在某个模块中进行与Abp用户、角色的联合查询,我们可以在这个模块中定义查询需要的AbpUser,AbpRole和AbpUserRole实体:
public class AbpUser
{
public virtual long Id { get; set; }
public string UserName { get; set; }
public int? TenantId { get; set; }
}
namespace jiagoushi_cn.MyFlow.Core
{
public class AbpRole
{
public long Id { get; set; }
public int? TenantId { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
}
}
namespace jiagoushi_cn.MyFlow.Core
{
public class AbpUserRole
{
public long Id { get; set; }
public int? TenantId { get; set; }
public long UserId { get; set; }
public long RoleId { get; set; }
}
}
DbContext的定义与通常的定义一样:
namespace jiagoushi_cn.MyFlow.EntityFramework
{
public class MyFlowQueryDbContext : AbpDbContext
{
public virtual IDbSet<AbpUser> AbpUsers { get; set; }
public virtual IDbSet<AbpRole> AbpRoles { get; set; }
public virtual IDbSet<AbpUserRole> AbpUserRoles { get; set; }
public virtual IDbSet<ProcessModel> ProcessModels { get; set; }
public virtual IDbSet<ProcessInstanceStatus> ProcessInstanceStatus { get; set; }
public virtual IDbSet<ProcessInstancePermission> ProcessInstancePermissions { get; set; }
public MyFlowQueryDbContext()
: base("name=Default")
{
}
public MyFlowQueryDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
//This constructor is used in tests
public MyFlowQueryDbContext(DbConnection existingConnection)
: base(existingConnection, false)
{
}
public MyFlowQueryDbContext(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
唯一不同的是,在模块初始化时,这个DbContext不需要对数据库做任何操作:
namespace jiagoushi_cn.MyFlow.EntityFramework
{
[DependsOn(
//typeof(AbpZeroEntityFrameworkModule), typeof(MyPlatCoreModule),
typeof(MyFlowCoreModule),
typeof(AbpEntityFrameworkModule))]
public class MyFlowDataModule : AbpModule
{
public override void PreInitialize()
{
Database.SetInitializer(new CreateDatabaseIfNotExists<MyFlowDbContext>());
Database.SetInitializer<MyFlowQueryDbContext>(null);
Configuration.DefaultNameOrConnectionString = "Default";
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
}
上面的代码中,调用了两次Database.SetInitializer,一次是针对MyFlowDbContext,这个DbContext负责数据库操作,一次针对MyFlowQueryDbContext,这个负责查询。
在使用时,可以使用MyFlowQueryDbContext实现针对User和Role的查询:
[UnitOfWork]
public IEnumerable<ProcessInstanceStatus> GetProcessInstanceStatuses(long userid,int tenantid,string processName)
{
var ctx= _dbqueryContextprovider.GetDbContext();
var ids = (from user in ctx.AbpUsers
from roles in ctx.AbpRoles
from userroles in ctx.AbpUserRoles
where user.Id == userid && user.TenantId == tenantid
&& user.Id==userroles.UserId && roles.Id==userroles.RoleId
select roles.Name ).ToArray();
IQueryable <ProcessInstanceStatus> lst = from p in ctx.ProcessInstanceStatus
from q in ctx.ProcessInstancePermissions
join user in ids on q.RoleName equals user
where p.InstanceId== q.InstanceId && (string.IsNullOrEmpty(q.UserName) || q.UserName == userid.ToString())
select p;
if (!string.IsNullOrEmpty(processName))
{
return lst.Where(o => o.ProcessName == processName).ToList();
}
return lst.ToList();
}