Skip to content

Instantly share code, notes, and snippets.

@orlys
Last active January 18, 2022 17:40
Show Gist options
  • Save orlys/c8a23b01cd321e1698029310eb22e3ba to your computer and use it in GitHub Desktop.
Save orlys/c8a23b01cd321e1698029310eb22e3ba to your computer and use it in GitHub Desktop.
Determines DbContext is Database-First or not.
public static class EntityFrameworkHelper
{
private static readonly System.Reflection.ConstructorInfo s_constructor =
typeof(System.Data.Entity.Infrastructure.UnintentionalCodeFirstException).GetConstructor(System.Type.EmptyTypes);
private static readonly System.Collections.Concurrent.ConcurrentDictionary<System.Type, bool> s_caches =
new System.Collections.Concurrent.ConcurrentDictionary<System.Type, bool>();
public static bool IsDatabaseFirst<TDbContext>() where TDbContext : System.Data.Entity.DbContext
=> IsDatabaseFirst(typeof(TDbContext));
public static bool IsDatabaseFirst(System.Type dbContextType)
{
if (dbContextType is null) throw new System.ArgumentNullException(nameof(dbContextType));
if (!s_caches.TryGetValue(dbContextType, out var isDatabaseFirst))
{
var onModelCreating = dbContextType.GetMethod("OnModelCreating", (System.Reflection.BindingFlags)36);
var cilBytes = onModelCreating.GetMethodBody().GetILAsByteArray();
using (var br = new System.IO.BinaryReader(new System.IO.MemoryStream(cilBytes)))
{
while (br.BaseStream.Position != br.BaseStream.Length)
{
if (br.ReadByte() == 0x73) // newobj
{
var metadataToken = br.ReadInt32();
var ctor = dbContextType.Module.ResolveMethod(metadataToken);
if (s_constructor == ctor &&
br.ReadByte() == 0x7A) // throw
{
isDatabaseFirst = true;
goto Leave;
}
}
}
}
isDatabaseFirst = false;
Leave:
s_caches.TryAdd(dbContextType, isDatabaseFirst);
}
return isDatabaseFirst;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment