我有一个实体框架 Code First DbContext,配置了以下实体。在此示例中,Bar 类是 Foo 类的子类。
public class Foo
{
public Guid Id { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public Guid Id { get; set; }
public Guid FooId { get; set; }
public virtual Foo Foo { get; set; }
}
现在我知道,实体框架在内部理解 Foo 和 Bar 之间的关系是由外键 Bar.FooId 定义的。我想做的是在运行时使用表达式以某种方式提取这种关系。我想实现一个行为如下的方法:
var context = new FooBarDbContext();
var bar = context.Set<Bar>().First();
// I want this method to return bar.FooId when passed the expression b => b.Foo
object result = MyService.GetForeignKeyValue(bar, b => b.Foo);
现在,在这个简单的示例中,我知道我只需获取 bar.FooId 即可完成。重点是,我正在编写一个类,我相信上面指定的 GetForeignKeyValue 方法对于用户来说是最干净的接口。
是否可以查询 DbContext 配置以确定哪个属性用作导航属性的外键? (假设有一个)
我实际上能够通过使用来确定外键属性获取依赖属性 http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.navigationproperty.getdependentproperties.aspx的方法导航属性 http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.navigationproperty%28v=vs.110%29.aspx class.
这是我(或多或少)用来获得我需要的代码:
object[] GetForeignKeyPropertyValues<TEntity, TRelatedEntity>(TEntity entity, Expression<Func<TEntity, TRelatedEntity>> navigationProperty)
{
if (entity == null)
return new object[] { };
// Find the entity metadata in the object context.
// (Assume you have access to the DbContext through the property CurrentDbContext.)
var objectContext = (CurrentDbContext as IObjectContextAdapter).ObjectContext;
var metadataNamespace = ObjectContextAdapter.GetType().Namespace;
var entityIdentity = metadataNamespace + "." + typeof(TEntity).Name; // HACK: This seems to work to retrieve the EntityType for an entity.
var entityMetadata = objectContext.MetadataWorkspace.GetItem<EntityType>(entityIdentity, DataSpace.CSpace);
// TODO: Verify that the entity metadata was found.
// Get the navigation property metadata by parsing the name from the navigation property expression.
var navigationPropertyName = GetPropertyName(navigationProperty);
var navigationPropertyMetadata = entityMetadata.NavigationProperties.FirstOrDefault(np => np.Name == navigationPropertyName);
// TODO: (JMB) Verify that the navigation property metadata was found.
// Extract the foreign key columns from the navigation property.
var foreignKeyPropertyMetadatas = navigationPropertyMetadata.GetDependentProperties();
// Create property getters for each foreign key property.
var foreignKeyPropertyGetters = foreignKeyPropertyMetadatas
.Select(propertyMetadata => MakePropertyGetter<TEntity>(propertyMetadata.Name))
.ToArray();
// Execute the foreign key property getters to get the foreign key property values for the specified entity.
var foreignKeyPropertyValues = foreignKeyPropertyGetters
.Select(propertyGetter => propertyGetter(entity))
.ToArray();
return foreignKeyPropertyValues;
}
static string GetPropertyName<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> navigationProperty)
{
var lambda = navigationProperty as LambdaExpression;
var member = lambda.Body as MemberExpression;
return member.Member.Name;
}
static Func<TEntity, object> MakePropertyGetter<TEntity>(Type entityType, string propertyName)
{
var parameterExpression = Expression.Parameter(typeof(TEntity), "entity");
var propertyExpression = Expression.PropertyOrField(parameterExpression, propertyName);
var lambdaExpression = Expression.Lambda(propertyExpression, parameterExpression);
var lambdaFunction = lambdaExpression.Compile();
return (Func<TEntity, object>)lambdaFunction;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)