Метод 'Boolean Contains (System.DayOfWeek)' не поддерживает перевод на SQL - PullRequest
0 голосов
/ 18 января 2012

В моем приложении Windows Phone Mango у меня есть несколько флажков, каждый из которых соответствует дню недели. Я хочу отфильтровать запрашиваемые данные, по которым установлены флажки. Вот то, что я придумал, но я чувствую, что есть лучшее решение:

Объявите флажки в XAML:

            <CheckBox Content="Mon" x:Name="MonCheckbox" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap"/>
            <CheckBox Content="Tue" x:Name="TueCheckbox" Grid.Column="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
            <CheckBox Content="Wed" x:Name="WedCheckbox" Grid.Column="2" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
            <CheckBox Content="Thur" x:Name="ThurCheckbox"  Grid.Row="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
            <CheckBox Content="Fri" x:Name="FriCheckbox" Grid.Row="1" Grid.Column="1" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
            <CheckBox Content="Sat" x:Name="SatCheckbox" Grid.Row="1" Grid.Column="2" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />
            <CheckBox Content="Sun" x:Name="SunCheckbox" Grid.Row="2" Grid.Column="0" Checked="DayCheckbox_Tap" Unchecked="DayCheckbox_Tap" />

Свяжите день с каждым флажком:

    public MainPage()
    {
        InitializeComponent();

        LayoutRoot.DataContext = this;

        // This is grossly imperative. Can it be done in XAML?
        MonCheckbox.Tag = DayOfWeek.Monday;
        TueCheckbox.Tag = DayOfWeek.Tuesday;
        WedCheckbox.Tag = DayOfWeek.Wednesday;
        ThurCheckbox.Tag = DayOfWeek.Thursday;
        FriCheckbox.Tag = DayOfWeek.Friday;
        SatCheckbox.Tag = DayOfWeek.Saturday;
        SunCheckbox.Tag = DayOfWeek.Sunday;

        // ...
    }

Ведение коллекции текущих выбранных дней:

    ICollection<DayOfWeek> _selectedDays = new Collection<DayOfWeek>();

    private void DayCheckbox_Tap(object sender, RoutedEventArgs e)
    {
        CheckBox checkbox = (CheckBox)sender;
        if (_selectedDays.Contains((DayOfWeek)checkbox.Tag))
        {
            _selectedDays.Remove((DayOfWeek)checkbox.Tag);
        }
        else
        {
            _selectedDays.Add((DayOfWeek)checkbox.Tag);
        }

        refreshCheckinData();
    }

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

    private void refreshCheckinData()
    {
        Checkins.Clear();
        Checkins.AddAll(from checkin in checkinData.Items
                        where _selectedDays.Contains(checkin.DateTime.DayOfWeek)
                        select checkin);
    }

public static class ExtensionMethods
{
    public static void AddAll<T>(this ICollection<T> dest, IEnumerable<T> source)
    {
        if (dest == null)
        {
            throw new ArgumentNullException("dest");
        }

        foreach (T t in source)
        {
            dest.Add(t);
        }
    }
}

Когда код пытается перебрать source в AddAll(), возникает следующее исключение:

Method 'Boolean Contains(System.DayOfWeek)' has no supported translation to SQL."   System.Exception {System.NotSupportedException}

Как я могу обойти это? Почему Contains требует перевода SQL? Есть ли лучший подход ко всему этому, используя более декларативный XAML и менее обязательный код-позади?

Обновление: Я попытался изменить запрос на:

where _selectedDays.Any(day => day == checkin.DateTime.DayOfWeek)

теперь я получаю следующую ошибку:

"Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator." System.Exception {System.NotSupportedException}

_selectedDays определяется в памяти. почему его нужно перевести на SQL?

Ответы [ 2 ]

0 голосов
/ 21 января 2012

Ваш оригинальный запрос близок.Я думаю, что метод Contains () в ICollection мешает транслятору SQL - мне нужно было бы дважды проверить код, чтобы быть уверенным.

Вы можете обойти эту проблему, принудительно выбрав метод расширения Enumerable.Contains (), изменив свой код следующим образом:

    private void refreshCheckinData()
{
    Checkins.Clear();
    Checkins.AddAll(from checkin in checkinData.Items
                    where _selectedDays.AsEnumerable().Contains(checkin.DateTime.DayOfWeek)
                    select checkin);
}

Метод расширения Enumerable.Contains (T) переведет впредложение IN в базе данных.

Полученный запрос будет выглядеть примерно так: SELECT [t0]. [Key], [t0]. [Day] FROM [Stuff] AS [t0] WHERE [t0]. [Day] IN (@ p0, @ p1)

0 голосов
/ 19 января 2012

Если я правильно понимаю, вы захотите добавить все выбранные дни в свои «проверки», так почему бы вам не попробовать этот код, я думаю, что это решит вашу проблему на данный момент и ответит на другие вопросы, о которых мне нужно подуматьони немного исследования.:)

foreach(var day in _selectedDays)
{
 Checkins.AddAll(from checkin in checkinData.Items
                    where checkin.DateTime.DayOfWeek == day
                    select checkin);
}

Должен был бы проверить это, я не знаю, работает ли он или нет, или если он даже действителен.

from checkin in checkinData.Items
join sdays in _selectedDays on checkin.DateTime.DayOfWeek == sdays
select checkin
...