9

I'm using the Model First approach with EF6 and I'm trying to use Entity Framework Effort to develop in-memory tests.

Here is what I do in my test:

var inMemoryConnection = Effort.DbConnectionFactory.CreateTransient("name=MyEntities");
var inMemoryContext = new MyEntities(inMemoryConnection);

MyEntities:

public partial class MyEntities: DbContext
{
    public MyEntities(DbConnection dbConnection)
        : base(dbConnection, contextOwnsConnection: true)
    {
    }

When I run the tests, I get an error saying I didn't specify any [key] attributes which is normal since I am not using a Code First approach. Therefor, the OnModelCreating method is called and shouldn't have to.

Is there a way to use Effort in a Model First design without having to add these attributes?

Thanks !

Boubou
  • 632
  • 5
  • 18

2 Answers2

10

I found my mistake.

Turns out Effort.DbConnectionFactory.CreateTransient is used for Code-First.

Instead if you're working with a .edmx, Model-First, it is Effort.EntityConnectionFactory.CreateTransient("name=MyEntities") you have to use.

Boubou
  • 632
  • 5
  • 18
  • This didn't work for me - it still uses the actual database instead of an in-memory one. What does your ``app.config`` look like? – Matt Koch Jul 10 '18 at 16:33
  • 2
    @MattKoch I had to add `` into the `` section of my app.config – MikeS Oct 12 '18 at 16:07
  • @MattKoch How do you know it is using the actual db? – Andes Lam Aug 31 '21 at 04:36
  • in case you're getting an exception `Argument 'xmlReader' is not valid. A minimum of one .ssdl artifact must be supplied` ... What's also relevant is that you need to have the model assembly (containing the edmx file) loaded BEFORE the above call `Effort.EntityConnectionFactory.CreateTransient("name=MyEntities")` i.e. just doing a `typeof(MyDbContext)` before the call will do the trick. – user3391859 Aug 30 '23 at 05:58
8

I too had a bit of a difficult time in trying to get Effort to work with a DB first, or model first as it's also known, approach. This is what I did to make it work:

  • Download the Effort.EF6 nuget package
  • Add the effort.provider to the entity-framework config section:
    <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="Effort.Provider" type="Effort.Provider.EffortProviderServices,Effort" />
    </providers>
  </entityFramework>
  • Replace the sql-provider with the Effort-provider in the connection-string:
<connectionStrings>
    <add name="testDb" providerName="Effort.Provider" connectionString="metadata=res://*/StaginDB.csdl|res://*/StaginDB.ssdl|res://*/StaginDB.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=testDB;initial catalog=foobaroo;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;"  />
  </connectionStrings>
  • If your model-first context doesn't offer a constructor you can inject a connection into, you can modify your tt-template to do so:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{

    // I added this constructor so I could inject a db-connection into the context:
    public <#=code.Escape(container)#>(System.Data.Common.DbConnection dbConnection, bool contextOwnsConnection) 
        : base(dbConnection, contextOwnsConnection)
        {
    }

    // Original constructor
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
        this.Configuration.LazyLoa.... etc. etc.
  • And we can now use that constructor to instantiate a connection, and an Effort-based in-memory db-context based on this connection:
System.Data.Common.DbConnection connection = Effort.EntityConnectionFactory.CreateTransient("name=KPDBSTAGINGEntities");
TestDbContext testDbContext = new testDbContext(connection, false);

TestDbContext.your-entity.add( new your-entity() { etc. tec. });
TestDbContext.SaveChanges();

Hope this helps.

P.S. Others have had to add a db-provider-factory section to their config. This was not required for me, but maybe for you:

<system.data>
    <DbProviderFactories>
      <add name="Effort.Provider" invariant="Effort.Provider" description="Effort.Provider" type="Effort.Provider.EffortProviderFactory,Effort" />
    </DbProviderFactories>
  </system.data>
Morten Nørgaard
  • 2,609
  • 2
  • 24
  • 24