nhibernate - SQL Azure 联合与 S#arp 架构

标签 nhibernate azure-sql-database s#arp-architecture sharp-architecture federation

我正在使用 S#harp 架构,有人找到了使用它访问 SQL Azure 联合的方法吗?

我知道以下命令必须在事务外部执行,因为 SQL Azure 不允许在事务内使用“use Federation”语句。

use Federation CustomerFederation (CustomerID=2) with reset, filtering=on 
GO
<some sql statement...>
GO

这里还有另一篇文章展示了创建自定义 NHibernate Session 类的示例,但是如何使用 S#arp 架构来完成/扩展呢?

我还知道 SQL Azure Federation 还有其他分片选项,例如 NHibernate.Shards 或 Multi-Tenancy S#arp 架构扩展,但请继续回答问题,而不是提供其他选项。

我知道我不是唯一使用 S#arp 架构和 SQL Azure 联合的人,而且 Google 没有提供太多信息,因此如果其他人找到了解决方案,请分享。

最佳答案

由于尚未有人回复我的帖子,我经过几天的研究才做出回复。我能够与 S#harp 集成,具有 1 个接口(interface)和 3 个类(我希望它们是一个开箱即用的解决方案?)。

下面提供的代码可以复制并粘贴到任何应用程序中,并且应该可以正常工作。唯一的异常(exception)是 FederationSessionHelper 类。这是特定于每个应用程序的,您获取的信息可能会发生变化。我的 web.config 中有一个应用程序设置部分,其中包含联合名称等。此外,当用户进行身份验证时,我会解析他们来自的根 url,然后查询联合根以找出他们是什么租户(我有一个我创建的自定义租户表)。然后,我将 session 中的租户 ID 放置在键“FederationKeyValue_Key”下,然后将在 FederationSession 类中使用该键来构建 Use Federation 语句。

/// <summary>
/// Interface used to retrieve app specific info about your federation.
/// </summary>
public interface IFederationSessionHelper
{
    string ConnectionString { get; }
    string FederationName { get; }
    string DistributionName { get; }
    string FederationKeyValue { get; }
}

/// <summary>
/// This is were you would get things specific for your application. I have 3 items in the web.config file and 1 stored in session. You could easily change this to get them all from the repository or wherever meets the needs of your application.
/// </summary>
public class FederationSessionHelper : IFederationSessionHelper
{
    private const string ConnectionStringKey = "ConnectionString_Key";
    private const string FederationNameKey = "FederationName_Key";
    private const string DistributionNameKey = "DistributionName_Key";
    private const string FederationKeyValueKey = "FederationKeyValue_Key";

    public string ConnectionString { get { return ConfigurationManager.ConnectionStrings[ConnectionStringKey].ConnectionString; } }
    public string FederationName { get { return ConfigurationManager.AppSettings[FederationNameKey]; } }
    public string DistributionName { get { return ConfigurationManager.AppSettings[DistributionNameKey]; } }

    //When user authenitcates, retrieve key value and store in session. This will allow to retrieve here.
    public string FederationKeyValue { get { return Session[FederationKeyValueKey]; } }       
}

/// <summary>
/// This is were the magic begins and where the integration with S#arp occurs. It manually creates a Sql Connections and adds it the S#arps storage.  It then runs the Use Federation command and leaves the connection open. So now when you use an NhibernateSession.Current it will work with Sql Azure Federation.
/// </summary>
public class FederationSession : IDisposable
{
    private SqlConnection _sqlConnection;

    public void Init(string factoryKey,
                       string federationName,
                       string distributionName,
                       string federationKeyValue,
                       bool doesFilter,
                       string connectionString)
    {
        var sql = string.Format("USE FEDERATION {0}({1} = '{2}') WITH RESET, FILTERING = {3};", federationName, distributionName, federationKeyValue, (doesFilter) ? "ON" : "OFF");
        _sqlConnection = new SqlConnection(connectionString);

        _sqlConnection.Open();
        var session = NHibernateSession.GetSessionFactoryFor(factoryKey).OpenSession(_sqlConnection);
        NHibernateSession.Storage.SetSessionForKey(factoryKey, session);

        var query = NHibernateSession.Current.CreateSQLQuery(sql);
        query.UniqueResult();
    }

    public void Dispose()
    {
        if (_sqlConnection != null && _sqlConnection.State != ConnectionState.Closed)
            _sqlConnection.Close();
    }
}

/// <summary>
/// This was just icing on the cake.  It inherits from S#arps TransactionAttribute and calls the FederationSession helper to open a connection.  That way all you need to do in decorate your controller with the newly created [FederationTransaction] attribute and thats it.
/// </summary>
public class FederationTransactionAttribute : TransactionAttribute
{
    private readonly string _factoryKey = string.Empty;
    private bool _doesFilter = true;

    /// <summary>
    ///     When used, assumes the <see cref = "factoryKey" /> to be NHibernateSession.DefaultFactoryKey
    /// </summary>
    public FederationTransactionAttribute()
    { }

    /// <summary>
    ///     Overrides the default <see cref = "factoryKey" /> with a specific factory key
    /// </summary>
    public FederationTransactionAttribute(string factoryKey = "", bool doesFilter = true)
        : base(factoryKey)
    {
        _factoryKey = factoryKey;
        _doesFilter = doesFilter;
    }        

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var federationSessionHelper = ServiceLocator.Current.GetInstance<IFederationSessionHelper>();
        var factoryKey = GetEffectiveFactoryKey();
        new FederationSession().Init(factoryKey,
                                        federationSessionHelper.FederationName,
                                        federationSessionHelper.DistributionName,
                                        federationSessionHelper.FederationKeyValue,
                                        _doesFilter,
                                        federationSessionHelper.ConnectionString);

        NHibernateSession.CurrentFor(factoryKey).BeginTransaction();
    }

    private string GetEffectiveFactoryKey()
    {
        return String.IsNullOrEmpty(_factoryKey) ? SessionFactoryKeyHelper.GetKey() : _factoryKey;
    }        
}

现在我可以用新创建的 [FederationTransaction] 替换 S#arp 的 [Transaction] 属性,如下所示:

[HttpGet] 
[FederationTransaction]
public ActionResult Index()
{
   var viewModel = NHibernateSession.Current.QueryOver<SomeDemoModel>().List()
   return View(viewModel);            
}

Controller 中的任何代码都不需要知道它使用 Sql Azure Federation。一切都应该正常。

有什么想法吗?有人找到更好的解决方案吗?请分享。

关于nhibernate - SQL Azure 联合与 S#arp 架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11252453/

相关文章:

.net - 运算符和参数中的 HQL

c# - 每个请求的 spring.net nhibernate session /事务

sql-server - 无法确定至少一个变体参数的参数类型

asp.net-mvc - ASP.NET MVC + S#arp Architectur + Spark View Engine - 无法使用 ActionLinkForAreas

asp.net-mvc - 在 SharpArchitecture 的 VB.Net 转换中实现 StructureMap 的问题

c# - Winform 应用程序的锐利架构?

nhibernate - NHibernate Profiler 的初始启动方式

nhibernate - 流利的NHibernate HasManyToMany()映射

SQL Azure 数据库的 SQL 代理替代方案

sql-server - 如何更改 Azure SQL 数据库中的时区?