Efcore: Error MSB4006: There is a circular dependency -- Creating migrations

Created on 13 Jan 2019  路  9Comments  路  Source: dotnet/efcore

While trying to setup an EF Core project, the following error occurs when creating the migration.

\foo\view\obj\view.csproj.EntityFrameworkCore.targets(4,5): error MSB4006: There is a circular dependency in the target dependency graph involving target "GetEFProjectMetadata". [\foo\view\view.csproj]
Unable to retrieve project metadata. Ensure it's an MSBuild-based .NET Core project. If you're using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

This is a typical MVVM WPF project, where the (EF Core) model, view-model(s), and (WPF) view(s) are each separated into their own projects. The model and view-model projects are NetStandard 2.0 projects, while the WPF is a .Net Framework desktop application. (I plan to change this to a Core project once Dotnet Core 3.0 is released.)

Here are the reproduction steps.

  • Create solution folder 'foo'.
    mkdir foo

  • Create solution 'foo'.
    <..\foo>dotnet new sln -n foo

  • Create a library project 'model'.
    <..\foo>dotnet new classlib -o model

  • Create a library project 'modelviews'.
    <..\foo>dotnet new classlib -o modelviews

  • Add projects to solution.

<..\foo>dotnet sln foo.sln add model/model.csproj
<..\foo>dotnet sln foo.sln add modelviews/modelviews.csproj
  • Open solution in Visual Studio. Add a WPF App (.NET Framework) project 'view' to the solution.

  • Change directory to 'model' project.
    <..\foo>cd model

  • Install EF Core for SqlLite

<..\foo\model>dotnet add package Microsoft.EntityFrameworkCore.Sqlite
<..\foo\model>dotnet add package Microsoft.EntityFrameworkCore.Design
  • Create model 'model.cs' in 'model' project.
using System;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace Foo
{
    public class Foo
    {
        public int Id { get; set; }
        public int Name { get; set; }
    }

    public class Bar
    {
        public int Id { get; set; }
        public int Name { get; set; }
    }

    public class FooContext : DbContext
    {
        public DbSet<Foo> Foos { get; set; }
        public DbSet<Bar> Bars { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Data Source=foo.db");
        }
    }
}
  • Create initial migration in the model project.
    <..\foo>dotnet ef migrations add Initial --project model/model.csproj --startup-project view/view.csproj

This results in the error:

\foo\view\obj\view.csproj.EntityFrameworkCore.targets(4,5): error MSB4006: There is a circular dependency in the target dependency graph involving target "GetEFProjectMetadata". [\foo\view\view.csproj]
Unable to retrieve project metadata. Ensure it's an MSBuild-based .NET Core project. If you're using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

What can be done to resolve or workaround this issue?

Version information:
-Dotnet Core: 2.2.102
-Visual Studio: 15.9.4
-EF Core: 2.2.1
-OS: Windows 10 Pro (1809 -- Build 17763.195)

closed-question customer-reported

Most helpful comment

Had exactly the same problem. Solution:

add-migration -Name [Name] -Project "[ProjectName]"

I don't know how or why, but it worked for me.

All 9 comments

Had exactly the same problem. Solution:

add-migration -Name [Name] -Project "[ProjectName]"

I don't know how or why, but it worked for me.

@bricelam to consider workarounds/documentation.

Thanks @Davecameron77.
I tried your solution, but I was not able to get it to work.

PM> Add-Migration -Name Initial -Project model
Startup project 'model' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core Package Manager Console Tools with this project, add an executable project targeting .NET Framework or .NET Core that references this project, and set it as the startup project; or, update this project to cross-target .NET Framework or .NET Core. For more information on using the EF Core Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034705

Which makes sense, so I added the -StartupProject argument, but now get the following error:

PM> Add-Migration -Name Initial -Project model -StartupProject view
Your startup project 'view' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.

I have not yet tried to add Microsoft.EntityFrameworkCore.Design, but I would really rather not as it largely defeats the purpose of separating the model from the rest of the project(s).

Are there any other workarounds?

It sounds like view.csproj isn't on of the new "SDK" projects (i.e. it doesn't start with <Project Sdk="Microsoft.NET.Sdk">). dotnet ef will not work. Instead, use the PMC commands:

Add-Migration Initial -Project model -StartupProject view

Oops looks like you got that far. 馃槃

Just add the Microsoft.EntityFrameworkCore.Design (or .Tools) package directly to the startup project. Your goal to keep EF out of the application project is very hard to achieve--NuGet will automatically include packages used by referenced projects into the main project.

In other words, Microsoft.EntityFrameworkCore.Design is already referenced by view.csproj. But MSBuild fails to copy it to the output directory since it thinks it's not needed. Adding the PackageReferecne directly to view.csproj will work around this quirk.

Hi @bricelam. Thank you for the suggestions.
And sorry for the delay.
As suggested, I manually added a reference to Microsoft.EntityFrameworkCore.Design to the startup project (view).
I next ran the same command, but got a new error.

PM> Add-Migration -Name Initial -Project model -StartupProject view
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.EntityFrameworkCore, Version=2.2.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
at Microsoft.EntityFrameworkCore.Design.OperationExecutor..ctor(Object reportHandler, IDictionary args)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(String assemblyString, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.AppDomain.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at Microsoft.EntityFrameworkCore.Tools.AppDomainOperationExecutor..ctor(String assembly, String startupAssembly, String projectDir, String dataDirectory, String rootNamespace, String language)
at Microsoft.EntityFrameworkCore.Tools.Commands.ProjectCommandBase.CreateExecutor()
at Microsoft.EntityFrameworkCore.Tools.Commands.MigrationsAddCommand.Execute()
at Microsoft.DotNet.Cli.CommandLine.CommandLineApplication.Execute(String[] args)
at Microsoft.EntityFrameworkCore.Tools.Program.Main(String[] args)
Exception has been thrown by the target of an invocation.

I uploaded the solution to GitHub.
Maybe that will help track down the issue.

Sent PR bendono/EFCoreSample#1 to fix it. Two issues:

  • Missing a project reference from your startup project to your models library.
  • Microsoft.EntityFrameworkCore.Design wasn't installed into the startup project via NuGet

Hi @bricelam. Thank you very much reviewing the repo and the PR.
I am now able to add the migrations as expected.

However, I am a little concerned in the resolution steps.
In a MVVM architecture, the (EF) model and view should not be linked to each other.
Rather, the view-model links to the view, and the view links to the view-model.
But in order to get the EF tooling to work, apparently the view must reference the model.

With this result, there is no longer any advantage to splitting the model / view-model / view into separate projects. A single project sharing everything would be just as effective, and likely much easier for the EF tooling to process.

This seems wrong to me.
Is this really the way that EF was designed to work?
Are there any plans or discussion to support other architectures?

Looking at the generated code, I suppose I could write and update it by hand.
Is this a common scenario? Or would this likely cause more problems than it is worth?

The app depends on all of its layers. You can remove the reference to views and add a reference to viewmodels. The viewmodels project would then reference the views project.

Not referencing model types from the views is up to the developers. However, I think you're wrong. It's very normal to define data templates in the view for objects in the model layer since the viewmodel often contains properties exposing these objects.

Was this page helpful?
0 / 5 - 0 ratings