将标志拆分为规范化表

3

我有一张表格,看起来像这样:

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

我正在尝试迁移到一个更加规范化的改进数据库,其中包括以下三个表:

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

FlagDetail        
id  | description | mask
int | varchar     | int

Flag
ThingID | FlagID 
int     | int

我尝试使用自定义的IEqualityComparerJoin生成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 中输入并运行的东西,同时还要迁移每个应用程序。
我目前有 Mask 值为 124FlagDetail 行。

我不确定我是否理解你的意思,但是... 你想将 OldThingsFlagDetails 进行连接吗?我说得对吗?你尝试过什么? - Maciej Los
我正在尝试使用FlagDetail.Mask的值生成Flag表的行,因此当(OldThing.Flags&FlagDetail.Mask)> 0时生成Flag行。我只是想知道是否有一种我忽略了的用Linq实现这个功能的方法。 - RoadieRich
@MaciejLos 编辑以包括之前的尝试。 - RoadieRich
你能给我们提供OldThings标志列内容和新的flag-mask列内容吗?无需ID或文本。 - Fredou
@Fredou 问题已编辑以包含。 - RoadieRich
1个回答

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};

假设你有3个旧物品(OldThings)的行;
1、'blah1',1 2、'blah2',2 3、'blah3',3
还有2个标志细节(FlagDetails)的行:
1、'mask1',1 2、'mask2',2
使用join后,你将得到这个结果,即Flag:
1、1 2、2 3、1
使用我的查询语句,你将得到:
1、1 2、2 3、1 3、2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接