【问题标题】:Linq-to-SQL Table CoalesceLinq-to-SQL 表合并
【发布时间】:2009-04-14 20:34:09
【问题描述】:

假设我有三个表:

用户

身份证 |姓名 =========== 1 |用户A ------------ 2 |用户B ------------

设置

身份证 |姓名 |默认 ========================== 1 |设置A | A默认 ------------------------- 2 |设置B | B默认 -------------------------

用户设置

用户名 |设置ID |价值 ================================= 1 | 1 |爱丽丝 -------------------------------- 1 | 2 |鲍勃 -------------------------------- 2 | 1 | A覆盖 --------------------------------

当我创建我的 dbml 文件时,它会根据数据库中设置的外键将用户适当地链接到 UserSettingUserSettingSetting

我想知道的是,如果用户没有以有意义的方式明确覆盖该值,是否有可能从 UserSetting 合并回 Setting 表。

具体来说,我正在寻找以下伪代码:

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

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

要输出如下内容:

1 | A覆盖 2 | B默认

如果不修改,user.UserSettings 将只包含被明确覆盖的值,所以它只会返回:

1 | A覆盖

有什么想法吗?或者有更多代表的人可以帮我改一下,因为它可能并不完全清楚? :)

【问题讨论】:

    标签: c# linq-to-sql


    【解决方案1】:

    我喜欢让 Linq-to-SQL 相当笨拙,并向我的部分类添加任何花哨的要求,以下是我使用的解决方案。

    我在我的 User 类中添加了以下帮助程序(基于 Jose 的回答,但已修复,因此可以正常工作):

    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
    

    【讨论】:

    • 这非常有效。我做了一个我认为有帮助的小调整。而不是在 linq 查询中设置 IsDefault,在 SettingValue 中的 get 只是返回 (Setting.Default == Value)。
    【解决方案2】:

    您可以创建一个视图,将 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多