Skip to content

Instantly share code, notes, and snippets.

@jods4
Created October 18, 2020 15:30
Show Gist options
  • Save jods4/2f44393ea20764682be31f329f545d84 to your computer and use it in GitHub Desktop.
Save jods4/2f44393ea20764682be31f329f545d84 to your computer and use it in GitHub Desktop.
Finds the inverse Property of an EF 6 NavigationProperty.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Reflection;
class Program
{
static PropertyInfo GetInverseProperty(DbContext context, Type parentType, string parentProperty)
{
var meta = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
// Note: a CLR class can have a null Namespace (if it isn't defined in one),
// but EDM throws NullArgumentException and expects an empty string instead.
// TODO: if this code can be called from contexts where `parentType` isn't guaranteed to be
// a mapped EF class, you may want to call `TryGetType` and handle the error instead.
var oType = meta.GetType(parentType.Name, parentType.Namespace ?? "", DataSpace.OSpace) as EntityType;
// TODO: if this code can be called from contexts where `parentProperty` isn't guaranteed to be
// a mapped EF navigation property, you may want to call `TryGetValue` and handle the error instead.
var navigation = oType.NavigationProperties.GetValue(parentProperty, ignoreCase: false);
var cType = (AssociationType)meta.GetEdmSpaceType(navigation.RelationshipType);
// TODO: Could it sometimes be [0] ?
// Maybe it's safer to check if the property is different from the source property?
// Don't check the type though, as it could be a self-referencing relationship.
var endMember = (AssociationEndMember)cType.RelationshipEndMembers[1];
return endMember.MetadataProperties.TryGetValue("ClrPropertyInfo", ignoreCase: false, out var metaProperty)
? (PropertyInfo)metaProperty.Value
: null; // No inverse property
}
static void Main(string[] args)
{
var db = new Context();
var foo = typeof(Foo);
Console.WriteLine(GetInverseProperty(db, foo, nameof(Foo.Bars)));
Console.WriteLine(GetInverseProperty(db, foo, nameof(Foo.Children)));
}
}
// Fake data model for demonstration:
class Foo
{
public int Id { get; set; }
// This one has an inverse nav
public ICollection<Bar> Bars { get; set; }
// This one doesn't
public ICollection<Child> Children { get; set; }
}
class Bar
{
public int Id { get; set; }
public int FooId { get; set; }
public Foo Foo { get; set; }
}
class Child
{
public int Id { get; set; }
public int FooId { get; set; }
}
class Context : DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
public DbSet<Child> Children { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment