如何处理域模型的按需数据获取
Posted
技术标签:
【中文标题】如何处理域模型的按需数据获取【英文标题】:How to handle on-demand data fetching for Domain Models 【发布时间】:2018-06-15 13:55:15 【问题描述】:鉴于以下情况...
我担心两件事......
1) 可以将提供者注入业务模型对象吗? - 就像我对文件夹实现所做的那样,因为我想按需加载子文件夹。
2) 由于我在 IFolderDataProvider 的 Sql 实现中注入 DbContext,上下文可以被释放或者它可以永远存在,因此我应该在构造函数中实例化上下文吗?
如果这个设计不正确,那么请告诉我应该如何加载商业模型。
//Business model.
interface IFolder
int Id get;
IEnumerable<IFolder> GetSubFolders();
class Folder : IFolder
private readonly int id_;
private readonly IFolderDataProvider provider_;
public Folder(int id, IFolderDataProvider provider)
id_ = id;
provider_ = provider;
public int Id get;
public IEnumerable<IFolder> GetSubFolders()
return provider_.GetSubFoldersByParentFolderId(id_);
interface IFolderDataProvider
IFolder GetById(int id);
IEnumerable<IFolder> GetSubFoldersByParentFolderId(int id);
class SqlFolderDataProvider : IFolderDataProvider
private readonly DbContext context_;
public SqlFolderDataProvider(DbContext context)
context_ = context;
public IFolder GetById(int id)
//uses the context to fetch the required folder entity and translates it to the business object.
return new Folder(id, this);
public IEnumerable<IFolder> GetSubFoldersByParentFolderId(int id)
//uses the context to fetch the required subfolders entities and translates it to the business objects.
【问题讨论】:
您项目的是 .Net Core 吗?您应该添加标签。 附注:我们在类私有变量的开头而不是结尾使用下划线。 【参考方案1】:可以将提供者注入业务模型对象吗? - 就像我对文件夹实现所做的那样,因为我想按需加载子文件夹。
是的,您还能如何调用提供者并获取数据?
但是,后缀DataProvider
非常令人困惑,因为它用于连接到数据库的提供程序。我建议将其更改为其他内容。示例:Repository
、Context
。
由于我在 IFolderDataProvider 的 Sql 实现中注入 DbContext,上下文可以被释放或者它可以永远存在,因此我应该在构造函数中实例化上下文吗?
它不一定会永远存在。当您将其添加为服务时,您可以在 ConfigureServices
函数中决定其生命周期,因此您可以将其范围从 Singleton
更改为您喜欢的任何内容。我个人将DBContext
服务的范围设置为Transient
,并且我还使用连接字符串在那里启动它:
services.AddTransient<IDbContext, DbContext>(options =>
new DbContext(Configuration.GetConnectionString("DefaultDB")));
然后我在我的数据层文件中的每个函数中打开和关闭数据库连接(你称之为提供者)。我在 using()
语句中打开它,然后保证在任何情况下(正常或异常)关闭连接。像这样的:
public async Task<Location> GetLocation(int id)
string sql = "SELECT * FROM locations WHERE id = @p_Id;";
using (var con = _db.CreateConnection())
//get results
【讨论】:
谢谢你,伙计。你的回答很有用。 IFolderRepository接口应该在BLL项目还是DAL项目?因为我读过文章说 BLL 和 DAL 不应该互相了解。 看来您使用的是 3 层设计。在那种情况下,我将我所有的存储库(例如IFolderRepository
及其实现FolderRepository
)与DbContext
以及我的所有服务(我称之为服务或门面)(例如@987654334 @ 和 FolderService
) 以及我的 BL(业务层)中的所有域或业务模型(例如 IFolder
和 Folder
)。我只在模型中放置字段,逻辑进入服务。
但是,我只对大型企业解决方案中的层使用单独的项目。这种分离适用于大团队。对于较小的应用程序,我只是将所有层放在同一个项目中。【参考方案2】:
是否可以将提供者注入到业务模型对象中
是的,如果您将其称为“业务”提供商:)。其实不要太认真对待所有这些术语“注入”、“提供者”。直到您传递(到业务模型层的方法/构造函数)在业务模型层上声明的接口(以及文档抽象泄漏)-您没问题。
我应该在构造函数中实例化上下文吗?
这可能被视为应记录在案的抽象泄漏。重用的上下文可能会被破坏或与另一个线程共享等等——所有这些都会带来副作用。所以开发人员倾向于为每个“用户请求”创建一个像 dbContext 这样的“重”对象(这通常意味着每个服务调用using(var context = new DbContext())
,但并非总是如此,例如有时我与身份验证服务调用共享它 - 检查是否允许下一个操作对于这个用户)。顺便说一句,DbContext 的创建速度非常快,所以不要仅仅为了“优化”而重用它。
【讨论】:
是的,我的印象是数据库上下文是一个昂贵的创建对象,但现在我将更好地利用它。谢谢。 您可能混淆了这些概念。数据库连接本身是一种昂贵的资源,但 db 上下文通常是一个轻量级的类(我的只有几行)。但是,虽然数据库连接很昂贵,不应该经常打开和关闭,但它是通过连接池为您管理的。因此,请确保在完成后立即关闭它(using()
语句几乎可以完美地做到这一点),不要担心它,因为它只会返回到连接池而不是真正立即关闭.以上是关于如何处理域模型的按需数据获取的主要内容,如果未能解决你的问题,请参考以下文章