Невозможно установить / получить SQL session_context в .NET C #

У меня была такая же проблема, и я придумал решение. Я нашел этот вопрос после того, как решил его, и вижу, что мое решение имеет много общего с Марком. Однако этот подход немного отличается.

Основная проблема заключается в том, что поведение и триггеры ассоциируются с определенным объектом, поэтому вы не можете использовать один и тот же экземпляр поведения для нескольких разных связанных объектов. Когда вы определяете свое поведение, встроенный XAML обеспечивает это взаимно-однозначное отношение. Однако, когда вы пытаетесь установить поведение в стиле, стиль может быть повторно использован для всех объектов, к которым он применяется, и это будет генерировать исключения в базовых классах поведения. На самом деле авторы приложили немало усилий, чтобы помешать нам даже попытаться это сделать, зная, что это не сработает.

Первая проблема заключается в том, что мы даже не можем построить значение setterter, потому что конструктор внутренний. Поэтому нам нужно собственное поведение и триггерные классы.

Следующая проблема заключается в том, что свойства поведения и триггера не имеют сеттеров, поэтому их можно добавить только с помощью встроенного XAML. Эта проблема мы решаем с помощью наших собственных подключенных свойств, которые управляют первичным поведением и свойствами запуска.

Третья проблема заключается в том, что наша коллекция поведения хороша только для единственной цели стиля. Это мы решаем, используя малоиспользуемую функцию XAML x:Shared="False", которая создает новую копию ресурса каждый раз, когда на нее ссылаются.

Конечная проблема заключается в том, что поведение и триггеры не похожи на другие стилисты; мы не хотим заменять старые поведения новым поведением, потому что они могут делать дико разные вещи. Поэтому, если мы согласны с тем, что после добавления поведения вы не можете его убрать (и в настоящее время это поведение поведения), мы можем заключить, что поведение и триггеры должны быть аддитивными, и это может быть обработано нашими приложенными свойствами.

Вот пример с использованием этого подхода:

<Grid>
    <Grid.Resources>
        <sys:String x:Key="stringResource1">stringResource1</sys:String>
        <local:Triggers x:Key="debugTriggers" x:Shared="False">
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <local:DebugAction Message="DataContext: {0}" MessageParameter="{Binding}"/>
                <local:DebugAction Message="ElementName: {0}" MessageParameter="{Binding Text, ElementName=textBlock2}"/>
                <local:DebugAction Message="Mentor: {0}" MessageParameter="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}}"/>
            </i:EventTrigger>
        </local:Triggers>
        <Style x:Key="debugBehavior" TargetType="FrameworkElement">
            <Setter Property="local:SupplementaryInteraction.Triggers" Value="{StaticResource debugTriggers}"/>
        </Style>
    </Grid.Resources>
    <StackPanel DataContext="{StaticResource stringResource1}">
        <TextBlock Name="textBlock1" Text="textBlock1" Style="{StaticResource debugBehavior}"/>
        <TextBlock Name="textBlock2" Text="textBlock2" Style="{StaticResource debugBehavior}"/>
        <TextBlock Name="textBlock3" Text="textBlock3" Style="{StaticResource debugBehavior}"/>
    </StackPanel>
</Grid>

В примере используются триггеры, но поведение работает одинаково. В этом примере мы показываем:

  • стиль может применяться к нескольким текстовым блокам
  • несколько типов привязки данных, которые все работают правильно
  • отладка действие, которое генерирует текст в окне вывода

Вот пример поведения, наш DebugAction. Более корректно это действие, но из-за злоупотребления языком мы называем поведение, триггеры и действия «поведения».

public class DebugAction : TriggerAction<DependencyObject>
{
    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public static readonly DependencyProperty MessageProperty =
        DependencyProperty.Register("Message", typeof(string), typeof(DebugAction), new UIPropertyMetadata(""));

    public object MessageParameter
    {
        get { return (object)GetValue(MessageParameterProperty); }
        set { SetValue(MessageParameterProperty, value); }
    }

    public static readonly DependencyProperty MessageParameterProperty =
        DependencyProperty.Register("MessageParameter", typeof(object), typeof(DebugAction), new UIPropertyMetadata(null));

    protected override void Invoke(object parameter)
    {
        Debug.WriteLine(Message, MessageParameter, AssociatedObject, parameter);
    }
}

Наконец, наши коллекции и прикрепленные свойства, чтобы все это работало. По аналогии с Interaction.Behaviors целевое свойство называется SupplementaryInteraction.Behaviors, потому что, установив это свойство, вы добавите поведения к Interaction.Behaviors и аналогичным образом для триггеров.

public class Behaviors : List<Behavior>
{
}

public class Triggers : List<TriggerBase>
{
}

public static class SupplementaryInteraction
{
    public static Behaviors GetBehaviors(DependencyObject obj)
    {
        return (Behaviors)obj.GetValue(BehaviorsProperty);
    }

    public static void SetBehaviors(DependencyObject obj, Behaviors value)
    {
        obj.SetValue(BehaviorsProperty, value);
    }

    public static readonly DependencyProperty BehaviorsProperty =
        DependencyProperty.RegisterAttached("Behaviors", typeof(Behaviors), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyBehaviorsChanged));

    private static void OnPropertyBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behaviors = Interaction.GetBehaviors(d);
        foreach (var behavior in e.NewValue as Behaviors) behaviors.Add(behavior);
    }

    public static Triggers GetTriggers(DependencyObject obj)
    {
        return (Triggers)obj.GetValue(TriggersProperty);
    }

    public static void SetTriggers(DependencyObject obj, Triggers value)
    {
        obj.SetValue(TriggersProperty, value);
    }

    public static readonly DependencyProperty TriggersProperty =
        DependencyProperty.RegisterAttached("Triggers", typeof(Triggers), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyTriggersChanged));

    private static void OnPropertyTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var triggers = Interaction.GetTriggers(d);
        foreach (var trigger in e.NewValue as Triggers) triggers.Add(trigger);
    }
}

и там у вас есть , полнофункциональное поведение и триггеры, применяемые через стили.

0
задан Cyril Durand 11 March 2019 в 13:54
поделиться

1 ответ

Вы используете метод SPSDatabaseInfo.ExecuteScalar, отправляющий строку соединения вместо открытого SQLConnection, этот метод внутренне создает / открывает / закрывает свое собственное соединение.

Это означает, что ваши звонки выполняются в разных сеансах.

Используйте эту перегрузку метода ExecuteScalar, используя одно и то же соединение для обоих запросов

public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText)
{
    //pass through the call providing null for the set of SqlParameters
    return ExecuteScalar(connection, commandType, commandText, (SqlParameter[])null);
}

таким образом

using (SqlConnection cn = new SqlConnection(_connString))
{
    cn.Open();
    String.Format("EXEC sp_set_session_context N'TENANTID', '{0}'", tenantId); 
    SPSDatabaseInfo.ExecuteScalar(cn, CommandType.Text, sql);

    sql = "select SESSION_CONTEXT(N'TENANTID') AS SESSION_ID"; 
    var retVal = SPSDatabaseInfo.ExecuteScalar(cn, CommandType.Text, sql);
}
0
ответ дан Daniel Brughera 11 March 2019 в 13:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: