Объединение таблиц Linq-to-SQL - PullRequest
1 голос
/ 15 апреля 2009

Допустим, у меня есть три таблицы:

Пользователь

ID | Name
===========
 1 | UserA
-----------
 2 | UserB
-----------

Настройка

ID | Name     | Default
=========================
 1 | SettingA | ADefault
-------------------------
 2 | SettingB | BDefault
-------------------------

И

UserSetting

UserID | SettingID | Value
================================
 1     |  1        | Alice
--------------------------------
 1     |  2        | Bob
--------------------------------
 2     |  1        | AOverride
--------------------------------

Когда я создаю свой dbml-файл, он соответствующим образом связывает пользователя с UserSetting и UserSetting с Setting на основе внешних ключей, установленных в базе данных.

Что меня интересует, так это то, можно ли объединиться обратно из UserSetting в таблицу Setting, если пользователь специально не переопределил значение таким способом, который имеет смысл.

В частности, я ищу следующий псевдокод:

var user = MyDataContext.Users.SingleOrDefault(u => u.ID == 2);

foreach(var setting in user.UserSettings)
{
  Console.Writeline(setting.ID + "|" + setting.Value);
}

Чтобы вывести что-то вроде этого:

 1 | AOverride
 2 | BDefault

Без изменений user.UserSettings будет содержать только значения, которые были специально переопределены, поэтому он будет только возвращать:

 1 | AOverride

Есть идеи? Или кто-то с большим количеством представителей, пожалуйста, помогите мне перефразировать это, так как это, вероятно, не совсем понятно? :)

Ответы [ 2 ]

3 голосов
/ 15 апреля 2009

Я хотел бы, чтобы Linq-to-SQL был довольно приглушенным, и добавлял какие-то причудливые требования к моим частичным классам, вот решение, которое я использовал.

Я добавил следующий помощник в свой класс User (основываясь на ответе Хосе, но исправил так, что он работает):

public IEnumerable<SettingValue> GetSettingsWithDefaults( IEnumerable<Setting> settings )
{
    return from s in settings
           join us in this.UserSettings
             on s.ID equals us.SettingID into userSettings
           from us in userSettings.DefaultIfEmpty()
           select new SettingValue
                  {
                      Setting = s,
                      Value = ( us == null ) ? s.Default : us.Value,
                      IsDefault = ( us == null )
                  };
}

Требуется новый класс:

public class SettingValue
{
    public Setting Setting { get; set; }
    public string Value { get; set; }
    public bool IsDefault { get; set; }
}

Тогда я мог бы сделать следующее:

foreach( var userSetting in user.GetSettingsWithDefaults( settings ) )
{
    Debug.WriteLine( string.Format( "Name:{0}, Value:{1}, IsDefault:{2}", 
        userSetting.Setting.Name,
        userSetting.Value,
        userSetting.IsDefault 
    ) );
}

Который дал мне следующий вывод

Name:SettingA, Value:OverrideA, IsDefault:False
Name:SettingB, Value:DefaultB, IsDefault:True
0 голосов
/ 15 апреля 2009

Вы можете создать представление, которое объединяет UserSetting and Setting, которое представляет все настройки для каждого пользователя. Затем используйте представление в вашем файле DBML в дополнение (или вместо) к ассоциации UserSettings (вместо того, чтобы работать, если только вы не хотите иметь возможность добавлять новые настройки, в этом случае вы можете захотеть, чтобы ассоциация UserSettings также присутствовала).

У меня нет удобного сервера SQL, но вид, вероятно, будет выглядеть примерно так:

SELECT
    User.ID AS UserID,
    Setting.ID AS SettingID,
    COALESCE(UserSetting.Value, Setting.Default) AS Value,
    CASE WHEN UserSetting.UserID IS NOT NULL THEN CAST(0 AS BIT)
        ELSE CAST(1 AS BIT) END AS IsDefault
FROM User
    CROSS JOIN Setting
    LEFT JOIN UserSetting ON Setting.ID = UserSetting.SettingID
        AND UserSetting.UserID = User.ID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...