如何处理域模型的按需数据获取

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 非常令人困惑,因为它用于连接到数据库的提供程序。我建议将其更改为其他内容。示例:RepositoryContext

由于我在 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(业务层)中的所有域或业务模型(例如 IFolderFolder)。我只在模型中放置字段,逻辑进入服务。 但是,我只对大型企业解决方案中的层使用单独的项目。这种分离适用于大团队。对于较小的应用程序,我只是将所有层放在同一个项目中。【参考方案2】:

是否可以将提供者注入到业务模型对象中

是的,如果您将其称为“业务”提供商:)。其实不要太认真对待所有这些术语“注入”、“提供者”。直到您传递(到业务模型层的方法/构造函数)在业务模型层上声明的接口(以及文档抽象泄漏)-您没问题。

我应该在构造函数中实例化上下文吗?

这可能被视为应记录在案的抽象泄漏。重用的上下文可能会被破坏或与另一个线程共享等等——所有这些都会带来副作用。所以开发人员倾向于为每个“用户请求”创建一个像 dbContext 这样的“重”对象(这通常意味着每个服务调用using(var context = new DbContext()),但并非总是如此,例如有时我与身份验证服务调用共享它 - 检查是否允许下一个操作对于这个用户)。顺便说一句,DbContext 的创建速度非常快,所以不要仅仅为了“优化”而重用它。

【讨论】:

是的,我的印象是数据库上下文是一个昂贵的创建对象,但现在我将更好地利用它。谢谢。 您可能混淆了这些概念。数据库连接本身是一种昂贵的资源,但 db 上下文通常是一个轻量级的类(我的只有几行)。但是,虽然数据库连接很昂贵,不应该经常打开和关闭,但它是通过连接池为您管理的。因此,请确保在完成后立即关闭它(using() 语句几乎可以完美地做到这一点),不要担心它,因为它只会返回到连接池而不是真正立即关闭.

以上是关于如何处理域模型的按需数据获取的主要内容,如果未能解决你的问题,请参考以下文章

如何处理重叠 Mousareas 中的按下和释放信号?

EasyNVR非按需拉流返回的RTMP流地址无法播放如何处理?

Echarts的按需加载

领域驱动设计中的验证

为啥我的按需资源仍处于正在下载...状态?

EasyNVR多通道非按需直播视频播放时卡顿如何处理?