加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – NHibernate和上下文实体

发布时间:2020-12-16 03:16:17 所属栏目:asp.Net 来源:网络整理
导读:我正在尝试将NHibernate用于带有旧数据库的新应用程序.它运行得很好,但我陷入困境,无法找到解决问题的好方法. 假设我有这个模型: 服务表(Id,ServiceName ..) 电影表(Id,Title,…) 一个关联服务和电影的内容表(IdContent,Name,IdMovie,IdService) 所以我绘制
我正在尝试将NHibernate用于带有旧数据库的新应用程序.它运行得很好,但我陷入困境,无法找到解决问题的好方法.

假设我有这个模型:

>服务表(Id,ServiceName ..)
>电影表(Id,Title,…)
>一个关联服务和电影的内容表(IdContent,Name,IdMovie,IdService)

所以我绘制了这个并且一切顺利.现在我可以检索一部电影,获取所有相关的内容,……
我的应用程序是电影商店“发电机”.每个“服务”实际上是一个不同的商店,当用户进入我的网站时,他被重定向到其中一个商店,显然,我必须向他展示他的商店可用的电影.这个想法是:用户来了,他的服务得到认可,我向他展示了与他的服务相关的内容.我需要能够为后台检索电影的所有内容.
我正在尝试用NHibernate找到最透明的方法来实现这一点.我无法真正对db模型进行更改.

我想了几个解决方案:

>将服务条件添加到我的所有查询中.会工作,但它有点麻烦.该模型非常复杂,有大量的表/查询..
>使用nhibernate过滤器.看似理想并且工作得很好,我在所有映射中添加了serviceid上的过滤器,并在我的用户服务被识别后立即执行了EnableFilter但是… nhibernate过滤的集合不适用于第二个lvl缓存(在我的情况下是redis)和第二个lvl缓存使用是必需的.
>将计算属性添加到我的对象,如Movie.PublishedContents(Int32 serviceId).可能会工作但需要编写大量代码并“污染”我的域名.
>添加从我的nhibernate实体继承的新实体,如PublishedMovie:Movie,它只显示上下文数据

这些都不能让我满意.有没有办法做到这一点?

谢谢 !

解决方法

您询问的是同一数据库中所有租户的多租户问题.我使用Ninject依赖注入有效地处理了这种情况.在我的应用程序中,租户被称为“手动”,我将在示例代码中使用它.

该路线需要包含租户,例如

{manual}/{controller}/{action}/{id}

可以在租户上设置约束以限制允许的租户.

我使用Ninject配置和提供ISessionFactory作为单个和ISession in session-per-request策略.这是使用Ninject Provider类封装的.

我使用轻量级存储库类进行过滤,例如

public class ManualRepository
{
    private readonly int _manualId;
    private readonly ISession _session;

    public ManualRepository(int manualId,ISession session)
    {
        _manualId = manualId;
        _session = session;
    }

    public IQueryable<Manual> GetManual()
    {
        return _session.Query<Manual>().Where(m => m.ManualId == _manualId);
    }
}

如果你想要漂亮的网址,你需要将租户路由参数转换为相应的数据库值.我在web.config中设置了这些,并在启动时将它们加载到字典中. IRouteConstraint实现读取“手动”路由值,查找它,并设置“manualId”路由值.

Ninject可以处理将ISession注入存储库并将存储库注入控制器.控制器操作中的任何查询都必须基于存储库方法,以便应用过滤器.诀窍是从路由值注入manualId.在NinjectWebCommon中,我有两种方法可以完成此任务:

private static int GetManualIdForRequest()
{
    var httpContext = HttpContext.Current;
    var routeValues = httpContext.Request.RequestContext.RouteData.Values;
    if (routeValues.ContainsKey("manualId"))
    {
        return int.Parse(routeValues["manualId"].ToString());
    }
    const string msg = "Route does not contain 'manualId' required to construct object.";
    throw new HttpException((int)HttpStatusCode.BadRequest,msg);
}

/// <summary>
/// Binding extension that injects the manualId from route data values to the ctor.
/// </summary>
private static void WithManualIdConstructor<T>(this IBindingWithSyntax<T> binding)
{
    binding.WithConstructorArgument("manualId",context => GetManualIdForRequest());
}

并声明存储库绑定以注入manualId.通过惯例可能有更好的方法来实现这一目标.

kernel.Bind<ManualRepository>().ToSelf().WithManualIdConstructor();

最终结果是查询遵循模式

var manual = _manualRepository
    .GetManual()
    .Where(m => m.EffectiveDate <= DateTime.Today)
    .Select(m => new ManualView
    {
        ManualId = m.ManualId,ManualName = m.Name
    }).List();

我不需要担心在我的查询中过滤每个租户.

至于二级缓存,我不在这个应用程序中使用它,但我的理解是你可以设置缓存区域来隔离租户.这应该让你开始:http://ayende.com/blog/1708/nhibernate-caching-the-secong-level-cache-space-is-shared

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读