将标志拆分为标准化表

时间:2015-05-08 16:42:04

标签: c# linq linq-to-entities linqpad

我有一张类似

的表格
OldThing
id  | Value    | Flags | ...
int | varchar  | int   | ...
... | ...      |   2   | ...
... | ...      |  19   | ...
... | ...      |  82   | ...
... | ...      |   3   | ...
... | ...      |  19   | ...
... | ...      |   3   | ...
... | ...      |  18   | ...
... | ...      |   3   | ...
... | ...      |  55   | ...
... | ...      |   3   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      | 112   | ...
... | ...      |   3   | ...
... | ...      |   3   | ...
... | ...      |   3   | ...
... | ...      |  48   | ...
... | ...      |  16   | ...
... | ...      |  16   | ...
... | ...      |  64   | ...
... | ...      |  -1   | ...
... | ...      |   3   | ...

其中OldThing.Flags在应用程序中检查并生成为app中定义的按位和常量值。

我尝试使用以下三个表格转移到改进的,更加规范化的数据库:

Thing
id  | Value   | ...
int | varchar |

FlagDetail        
id  | description | mask
int | varchar     | int

Flag
ThingID | FlagID 
int     | int

我尝试使用Join使用自定义IEqualityComparer生成FlagDetail表的值,但它返回的结果很少我想要的结果:

void Main()
{
    var flags = OldThings
           .ToArray()
           .Join(FlagDetails, thing=>thing.Flags.Value, 
                flag => flag.Mask, (t,f) => new {t, f}, 
                new BitwiseComparer())
           .Select (r => new Flag{ThingID = r.t.Id, FlagId = r.f.Id});

    Flags.InsertOnSubmit(flags);
    SubmitChanges();
}

// Define other methods and classes here
class BitwiseComparer : IEqualityComparer<int>
{
    public bool Equals(int a, int b)
    {
        return (a&b)>0;
    }

    public int GetHashCode(int n)
    {
        return 0;
    }
}

这导致19个结果,而预期的行数应为29(由SubscriptionTypes.Sum(st => EmailNames.Count(n => (n.Subscriptions & st.Mask)>0));计算)。

最后,我使用了两个嵌套的foreach循环:

var flags = new List<Flag>();

foreach (var thing in OldThings)
{
    foreach (var flag in FlagDetails)
    {
        if ((thing.Flag & flag.Mask) > 0)
            subs.Add(new Flag{ThingId = Thing.Id, FlagId = flag.Id});
    }
}

Flags.InsertAllOnSubmit(flags);
SubmitChanges();

这些表在多个应用程序中使用,因此迁移将逐步进行,并在我们开始时添加额外的FlagDetail行。

有没有办法在Linq中生成flags值,而无需手动编写循环?我可以在迁移每个应用程序后快速轻松地在LinqPad中输入和运行。

我目前有FlagDetail行,其掩码值为124

1 个答案:

答案 0 :(得分:2)

除非我误解,你需要做的是交叉连接而不是正常连接

像这样;

var flags = from o in OldThings.ToArray()
            from f in FlagDetails
            where (o.Flags.Value & flag.Mask) > 0
            select new Flag{ThingID = o.Id, FlagId = f.Id};

假设您在OldThings;

中有3行
  

1,&#39; blah1&#39;,1
    2,&#39; blah2&#39;,2
    3,&#39; blah3&#39;,3

FlagDetails中的第2行;

  

1,&#39; mask1&#39;,1
    2,&#39; mask2&#39;,2

您的加入会为您提供Flag;

  

1,1   2,2   3,1

我的查询你将有

  

1,1   2,2   3,1   3,2