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

标签 asp.net-mvc nhibernate

我正在尝试将 NHibernate 用于具有旧数据库的新应用程序。它进展顺利,但我被卡住了,找不到解决问题的好方法。

假设我有这个模型:

  • 服务表(Id、ServiceName..)
  • 电影表(ID、标题、...)
  • 将服务和电影关联起来的目录表(IdContent、Name、IdMovie、IdService)

  • 所以我映射了这个,一切都很顺利。现在我可以检索电影,获取所有相关内容,...
    我的应用程序是电影商店“生成器”。每个“服务”实际上是一个不同的商店,当用户进入我的网站时,他会被重定向到其中一个商店,显然,我必须向他展示仅适用于他的商店的电影。想法是:用户来了,他的服务被认可了,我给他看内容与他的服务相关的电影。我还需要能够为后台检索电影的所有内容。
    我正在尝试找到最透明的方式来使用 NHibernate 完成此任务。我无法真正更改 db 模型。

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

  • 这些都没有真正让我满意。有没有好的方法来做到这一点?

    谢谢 !

    最佳答案

    您正在询问同一数据库中所有租户的 Multi-Tenancy 。我已经使用 Ninject 依赖注入(inject)有效地处理了这种情况。在我的应用程序中,租户称为“手动”,我将在示例代码中使用它。

    路线需要包含租户,例如

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

    可以对租户设置约束以限制允许的租户。

    我使用 Ninject 将 ISessionFactory 配置和提供为单例,并在 session-per-request 策略中提供 ISession。这是使用 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);
        }
    }
    

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

    Ninject 可以处理将 ISession 注入(inject)存储库和将存储库注入(inject) Controller 。 Controller 操作中的任何查询都必须基于存储库方法,以便应用过滤器。诀窍是从路由值中注入(inject) 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());
    }
    

    并且存储库绑定(bind)被声明为注入(inject)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

    关于asp.net-mvc - NHibernate 和上下文实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21878548/

    相关文章:

    c# - 为什么 Await 不会出现阻止对 EF 上下文的第二次操作

    javascript - MVC 中的页面加载

    nhibernate - 在 NHibernate 中限制结果

    NHibernate:如果参数不为空,则添加条件

    NHibernate dateTime 作为 ID 坏主意?

    c# - NHibernate 平等 : How do I ensure only one row is persisted from many "equal" . NET 对象?

    nhibernate - 在 NHibernate 中使用非默认构造函数

    c# - 返回文件或 View 的方法

    c# - PostSharp 的任何免费替代品

    asp.net-mvc - ASP.NET MVC 验证码