将标志拆分为标准化 Table

Split Flags into Normalized Table

我有一个 table 看起来像

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 在应用程序中被检查并生成为按位和应用程序中定义的常量值。

我正在尝试使用以下三个 tables:

改进、更规范化的数据库
Thing
id  | Value   | ...
int | varchar |

FlagDetail        
id  | description | mask
int | varchar     | int

Flag
ThingID | FlagID 
int     | int

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

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();

这些 table 在多个应用程序中使用,因此迁移将逐步添加额外的 FlagDetail 行。

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

我目前有 FlagDetail 行掩码值为 124

除非我误解了,你需要做的是交叉连接而不是普通连接

像这样;

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, 'blah1', 1
2, 'blah2', 2
3, 'blah3', 3

FlagDetails 中的 2 行;

1, 'mask1', 1
2, 'mask2', 2

你的加入会给你这个,Flag;

1, 1
2, 2
3, 1

通过我的查询,您将得到

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