我有以下几张表:
ImageSettingOverrides

TechniqueSettings

SettingKeyValues

来自TechniqueSettings表:
BAZ-FOO设置(SettingKeyId: 7)是对BAZ-Default (SettingKeyId: 4)设置的重写。
按覆盖值分组的查询的预期返回的示例:

我希望编译一个SettingKeyValues给定技术BAZ的列表,并覆盖FOO,该列表排除了重写的BAZ-Default设置,并包含非重写的BAZ-Default设置。
我现在有一个LINQ查询,它根据默认值/重写值对设置键值进行分组:
var techniqueSettings = _dataRepository.All<TechniqueSetting>()
.Where(s => s.Technique.Equals(TechniqueName, StringComparison.InvariantCultureIgnoreCase))
// group settings by: e.g. Default | FOO
.GroupBy(s => s.Override);从这里,我确定用户是在查询默认值,还是只查询带有重写的默认值:
var techniqueGroups = techniqueSettings.ToArray();
if (OverridesName.Equals("Default", StringComparison.InvariantCultureIgnoreCase)) {
// get the default group and return as queryable
techniqueSettings = techniqueGroups
.Where(grp => grp.Key.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
.AsQueryable();
} else {
// get the overrides group - IGrouping<string, TechniqueSetting>
var overridesGroup = techniqueGroups
.Where(grp => !grp.Key.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
.First();
var defaultGroup = techniqueGroups
.Where(grp => grp.Key.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
// we know what is in the overrides, so exlude them from being selected here
// how to exlude overridden defaults???
.First();
}此外,我情不自禁地认为必须有一个使用JOIN (可能?)的更简单、不那么笨拙的LINQ查询。
注:使用EntityFramework 6.x
__
更新:我发现似乎简化了一些Aggregate,但仍然需要一个匿名方法。
var defaultGroup = techniqueGroups
.Where(grp => grp.Key.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
.Aggregate(overridesGroup,
(overrides, defaults) => {
var settings = new List<TechniqueSetting>();
foreach (var setting in defaults) {
if (overrides.Any(o => o.SettingKey.Key == setting.SettingKey.Key)) {
continue;
}
settings.Add(setting);
}
return settings.GroupBy(s => s.Override).First();
},
setting => setting);根据@MarkoDevcic的评论,我还没有试过Join。
在这个查询中可以使用Except吗?
发布于 2014-05-01 14:41:36
我发现Aggregate似乎有点简化,但仍然需要一个匿名方法。
var defaultGroup = techniqueGroups
.Where(grp => grp.Key.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
.Aggregate(overridesGroup,
(overrides, defaults) => {
var settings = new List<TechniqueSetting>();
foreach (var setting in defaults) {
if (overrides.Any(o => o.SettingKey.Key == setting.SettingKey.Key)) {
continue;
}
settings.Add(setting);
}
return settings.GroupBy(s => s.Override).First();
},
setting => setting);更新:
我提出了几种扩展方法,允许排除项以及比较和替换:
internal static IEnumerable<TSource> Exclude<TSource>(this IEnumerable<TSource> Source, Func<TSource, bool> Selector) {
foreach (var item in Source) {
if (!Selector(item)) {
yield return item;
}
}
}
internal static IEnumerable<TResult> ReplaceWith<TSource1, TSource2, TResult>(this IEnumerable<TSource1> Source1,
Func<TSource1, TResult> Source1Result,
IEnumerable<TSource2> Source2,
Func<TSource1, IEnumerable<TSource2>, TResult> Selector) {
foreach (var item in Source1) {
var replaceWith = Selector(item, Source2);
if (replaceWith == null) {
yield return Source1Result(item);
continue;
}
yield return replaceWith;
}
}Exclude相当简单。对于ReplaceWith的使用:
var settings = _repository.Settings
.ReplaceWith(s => s.SettingKeyValue,
_repository.SettingOverrides.Where(o => o.OverrideName == overrideName),
(s, overrides) => overrides.Where(o => o.Setting == s)
.Select(o => o.SettingKeyValueOverride)
.FirstOrDefault())
.ToList();发布于 2014-05-05 19:24:28
修正后的答案
值为的
int myImageId = 1;
字符串myOverride = "FOO";
字符串myTechnique = "BAZ";
结果=
ImageId覆盖值
1 FOO 1000
值为的
int myImageId = 1;
字符串myOverride =“默认”;
字符串myTechnique = "BAZ";
结果=
ImageId覆盖值
1默认10000
void Main()
{
// Create Tables and Initialize values
// ***********************************
var techniqueSettings = new List<TechniqueSettings>();
techniqueSettings.Add(new TechniqueSettings { Id = 1, Override = "Default", SettingKeyId = 3, Technique="BAZ"});
techniqueSettings.Add(new TechniqueSettings { Id = 2, Override = "Default", SettingKeyId = 4, Technique="BAZ"});
techniqueSettings.Add(new TechniqueSettings { Id = 3, Override = "FOO", SettingKeyId = 7, Technique="BAZ"});
techniqueSettings.Add(new TechniqueSettings { Id = 4, Override = "FOO", SettingKeyId = 8, Technique="BAZ"});
var imageSettingOverrides = new List<ImageSettingOverrides>();
imageSettingOverrides.Add(new ImageSettingOverrides {SettingId = 1, ImageId=1, Override=null } );
imageSettingOverrides.Add(new ImageSettingOverrides {SettingId = 2, ImageId=1, Override="FOO" } );
imageSettingOverrides.Add(new ImageSettingOverrides {SettingId = 3, ImageId=1, Override="FOO" } );
var settingKeyValues = new List<SettingKeyValues>();
settingKeyValues.Add(new SettingKeyValues {Id = 4, Setting="Wait", Value=1000 } );
settingKeyValues.Add(new SettingKeyValues {Id = 7, Setting="Wait", Value=10000 } );
int myImageId = 1;
string myOverride = "FOO";
string myTechnique = "BAZ";
var results = from iso in imageSettingOverrides
join ts in techniqueSettings on iso.SettingId equals ts.Id
join skv in settingKeyValues on ts.SettingKeyId equals skv.Id
where iso.ImageId == myImageId &&
//iso.Override.Equals(myOverride,StringComparison.InvariantCultureIgnoreCase) &&
ts.Override.Equals(myOverride,StringComparison.InvariantCultureIgnoreCase) &&
ts.Technique.Equals(myTechnique, StringComparison.InvariantCultureIgnoreCase)
select new {
ImageId = iso.ImageId,
Override = ts.Override,
Value = skv.Value
};
results.Dump();
}
// Define other methods and classes here
public class ImageSettingOverrides
{
public int SettingId {get; set;}
public int ImageId {get; set;}
public string Override {get; set;}
}
public class TechniqueSettings
{
public int Id {get; set;}
public string Override {get; set;}
public int SettingKeyId {get; set;}
public string Technique { get; set;}
}
public class SettingKeyValues
{
public int Id {get; set;}
public String Setting {get; set;}
public int Value {get; set;}
}发布于 2014-05-08 02:59:39
我要做一些假设。
如果我了解您的类以及它们之间的关系,这将给出一个SettingKeyValues列表。因为一切都保持IQueryable,所以它应该在服务器上执行。
//I'm assuming these are your variables for each IQueryable
IQueryable<TechniqueSetting> techniqueSettings;
IQueryable<ImageSettingOverride> imageSettingOverrides;
IQueryable<SettingKeyValue> settingKeyValues;
var OverridesName = "FOO";
var TechniqueName = "BAZ";
IQueryable<TechniqueSetting> tSettings;
if (OverridesName.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
{
// Get a list of TechniqueSettings that have this name and are default
tSettings = techniqueSettings.Where(t => t.Override == OverridesName && t.Technique == TechniqueName);
}
else
{
// Get a list of TechniqueSettings Id that are overridden
// The ImageSettingOverrides have the same override
var overriddenIDs = techniqueSettings.Where(t => t.Technique == TechniqueName && t.Override == "Default")
.Join(
imageSettingOverrides.Where(
iSettingsOverrides =>
iSettingsOverrides.Override == OverridesName),
tSetting => tSetting.SettingKeyId,
iSettings => iSettings.TechniqueSettingsId,
(tSetting, iSettingsOverrides) => tSetting.Id);
// Get a list of techniqueSettings that match the override and TechniqueName but are not part of the overriden IDs
tSettings =
techniqueSettings.Where(
t =>
t.Technique == TechniqueName && !overriddenIDs.Contains(t.Id) &&
(t.Override == OverridesName || t.Override == "Default"));
}
// From expected results seems you just want techniqueSettings and that's what would be in techniqueSettings right now.
// If you want a list of SettingKeyValues (which is what is stated in the questions we just need to join them in now)
var settings = tSettings.Join(settingKeyValues, tSetting => tSetting.SettingKeyId,
sKeyValues => sKeyValues.Id, (tSetting, sKeyValues) => sKeyValues)
.Distinct();https://stackoverflow.com/questions/23395011
复制相似问题