2009-04-14 3 views
1

Скажем, у меня есть три таблицы:Linq к SQL Таблица Coalesce

пользователя

 
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 

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

ответ

3

мне нравится держать Linq к 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

Это сработало отлично. Я сделал небольшую корректировку, которую, как мне показалось, помог.Вместо того, чтобы устанавливать IsDefault в запросе linq, get в SettingValue просто возвращает (Setting.Default == Value). – jerhinesmith

-1

Вы можете создать представление, объединяющее UserSetting и 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 
Смежные вопросы