diff --git a/src/EFCore.Design/Design/DbContextActivator.cs b/src/EFCore.Design/Design/DbContextActivator.cs index 037fe02ff14..164826caaaa 100644 --- a/src/EFCore.Design/Design/DbContextActivator.cs +++ b/src/EFCore.Design/Design/DbContextActivator.cs @@ -43,6 +43,8 @@ public static DbContext CreateInstance( { Check.NotNull(contextType, nameof(contextType)); + EF.IsDesignTime = true; + return new DbContextOperations( new OperationReporter(reportHandler), contextType.Assembly, diff --git a/src/EFCore.Design/Design/OperationExecutor.cs b/src/EFCore.Design/Design/OperationExecutor.cs index f8ea9076ea2..e9a7295a62f 100644 --- a/src/EFCore.Design/Design/OperationExecutor.cs +++ b/src/EFCore.Design/Design/OperationExecutor.cs @@ -706,6 +706,7 @@ protected OperationBase(IOperationResultHandler resultHandler) /// The action to execute. protected virtual void Execute(Action action) { + EF.IsDesignTime = true; try { action(); @@ -714,6 +715,10 @@ protected virtual void Execute(Action action) { _resultHandler.OnError(ex.GetType().FullName!, ex.Message, ex.ToString()); } + finally + { + EF.IsDesignTime = false; + } } /// diff --git a/src/EFCore/EF.cs b/src/EFCore/EF.cs index 457cc47efda..57b650f9251 100644 --- a/src/EFCore/EF.cs +++ b/src/EFCore/EF.cs @@ -17,6 +17,22 @@ public static partial class EF internal static readonly MethodInfo PropertyMethod = typeof(EF).GetTypeInfo().GetDeclaredMethod(nameof(Property))!; + /// + /// This flag is set to when code is being run from a design-time tool, such + /// as "dotnet ef" or one of the Package Manager Console PowerShell commands "Add-Migration", "Update-Database", etc. + /// + /// + /// + /// This flag can be inspected to change application behavior. For example, if the application is being executed by an EF + /// design-time tool, then it may choose to skip executing migrations commands as part of startup. + /// + /// + /// See EF Core command-line reference for more information + /// and examples. + /// + /// + public static bool IsDesignTime { get; set; } + /// /// References a given property or navigation on an entity instance. This is useful for shadow state properties, for /// which no CLR property exists. Currently this method can only be used in LINQ queries and can not be used to diff --git a/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs b/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs index 8628f6b3272..f0e8f6727b0 100644 --- a/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs +++ b/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs @@ -8,14 +8,20 @@ public class DbContextActivatorTest [ConditionalFact] public void CreateInstance_works() { + EF.IsDesignTime = false; + var result = DbContextActivator.CreateInstance(typeof(TestContext)); Assert.IsType(result); + + Assert.True(EF.IsDesignTime); } [ConditionalFact] public void CreateInstance_with_arguments_works() { + EF.IsDesignTime = false; + var result = DbContextActivator.CreateInstance( typeof(TestContext), null, @@ -23,13 +29,19 @@ public void CreateInstance_with_arguments_works() new[] { "A", "B" }); Assert.IsType(result); + + Assert.True(EF.IsDesignTime); } private class TestContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder options) - => options + { + Assert.True(EF.IsDesignTime); + + options .EnableServiceProviderCaching(false) .UseInMemoryDatabase(nameof(DbContextActivatorTest)); + } } } diff --git a/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs b/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs index 1b9e1963b31..7794f8062e7 100644 --- a/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs +++ b/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs @@ -17,6 +17,24 @@ public void Ctor_validates_arguments() public class OperationBaseTests { + [ConditionalFact] + public void Operations_have_design_time_flag_set() + { + EF.IsDesignTime = false; + + var handler = new OperationResultHandler(); + var result = "Twilight Sparkle"; + + new MockOperation(handler, () => + { + Assert.True(EF.IsDesignTime); + return result; + }); + + Assert.False(EF.IsDesignTime); + Assert.Equal(result, handler.Result); + } + [ConditionalFact] public void Execute_catches_exceptions() {