循环访问通过域模型上的 linq 查询返回的对象的属性和值
本文关键字:返回 查询 对象 属性 linq 循环 模型 访问 | 更新日期: 2023-09-27 18:28:00
我在关系数据库中有一个自定义实体,我已通过域模型将其映射到 CLR。因此,通过使用以下语句,我可以通过域模型上的 LINQ 查询将实体从数据库拉入内存中,如下所示;
var inspection = (from i in dbContext.New_testinspectionExtensionBases
where i.New_testinspectionId == currentInspection
select i).First();
我需要访问此实体上的属性/字段,我需要能够确定属性/字段名称及其值。我想在内存中循环访问这些项目,并将其名称和值写出到控制台。
我尝试使用这种方法,但无法弄清楚如何更正语法(我也不确定 GetProperties 是正确的使用方法,GetFields 由于某种原因没有返回任何内容,所以我认为这是要走的路(但这并不重要,因为我所需要的只是对值的读取访问权限;
var inspectionReportFields = inspection.GetType().GetProperties();
// I called this inspectionReportfields because the entity properties correspond to
// form/report fields I'm generating from this data.
foreach (var reportField in inspectionReportFields)
{
var value = reportField.GetValue();
Console.WriteLine(reportField.Name);
Console.WriteLine(value);
}
在使用 EF 或 openaccess 等域模型时,是否有更简单的方法来获取属性/字段值?如果没有,我的做法是否正确?最后,如果是这样,如何修复值变量声明中的语法?
下面是域模型生成的代码中的一些示例字段/属性,以供参考;
private int? _new_systemGauges;
public virtual int? New_systemGauges
{
get
{
return this._new_systemGauges;
}
set
{
this._new_systemGauges = value;
}
}
private int? _new_systemAlarm ;
public virtual int? New_systemAlarm
{
get
{
return this._new_systemAlarm;
}
set
{
this._new_systemAlarm = value;
}
}
我假设您正在尝试定义一种通用方法来"转储"对象,而无需了解其结构。如果是这样,那么你正在以正确的方式做事。使用反射(GetType()
和关联的Type
类方法(来检查对象并返回其信息。
GetFields()
没有返回任何内容的原因是您可能没有提供正确的绑定标志。特别是,如果您调用不带任何参数的重载,则只会返回public
字段;如果你想要私人字段,你需要特别要求它们。
在您的情况下,GetFields(BindingFlags.NonPublic)
会返回_new_systemGauges
和_new_systemAlarm
字段,而 GetProperties(( 会返回New_systemAlarm
和New_systemAlarm
属性。
遗漏的另一个关键元素是你返回的数据是元数据类型;它定义了class
的结构,而不是任何特定的实例。如果你想知道特定实例的属性值是多少,你需要问:
foreach (var prop in obj.GetType().GetProperties())
{
Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj, null));
}
如果您拥有类型元数据中的PropertyInfo
元素之一,则可以在该类型的任何实例上请求该属性值。它不必与您最初使用的实例相同。例如:
var objs = somelist.Where(x => x.Id == 1);
foreach (var prop in objs.First().GetType().GetProperties())
{
int x = 0;
foreach (var obj in objs)
{
if (prop.PropertyType.Name.Equals("Int32"))
{
int val = (int)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = 0x{2:x8}", x++, prop.Name, val);
}
else if (prop.PropertyType.Name.Equals("Decimal"))
{
int val = (decimal)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = {2:c2}", x++, prop.Name, val);
}
else
{
Console.WriteLine("Obj #{0}: {1} = '{2}'", x++, prop.Name, prop.GetValue(obj, null));
}
}
}
从技术上讲,您应该检查GetIndexParameters
的结果以查看属性是否已被索引;要GetValue
的null
参数实际上是一个索引值数组。
若要转换返回的值,可以使用类型转换,或者如果要更灵活一点,请使用 Convert 类的方法。区别在于,例如,如果您有一个 short
属性,GetValue()
将返回一个带框的短整型,然后您不能将其类型转换为 int
;您必须先将其拆箱到short
。使用 Convert.ToInt32()
将执行所有必需的步骤,从可转换为整数的任何属性中获取int
值。
在引用类型之间进行转换更容易,因为您可以只使用is
和as
;这些工作就像您对"反映"属性值的预期一样。
GetProperties
确实是正确的方法。
要摆脱编译器错误,请将代码更改为以下内容:
var value = reportField.GetValue(inspection, null);
您需要传递要从中获取值的实例,因为PropertyInfo
对象未绑定到任何特定的类实例。
请考虑遵循标准的 .NET 命名规则。
这将导致以下结果:
NewSystemAlarm
而不是New_systemAlarm
newSystemAlarm
或_newSystemAlarm
而不是_new_systemAlarm
NewTestInspectionExtensionBases
而不是New_testinspectionExtensionBases
NewTestInspectionId
而不是New_testinspectionId
如果您使用的是 OpenAccess,您始终可以获得有关模型类的完整信息。那里的信息是从映射中检索的,这意味着您无需反映类(无开销(。
只需浏览低谷上下文。Metadata.PersistentType 用于所有类映射信息。