I have application which uses EF-CodeFirst 5 (dll ver 4.4.0.0, on .net 4.0).
I need to be able to read entity metadata, so that I can, for a given entry type get following information:
I can get this info by writing foreach loops on lists of properties and then "recognizing" them by relying on all of the references being virtual, but I feel that is not "proper" way. I know that EdmxWriter
can provide that information in xml format, but it does so by accessing InternalContext which is not publicly accessible and I want to get strongly typed lists/arrays directly, without using that xml. Which API should I use (if there is one for this, it seems that I cannot find it)?
Gorane, this should get you started...
(I haven't played much with it - it takes a bit of experimenting in the debugger to see which properties / info and how to get it)
using (var db = new MyDbContext())
{
var objectContext = ((IObjectContextAdapter)db).ObjectContext;
var container = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace);
foreach (var set in container.BaseEntitySets)
{
// set.ElementType.
foreach (var metaproperty in set.MetadataProperties)
{
// metaproperty.
}
}
// ...or...
var keyName = objectContext
.MetadataWorkspace
.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets
.First(meta => meta.ElementType.Name == "Question")
.ElementType
.KeyMembers
.Select(k => k.Name)
.FirstOrDefault();
}
and more specifically...
foreach (var set in container.BaseEntitySets)
{
var dependents = ((EntitySet)(set)).ForeignKeyDependents;
var principals = ((EntitySet)(set)).ForeignKeyPrincipals;
var navigationProperties = ((EntityType)(set.ElementType)).NavigationProperties;
foreach (var nav in navigationProperties)
{
// nav.RelationshipType;
}
}
Some of these properties seem to not be exposed to 'general public' so you'd need to use reflection - or find some smarter way - but a good deal of info is in there.
And some more info in these links...
How to get first EntityKey Name for an Entity in EF4
How can I extract the database table and column name for a property on an EF4 entity?
EDIT: Using your list of navigationProperties as starting point, I got everything I needed like this:
ManyToManyReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
.ToList();
OneToManyReferences = navigationProperties.Where(np =>
(np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One ||
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne) &&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
.ToList();
ManyToOneReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
(np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One ||
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne))
.Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
.ToList();
OneToOneReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One &&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
.Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
.ToList();
CreateLambdaExpression method is not my courtesy, credits go to Jon Skeet, code was created with help of this answer
Here is my CreateLambdaExpression method:
public static Expression<Func<TEntity, object>> CreateLambdaExpression<TEntity>(string propertyName)
{
ParameterExpression parameter = Expression.Parameter(typeof (TEntity), typeof (TEntity).Name);
Expression property = Expression.Property(parameter, propertyName);
return Expression.Lambda<Func<TEntity, object>>(property, new[] {parameter});
}