我有Manufacturer
实体,如下所示:
class Manufacturer
{
[Key]
public int Id { get; set; }
[DisplayName("Manufacturer Code")]
public int Code { get; set; }
[DisplayName("Manufacturer Name")]
public string Name { get; set; }
}
如您所见,每个字段都有DisplayName
个数据注释。在正常方式中,我通过以下代码选择制造商表的行:
dataGridView1.DataSource = DatabaseContext.Set<Manufacturer>()
.Select(m => new
{
Id = m.Id,
Code = m.Code,
Name = m.Name,
})
.ToList();
我想找到一种方法,在Linq查询中动态地将DisplayName作为别名。
我认为我必须使用一个生成查询的方法:
dataGridView1.DataSource = DatabaseContext.Set<Manufacturer>()
.Select(m => new
{
Id = m.Id,
[Manufacturer Code] = m.Code,
[Manufacturer Name] = m.Name,
})
.ToList();
我可以通过以下代码获取所有DisplayName
:
public static Dictionary<string, string> GetEntityDisplayName(this Type type)
{
return TypeDescriptor.GetProperties(type)
.Cast<PropertyDescriptor>()
.ToDictionary(p => p.Name, p => p.DisplayName);
}
但不知道那是怎么回事。有没有办法动态地将DisplayName
作为 Linq查询的别名?
更新
作为回答之一,当使用.ToList
来获取实体中的行时,它会返回一个列表,该列表使用DisplayNameAttribute
投影模型,但是新的东西是当创建Linq查询时使用2个实体,列出项目您在查询中确切说的行。例如:
class Manufacturer
{
[Key]
public int Id { get; set; }
[DisplayName("Manufacturer Code")]
public int Code { get; set; }
[DisplayName("Manufacturer Name")]
public string Name { get; set; }
}
和
class Good
{
[Key]
[DisplayName("ID")]
public int Id { get; set; }
[DisplayName("Good Name")]
public string Name { get; set; }
public int? ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
和查询:
using (AppDbContext db = new AppDbContext())
{
var res2 = db.Goods.Select(m => new
{
Id = m.Id,
GoodsName = m.Name,
ManufacturerName = m.Manufacturer.Name,
}).ToList();
dataGridView1.DataSource = res2;
}
正如您在本案中所看到的,因为查询有2个名称字段,必须为它们声明不同的别名,而不是等于实体中的DisplayNameAttribute
。有没有人知道一种方法来将输出列表与实体中定义的DisplayNameAttribute
相同?
答案 0 :(得分:1)
在查看DataGridView
源代码后,我发现数据源绑定到一组对象,这些对象的属性为DisplayNameAttribute
,它将在列标题中显示这些属性值该财产。
因此,您只需要将LINQ查询投影到查看已定义属性的模型或实体。
例如,我有以下代码:
var listOfEntities = new List<CustomEntity>
{
new CustomEntity {Id = 1, Name = "Name1", Value = "Value1"},
new CustomEntity {Id = 2, Name = "Name2", Value = "Value2"},
new CustomEntity {Id = 3, Name = "Name3", Value = "Value3"},
new CustomEntity {Id = 4, Name = "Name4", Value = "Value4"},
};
dataGridView1.DataSource = listOfEntities;
public class CustomEntity
{
public int Id { get; set; }
[DisplayName("Custom name header")]
public string Name { get; set; }
[DisplayName("Custom name value")]
public string Value { get; set; }
}
如果您运行此列表,您会看到列标题来自DisplayNameAttribute
,而不是属性名称。
要投影以查看模型,您可以使用AutoMapper自动映射字段。
<强>更新强>
您可以使用Expando
对象实现此行为。
让我警告你,虽然在你的上下文中调用.ToList()
之前你不能使用它。因为默认情况下这不会转换为有效的SQL查询。
using System.Reflection;
/*...*/
public static object ToDynamicDisplayName(object input)
{
var type = input.GetType();
dynamic dObject = new ExpandoObject();
var dDict = (IDictionary<string, object>)dObject;
foreach (var p in type.GetProperties())
{
var prop = type.GetProperty(p.Name);
var displayNameAttr = p.GetCustomAttribute<DisplayNameAttribute>(false);
if (prop == null || prop.GetIndexParameters().Length != 0) continue;
if (displayNameAttr != null)
{
dDict[displayNameAttr.DisplayName] = prop.GetValue(input, null);
}
else
dDict[p.Name] = prop.GetValue(input, null);
}
return dObject;
}
要使用它,请尝试这样:
var myDynamicCollection = DatabaseContext.Set<Manufacturer>().ToList().Select(m =>
ToDynamicDisplayName(m));
更新2
当然我运行了代码并成功构建。我的设置是VS2017与.NET 4.6.2。但是,我也为它创建了一个.Net小提琴,它可用here。