Nhibernate 具有S#arp体系结构的SQL Azure联合

Nhibernate 具有S#arp体系结构的SQL Azure联合,nhibernate,azure-sql-database,s#arp-architecture,sharp-architecture,federation,Nhibernate,Azure Sql Database,S#arp Architecture,Sharp Architecture,Federation,我正在使用S#harp体系结构,有人找到了使用它访问SQL Azure联合会的方法吗 我知道以下命令必须在事务之外执行,因为SQLAzure不允许在事务中使用“use Federation”语句 use Federation CustomerFederation (CustomerID=2) with reset, filtering=on GO <some sql statement...> GO 在重置、筛选=打开的情况下使用联合用户界面(CustomerID=2) 去 去

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

我知道以下命令必须在事务之外执行,因为SQLAzure不允许在事务中使用“use Federation”语句

use Federation CustomerFederation (CustomerID=2) with reset, filtering=on 
GO
<some sql statement...>
GO
在重置、筛选=打开的情况下使用联合用户界面(CustomerID=2)
去
去
这里还有一篇文章展示了一个创建自定义NHibernate会话类的示例,但是如何使用S#arp架构来实现/扩展这一点呢

我还知道SQL Azure Federation还有其他切分选项,如NHibernate.Shards或多租户S#arp架构扩展,但请继续回答这个问题,而不是提供其他选项


我知道我不是唯一一个使用S#arp架构和SQL Azure联合会的人,谷歌也没有提供太多,如果其他人找到了解决方案,请分享。

由于没有人回复我的帖子,经过几天的研究,我正在回复。我能够用1个接口和3个类与S#harp集成(我希望它们是现成的解决方案?)

下面提供的代码可以复制并粘贴到任何应用程序,它应该可以正常工作。唯一的例外是FederationSessionHelper类。这是特定于每个应用程序的,因为您获得的信息可能会更改。我的web.config中有一个应用程序设置部分,其中包含联合体名称等。此外,当用户进行身份验证时,我解析他们提交的根url,然后查询联合体根,以确定他们是什么租户(我创建了一个自定义租户表)。然后,我将会话中的租户ID放在键“FederationKeyValue\u 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;
    }        
}
//
///用于检索有关您的联盟的特定于应用程序的信息的接口。
/// 
公共接口IFederationSessionHelper
{
字符串连接字符串{get;}
字符串FederationName{get;}
字符串分发名称{get;}
字符串FederationKeyValue{get;}
}
/// 
///这是为了让您的应用程序具有特定的内容。我在web.config文件中有3项,在会话中存储了1项。您可以轻松地对此进行更改,以便从存储库或满足应用程序需要的任何地方获取所有这些内容。
/// 
公共类FederationSessionHelper:IFederationSessionHelper
{
private const string ConnectionStringKey=“ConnectionString_Key”;
私有常量字符串FederationNameKey=“FederationName\u Key”;
私有常量字符串DistributionNameKey=“DistributionName\u Key”;
私有常量字符串FederationKeyValueKey=“FederationKeyValue\u Key”;
公共字符串ConnectionString{get{return ConfigurationManager.ConnectionString[ConnectionStringKey].ConnectionString;}
公共字符串FederationName{get{return ConfigurationManager.AppSettings[FederationNameKey];}
公共字符串DistributionName{get{return ConfigurationManager.AppSettings[DistributionNameKey];}
//当用户进行身份验证时,检索键值并存储在会话中。这将允许在此处检索。
公共字符串FederationKeyValue{get{返回会话[FederationKeyValueKey];}
}
/// 
///这是魔术的开始,也是与S#arp集成的地方。它手动创建Sql连接并将其添加到S#arps存储中。然后,它运行useffederation命令并保持连接打开。因此,现在当您使用NhibernateSession.Current时,它将与Sql Azure Federation一起工作。
/// 
公共类联合会话:IDisposable
{
私有SqlConnection SqlConnection;
public void Init(字符串factoryKey,
字符串federationName,
字符串distributionName,
字符串federationKeyValue,
布尔·多斯菲尔特,
字符串连接(字符串)
{
var sql=string.Format(“将联合体{0}({1}='{2}')与重置一起使用,筛选={3};”,联合体名称,分配名称,联合体键值,(doesFilter)?“打开”:“关闭”);
_sqlConnection=新的sqlConnection(connectionString);
_sqlConnection.Open();
var session=NHibernateSession.GetSessionFactoryFor(factoryKey).OpenSession(\u sqlConnection);
NHibernateSession.Storage.SetSessionForKey(factoryKey,会话);
var query=NHibernateSession.Current.CreateSQLQuery(sql);
query.uniquerysult();
}
公共空间处置()
{
if(_sqlConnection!=null&&u sqlConnection.State!=ConnectionState.Closed)
_sqlConnection.Close();
}
}
/// 
///这只是锦上添花。它继承自S#arps TransactionAttribute,并调用FederationSession帮助程序打开连接。这样,您就可以用新创建的[FederationTransaction]属性来装饰控制器了。
/// 
公共类FederationTransactionAttribute:TransactionAttribute
{
私有只读字符串_factoryKey=string.Empty;
private bool_doesFilter=true;
/// 
///使用时,假定为NHibernateSession.DefaultFactoryKey
/// 
公共联合会事务属性()
{ }
/// 
///使用特定的出厂密钥覆盖默认值
/// 
public Federation Transaction属性(字符串factoryKey=“”,bool doesFilter=true)
:base(factoryKey)
{
_factoryKey=factoryKey;
_doesFilter=doesFilter;
}        
公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
{
var federationSessionHelper=ServiceLocator.Current.GetInstance();
var factoryKey=GetEffectiveFactoryKey();
new FederationSession().Init(factoryKey,
federationSessionHelper.FederationNam
[HttpGet] 
[FederationTransaction]
public ActionResult Index()
{
   var viewModel = NHibernateSession.Current.QueryOver<SomeDemoModel>().List()
   return View(viewModel);            
}