Connecting to Sequilizer with Code First Entity Framework.

nadrees's Avatar

nadrees

17 Jan, 2012 02:01 AM

I've been trying to get the db connection to work for my app for a few days now. I followed the directions on the documentation site about putting in the db alias as follows:

<add name="TrulySkilledContext"
     connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=TrulySkilled.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True"
     providerName="System.Data.SqlClient"
     />

(that connection string is for my local machine obviously), but every time I deploy the application I get the error The provider did not return a ProviderManifestToken string. ---> System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

I saw the post about writing your own custom connection string based off the appSettings variables that get injected into your application, but I still get the same error. What am I doing wrong?

Thanks for your time!

  1. Support Staff 1 Posted by friism on 17 Jan, 2012 02:05 AM

    friism's Avatar

    Have you specified TrulySkilledContext as the alias on sequelizer?

    Michael

  2. 2 Posted by nadrees on 17 Jan, 2012 02:07 AM

    nadrees's Avatar

    Yes I did, and I left the metadata portion blank because it's Code First (I think that's correct...)

  3. Support Staff 3 Posted by friism on 17 Jan, 2012 02:13 AM

    friism's Avatar

    Have you verified that your database still exists? EF has a tendency do drop it, and you need to use this nuget package: http://nuget.org/packages/EFCodeFirst.CreateTablesOnly

    Michael

  4. 4 Posted by nadrees on 17 Jan, 2012 02:20 AM

    nadrees's Avatar

    I can connect to the database using the Server Explorer in Visual Studio, and I still see the tables after doing a refresh.

    I have installed the NuGet package and it put a class is my App_Start folder:

    public static class DontDropDbJustCreateTablesIfModelChangedStart {
        public static void Start() {
            // Uncomment this line and replace CONTEXT_NAME with the name of your DbContext if you are 
            // using your DbContext to create and manage your database
             Database.SetInitializer(new DontDropDbJustCreateTablesIfModelChanged<TrulySkilledContext>());
        }
    }
    

    I think that's all I needed to do to make that package work right?

  5. Support Staff 5 Posted by friism on 17 Jan, 2012 03:05 AM

    friism's Avatar

    Yeah, sounds like you should be all set.

    You might want to use this method to see if you can figure out why your application is not using the expected connectionstring: http://blog.appharbor.com/2011/12/20/super-simple-logging-on-appharbor

    Michael

  6. 6 Posted by nadrees on 17 Jan, 2012 06:08 PM

    nadrees's Avatar

    Thanks, I'll look into this when I get home tonight. If I dump the connection string from the WebConfigurationManager I should see the Sequelizer connection string right? Is there anything else that you think I should be looking out for?

  7. Support Staff 7 Posted by friism on 17 Jan, 2012 07:19 PM

    friism's Avatar

    I think you can also get the connectionstring Entity Framework is currently using off the context, you should do that too.

    Michael

  8. 8 Posted by nadrees on 18 Jan, 2012 09:57 PM

    nadrees's Avatar

    I managed to get the app working by hard coding the connection string into the DbContext. It's not the best way but it works for now. Does the connection string replacement not get inject until the app has actually been deployed (this could cause my issues with the tests not being able to connect)?

  9. 9 Posted by nadrees on 18 Jan, 2012 10:03 PM

    nadrees's Avatar

    I tried the message you suggested, but the app isn't displaying any log
    messages in the Errors page. Could this be because the app is failing
    during the unit tests (that's when it's trying to connect to the database)?

    Thanks,
    Nathen Drees
    Iowa State Engineering
    Software Engineering

  10. Support Staff 10 Posted by friism on 18 Jan, 2012 10:13 PM

    friism's Avatar

    Your last messages explains everything.

    The connectionstring is not inserted while unit tests are run. This is because you shouldn't be using the database to execute tests, mock the data access instead.

    Michael

  11. 11 Posted by nadrees on 18 Jan, 2012 11:48 PM

    nadrees's Avatar

    Thanks, I mocked them out and everything appears to be working now.

    Thanks for all the help.

  12. nadrees closed this discussion on 18 Jan, 2012 11:48 PM.

  13. friism re-opened this discussion on 18 Jan, 2012 11:49 PM

  14. Support Staff 12 Posted by friism on 18 Jan, 2012 11:49 PM

    friism's Avatar

    No problem, I'm happy we found the cause! I'll add this to the FAQ now.

    Michael

  15. 13 Posted by nadrees on 18 Jan, 2012 11:56 PM

    nadrees's Avatar

    Here are some tidbits of code that should help people in the future (mocking the DbContext for the EntityFramework isn't obvious):

    Fake for IDbSet
    class ModelFakeDbSet : FakeDbSet where T : Model

    {
        public override T Find(params object[] keyValues)
        {
            return this.SingleOrDefault(a => a.ID == (int)keyValues.Single());
        }
    }
    
    // class mostly taken from http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/
    class FakeDbSet<T> : IDbSet<T> where T : class
    {
        protected HashSet<T> _data;
        protected IQueryable _query;
    
        public FakeDbSet()
        {
            _data = new HashSet<T>();
            _query = _data.AsQueryable();
        }
    
        public virtual T Find(params object[] keyValues)
        {
            throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
        }
    
        public T Add(T entity)
        {
            _data.Add(entity);
            return entity;
        }
    
        public T Attach(T entity)
        {
            return Add(entity);
        }
    
        public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
        {
            throw new NotImplementedException("Not needed for tests");
        }
    
        public T Create()
        {
            throw new NotImplementedException("Not needed for tests");
        }
    
        public System.Collections.ObjectModel.ObservableCollection<T> Local
        {
            get { return new System.Collections.ObjectModel.ObservableCollection<T>(_data); }
        }
    
        public T Remove(T entity)
        {
            _data.Remove(entity);
            return entity;
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return _data.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public Type ElementType
        {
            get { return _query.ElementType; }
        }
    
        public Expression Expression
        {
            get { return _query.Expression; }
        }
    
        public IQueryProvider Provider
        {
            get { return _query.Provider; }
        }
    }
    

    The base Model class
    public abstract class Model

    {
        /// <summary>
        /// The ID provided by the database.
        /// </summary>
        public int ID { get; set; }
    }
    

    I'm using the Repository pattern to access the database, so I abstracted the context away behind this interface:

    ///

    /// Repository interface for dealing with Account entities.
    /// </summary>
    public interface IAccountRepository : IDisposable
    {
        /// <summary>
        /// Fetches all Account entities.
        /// </summary>
        /// <returns>All Account entities</returns>
        IEnumerable<Account> GetAccounts();
    
        /// <summary>
        /// Searches for an Account entity with the numeric id provided
        /// </summary>
        /// <param name="id">The id of the desired Account</param>
        /// <returns>The desired Account, if one exists, or null if no Account exists with that ID</returns>
        Account GetAccountByID(int id);
    
        /// <summary>
        /// Searches for an Account with the id provided by the specified provider.
        /// </summary>
        /// <param name="id">The string id given by the provider</param>
        /// <param name="provider">One of 'google', 'yahoo', 'myopenid', or 'openid'</param>
        /// <returns>The desired Account, if one exists, or null if no Account exists with that ID</returns>
        /// <exception cref="ArgumentNullException">If either id is null</exception>
        /// <exception cref="AgrumentException">If provider is null or not one of the listed providers above</exception>
        [NotNull]
        Account GetAccountByID(String id, [ValueInSet("google", "yahoo", "myopenid", "openid")] String provider);
    
        /// <summary>
        /// Creates the account Account if it does not already exist (i.e. if the numeric ID is not 0 or could not be found in the database)
        /// </summary>
        /// <param name="account">The Accout object to be added to the database</param>
        [NotNull]
        void CreateAccount(Account account);
    
        /// <summary>
        /// Deletes the specified Account from the database, if it exists.
        /// </summary>
        /// <param name="account">The Account to be removed.</param>
        [NotNull]
        void DeleteAccount(Account account);
    
        /// <summary>
        /// Deletes the Account with the specified id, if it exists.
        /// </summary>
        /// <param name="id">The id of the Account to be removed.</param>
        void DeleteAccount(int id);
    
        /// <summary>
        /// Marks the Account as updated.
        /// </summary>
        /// <param name="account">The Account to be updated.</param>
        [NotNull]
        void UpdateAccount(Account account);
    
        /// <summary>
        /// Saves all changes to the database.
        /// </summary>
        void Save();
    }
    

    Ignore the annotations on that interface, they just do argument checking for me (using the Interceptor pattern if you're curious). To actually get tests to run, I mocked the DbContext as follows (using the Moq library):

    public class FakesAndMocksFactory

    {
        public static ITrulySkilledContext CreateContext()
        {
            var accounts = new ModelFakeDbSet<Account>();
    
            var mock = new Mock<ITrulySkilledContext>();
            mock.Setup(obj => obj.Accounts).Returns(accounts);
            mock.Setup(obj => obj.SaveChanges()).Returns(0);
            mock.Setup(obj => obj.SetModified(It.IsAny<Model>()));
    
            return mock.Object;
        }
    }
    
  16. Support Staff 14 Posted by friism on 19 Jan, 2012 12:20 AM

    friism's Avatar

    Thanks Nathen!

  17. friism closed this discussion on 19 Jan, 2012 12:20 AM.

Discussions are closed to public comments.
If you need help with AppHarbor please start a new discussion.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac