【问题标题】:Mapping a code table in BLToolkit在 BLToolkit 中映射代码表
【发布时间】:2025-11-23 10:25:01
【问题描述】:

在我的数据库中,有一个大型“代码”表,其中包含系统代码查找,用于查找整个系统中使用的值。像这样:

[TableName("code_entries")]                         public class Code {
    [MapField("code_nbr")][PrimaryKey, Identity]    public int Id;
    [MapField("code")]                              public string Value;
}

我是 BLToolkit 的新手,我希望有一个类似于我见过的静态映射的概念,但这将使我能够轻松地将其他表中这些代码的出现映射到它们各自的值。例如:

    [TableName("person")]                               public class Person {
        [MapField("person_nbr")][PrimaryKey, Identity]  public int Id;
        [MapField("dob")][Nullable]                     public int BirthDate;
        [MapField("eye_color")][Nullable]               public int EyeColorCode;
        [MapField("hair_color")][Nullable]              public int HairColorCode;    
}

如果上面的 EyeColorCode 和 HairColorCode 映射到 Codes 表中的值,我是否可以创建一种简单的方法来映射 OR 类中的数据并在单个查询中获取整个对象?

我希望得到类似的结果:

// person.Id = 1
// person.DOB = some date
// person.EyeColor = "Blue"
// person.HairColor = "Brown"

【问题讨论】:

    标签: .net linq orm bltoolkit


    【解决方案1】:

    谢谢大卫。我采用了您的方法,但稍作修改,以减轻对我的痛苦。如您的示例所示,我在类中添加了关联:

    [Association(ThisKey = "EyeColorCode", OtherKey = "Id")]    public Code EyeColor { get; set; }
    [Association(ThisKey = "HairColorCode", OtherKey = "Id")]   public Code HairColor { get; set; }
    

    然后我写了一个扩展方法。它接受一个新对象,并将所有可写属性合并到源对象中。使用它,我不需要在查询中指定每个属性,即:

    from p in db.Person
    select p.PropertyUnion(new Person() {
    {
        EyeColor  = p.EyeColor,
        HairColor = p.HairColor
    };
    

    这为我的一些更复杂的对象节省了相当多的代码,而且我认为它更具可读性。下面是扩展方法的代码:

    /// <summary>
    /// Union by retrieving all non-null properties from source parameter and setting those properties on the instance object
    /// </summary>
    public static T PropertyUnion<T>(this T destination, T source) {
        // Don't copy from a null object
        if (Object.ReferenceEquals(source, null) || Object.ReferenceEquals(destination, null)) {
            return destination;
        }
        // copy properties
        foreach (var property in source.GetType().GetProperties()) {
            if (!property.CanWrite || !property.CanRead)
                continue;
            var match = destination.GetType().GetProperty(property.Name);
            if (!match.CanWrite || !match.CanRead)
                throw new MethodAccessException("Matching property '" + match.Name + "' must allow both read and write operations.");
            var value = property.GetValue(source, null);
            if (value != null && !value.Equals(Activator.CreateInstance(property.PropertyType)))
                match.SetValue(destination, value, null);
        }
        return destination;
    }
    

    再次感谢您的帮助!

    【讨论】:

      【解决方案2】:

      这不是您真正想要的,但您可以使用 Associations

      这样您就可以将其添加到您的 Person 类中

      [Association(ThisKey="eye_color", OtherKey="code_nbr", CanBeNull=true)]
      public Code EyeColor;
      
      [Association(ThisKey="hair_color", OtherKey="code_nbr", CanBeNull=true)]
      public Code HairColor;
      

      然后做类似的事情

      from p in db.Person
      select new
      {
          Id        = p.Id,
          DOB       = p.BirthDate,
          EyeColor  = p.EyeColor.Value,
          HairColor = p.HairColor.Value
      };
      

      无论如何,这些似乎是几乎永远不会改变的代码类型 我通常在启动时将这些放在客户端上,然后在显示数据时填写描述,使一切变得容易得多,如果找不到 Id,我就 刷新集合

      【讨论】:

      • 我们有一些这样的代码,它们的变化足以在数据中做到这一点。这是我正在走向的道路,但问题在于它迫使我在新对象(您的示例中的 Id 和 DOB)中重新指定所有其他列,并阻止我使用生成的数据库类(Person ) 而不重建它。这些代码值在我们的许多表中都使用了,所以我根本无法使用生成的类。