使用 EF4 读取引用实体的 PropertyInfo 的值
我想动态读取在循环父实体的 PropertyInfo 时遇到的 EntityObjects 的 PropertyInfo 值(连接到当前 Image 实例的 ImageType 实例的列值,fi)。
主要实体的类型仅在运行时已知,因此我正在寻找一种读取任何引用实体对象的 PropertyInfo 值的通用方法。
我可以循环访问子实体的 PropertyInfos,但是当我尝试获取值时,我得到一个 TargetException:对象与目标类型不匹配。
// loop through the main entity's properties
foreach (PropertyInfo pi in entityType.GetProperties())
{
// if the main entity's property is an entity
if (pi.PropertyType.BaseType == typeof(System.Data.Objects.DataClasses.EntityObject))
{
// loop through the sub entity's properties
foreach(PropertyInfo mychildren in pi.PropertyType.GetProperties())
{
// the loop works fine but when i try to get a value I get a
// TargetException: Object does not match target type.
object test = mychildren.GetValue(pi, null);
}
}
}
我该怎么做?
编辑:
Entity Framework 4.0 似乎不允许您动态检索实体的相关实体的实例。但在 EF 4.1 及更高版本中,您可以通过使用类名作为字符串标识符来实现。所以我升级到 EF 4.2 并让它正常工作。
我想要这段代码的原因是在我的 DTO 翻译例程中使用它。我的 DTO 可以具有与相关实体的名称属性相对应的字符串属性,这样我就可以访问这些属性,而无需对相关实体的类型进行硬编码。
在 EF 4.1 及更高版本中,ObjectContext 由名为 DbContext 的类包装,该类提供导航属性,用于使用字符串获取相关实体的实例。要动态检索单个相关实体,您可以使用:
dynamic refObject = Activator.CreateInstance(refObjectType);
refObject = context.Entry(currentObject).Reference(refObjectType.Name).CurrentValue;
对于从 4.0 升级的用户:使用 DbContext 的推荐方法不是使用 EntityObject,而是使用 POCO。这些可以手动制作,也可以通过 edmx 上下文菜单生成。
我当前的实现如下:
// Loop through the propertyinfos of the dto's type
foreach (PropertyInfo pf in dtoType.GetProperties().Where(p => p.CanWrite))
{
// Use the name of the dto property to get the corresponding property from the POCO's type. If it doesn't exist, pi will be null
PropertyInfo pi = pocoType.GetProperty(pf.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (pi != null)
{
// Check if the current propertyinfo of the POCO has a subproperty named Id
// If this is the case we treat the propertyinfo as a referenced POCO
if (pi.PropertyType.GetProperty("Id") != null)
{
// skip referenced POCOs if their data is not needed
if (!includeRelated) continue;
// Get the type of the referenced POCO
Type refObjectType = pi.PropertyType;
// Create an instance of the referenced POCO
dynamic refObject = Activator.CreateInstance(refObjectType);
// Create a type of GenericRepository<objectType>
Type refObjectRepositoryType = typeof(GenericRepository<>).MakeGenericType(refObjectType);
// Create an instance of GenericRepository<objectType>
dynamic refObjectRepository = Activator.CreateInstance(refObjectRepositoryType);
// Fill the dynamic POCO instance with the values of the referenced POCO instance
refObject = refObjectRepository._context.Entry(poco).Reference(refObjectType.Name).CurrentValue;
try
{
// Set the dto property with the name value of the referenced POCO instance
// (i.e. dtoImage.ImageType = pocImage.ImageType.Name)
pf.SetValue(dto, refObject.Name, null);
}
catch (RuntimeBinderException)
{
// this happens when the related entity is null, ie. in one to zero-or-one relationships
continue;
}
continue;
}
// If the propertyinfo's propertytype does not have an Id property, just set the value of
// the dto property to that of the POCO's propertyinfo directly
pf.SetValue(dto, pi.GetValue(poco, null), null);
}
}
目前,此代码仅适用于同时具有 Id 和 Name 属性的引用实体。此外,这种方法可能会降低性能,因此我实现了标志 includeRelated 来切换是否查询相关对象。
I would like to dynamically read the values of the PropertyInfos of EntityObjects that I come across when looping through the PropertyInfos of a parent entity (the column values of the instance of ImageType that is connected to the current instance of Image, f.i.).
The main entity's type is only known at runtime, so I'm looking for a generic way of reading the PropertyInfo values of any referenced entity object.
I can loop through the PropertyInfos of the sub entity, but when I try to get a value I get a TargetException: Object does not match target type.
// loop through the main entity's properties
foreach (PropertyInfo pi in entityType.GetProperties())
{
// if the main entity's property is an entity
if (pi.PropertyType.BaseType == typeof(System.Data.Objects.DataClasses.EntityObject))
{
// loop through the sub entity's properties
foreach(PropertyInfo mychildren in pi.PropertyType.GetProperties())
{
// the loop works fine but when i try to get a value I get a
// TargetException: Object does not match target type.
object test = mychildren.GetValue(pi, null);
}
}
}
How can I do this?
Edit:
Entity Framework 4.0 doesn't seem to allow you to dynamically retrieve the instances of an entity's related entities. But with EF 4.1 and up you can, by using their class name as a string identifier. So I upgraded to EF 4.2 and got it working.
The reason I wanted this code is to use it in my DTO translation routine. My DTO's can have string properties that correspond to the name properties of related entities and this way I can access those without having to hard code the related entities' types.
In EF 4.1 and up, the ObjectContext is wrapped by a class named DbContext, which provides navigational properties with which to get instances of related entities using strings. To dynamically retrieve a singular related entity, you can use:
dynamic refObject = Activator.CreateInstance(refObjectType);
refObject = context.Entry(currentObject).Reference(refObjectType.Name).CurrentValue;
For those upgrading from 4.0: The recommended way to work with DbContext is not with EntityObjects but with POCOs. These can be made manually or they can be generated via the edmx context menu.
My current implementation is as follows:
// Loop through the propertyinfos of the dto's type
foreach (PropertyInfo pf in dtoType.GetProperties().Where(p => p.CanWrite))
{
// Use the name of the dto property to get the corresponding property from the POCO's type. If it doesn't exist, pi will be null
PropertyInfo pi = pocoType.GetProperty(pf.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (pi != null)
{
// Check if the current propertyinfo of the POCO has a subproperty named Id
// If this is the case we treat the propertyinfo as a referenced POCO
if (pi.PropertyType.GetProperty("Id") != null)
{
// skip referenced POCOs if their data is not needed
if (!includeRelated) continue;
// Get the type of the referenced POCO
Type refObjectType = pi.PropertyType;
// Create an instance of the referenced POCO
dynamic refObject = Activator.CreateInstance(refObjectType);
// Create a type of GenericRepository<objectType>
Type refObjectRepositoryType = typeof(GenericRepository<>).MakeGenericType(refObjectType);
// Create an instance of GenericRepository<objectType>
dynamic refObjectRepository = Activator.CreateInstance(refObjectRepositoryType);
// Fill the dynamic POCO instance with the values of the referenced POCO instance
refObject = refObjectRepository._context.Entry(poco).Reference(refObjectType.Name).CurrentValue;
try
{
// Set the dto property with the name value of the referenced POCO instance
// (i.e. dtoImage.ImageType = pocImage.ImageType.Name)
pf.SetValue(dto, refObject.Name, null);
}
catch (RuntimeBinderException)
{
// this happens when the related entity is null, ie. in one to zero-or-one relationships
continue;
}
continue;
}
// If the propertyinfo's propertytype does not have an Id property, just set the value of
// the dto property to that of the POCO's propertyinfo directly
pf.SetValue(dto, pi.GetValue(poco, null), null);
}
}
For now this code will only work for referenced entities that have both an Id and a Name property. Also, there is likely to be a performance penalty for this approach so I have implemented the flag includeRelated to toggle whether to query the related objects or not.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在尝试从父级的
PropertyInfo
获取值,但GetValue
需要pi.PropertyType
类型的对象。你应该使用这样的东西:You're trying to get value from parent's
PropertyInfo
, butGetValue
expected object ofpi.PropertyType
type. You should use something like this: