Entity Framework - Keyword not supported: 'metadata' - entity-framework-4.1

I have the following class:
public class EFRepository<TContext> : IDisposable where TContext : DbContext, IObjectContextAdapter, new()
{
private TContext context;
public EFRepository(string connectionStringName)
{
context = new TContext();
context.Database.Connection.ConnectionString =
ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
}
}
with the following connection string:
<connectionStrings>
<add name="EntitiesConnection" connectionString="metadata=res://*/EntityModel.csdl|res://*/EntityModel.ssdl|res://*/EntityModel.msl;provider=System.Data.SqlClient;provider connection string="data source=Bob-PC;initial catalog=Entities;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
Being called like this:
var Entities = new EFRepository<EntitiesConnection>("EntitiesConnection");
Which throws the error in the subject line. I've seen the solutions using the EntityStringBuilder, however the Connection property is read only. Any ideas on how to make this work?
Thanks,
Bob

DbContext already has a constructor that accepts a connection string or name. Can you modify your existing context classes to include a constructor that accepts a connection string parameter and call base(connectionStringOrName)?
So a context would look something like:
public class SomeContext : DbContext, IObjectContextAdapter
{
public SomeContext(string connectionStringOrName)
: base (connectionStringOrName)
{
}
// Rest of the implementation...
}
And then the constructor of EFRepository<TContext> would look like:
public EFRepository(string connectionStringName)
{
context = new TContext(connectionStringName);
}

Related

Where to set the DbConfiguration in a WCF service for EF6 code first?

Trying to use EF 6 code first with a WCF service, but have run into the following runtime error:
The default DbConfiguration instance was used by the Entity Framework
before the 'MyConfiguration' type was discovered. An instance of
'MyConfiguration' must be set at application start before using
any Entity Framework features or must be registered in the
application's config file. See
http://go.microsoft.com/fwlink/?LinkId=260883 for more information.
This error is thrown when trying to instantiate the following DbContext inside a service call:
[DbConfigurationType(typeof(MyConfiguration))]
public partial class MyContext : DbContext
{
public MyContext()
: base("name=MyContext")
{
}
}
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
SetExecutionStrategy(MySqlProviderInvariantName.ProviderName, () => new MySqlExecutionStrategy());
SetDefaultConnectionFactory(new MySqlConnectionFactory());
AddDependencyResolver(new MySqlDependencyResolver());
}
}
This WCF service has other DbContexts that are used before this class is even accessed, so the error message makes perfect sense. The question is where should the configuration be set?
Create a constructor on MyContext as follows:
public MyContext(DbConnection dbConnection, bool contextOwnsConnection)
: base(dbConnection, contextOwnsConnection)
{
}
Then supply a MySqlConnection manually:
var connection = new MySqlConnection(connectionString);
connection.Open();
var context = new MyContext(connection, true);

how to maintian the EF connection string at one place?

I have the following in my project solution,am trying to maintain the Database connection of Entity framework at one place so that if I have to switch the database to a different vendor(like MYSQL to MSSQL or vice-versa) I can just change the connection name at one place and doesn't have to change at all the places...I tried the following structure but running into an error,how to fix it?
Project#1
Dashboard.EntityFramework
-->bitDbConnection.cs
using
namespace Dashboard.EntityFramework
{
public class bitDbConnection
{
BitDatabaseEntities bitDB = new BitDatabaseEntities();
}
}
Project#2
Dashboard.Repository
-->Repository.cs
using Dashboard.EntityFramework
when I try use to bitDB variable I can the below error
Error:-
The name bitDB does not exist in current context
This probably isn't what you want but to get your code to work, write it like this:
namespace Dashboard.EntityFramework
{
public class bitDbConnection
{
public BitDatabaseEntities bitDB = new BitDatabaseEntities();
}
}
using Dashboard.EntityFramework
public class Repository
{
public void DoSomething()
{
var bitDB = new bitDbConnection().bitDB;
}
}
So, first make bitDB field public, and then use it...
edit for question in comments:
public class Repository
{
private BitDatabaseEntities bitDB = new BitDatabaseEntities().bitDB;
public void DoSomething()
{
var x = bitDB.ToString();
}
}

StructureMap3 How to configure constructor string injection for all types?

I have registered my types using
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
But how do I specify for constructor injection with out having to specify the concrete type like this?
string connStr = "...";
For<IRepository().Use<MyRepository>().Ctor<string>("connectionString").Is(connStr);
You can create dedicated convention for registration of repositories.
public class RepositoryConvention : IRegistrationConvention
{
private const string ConnectionString = "your connection string";
public void Process(Type type, Registry registry)
{
if (type.IsConcrete() && type.GetInterfaces().Contains(typeof(IRepository)))
{
registry.For(typeof(IRepository))
.Use(type)
.CtorDependency<string>("connectionString")
.Is(ConnectionString);
}
}
}
or create dedicated type to provide with connection string. I bet you are getting it from web/app.config so adding abstraction for accessing it would be helpful anyway.
public interface IConfigurationSettingsReader
{
string ReadConnectionString(string name);
T ReadSetting<T>(string settingName);
}
Then you just add it as a dependency for your MyRepository and you don't need to add it explicitly in registration or use custom convention.
public class MyRepository : IRepository
{
private readonly string connectionString;
public MyRepository(IConfigurationSettingsReader settingsReader)
{
this.connectionString = settingsReader.ReadConnectionString("ConnStrName");
}
}
You can consider creating an abstract base repository class to be inherited by each repository to get rid of setup bolerplate.
Hope this helps!

Changing IRepository to support IQueryable (LINQtoSQL queries)

I've inherited a system that uses the Castle Windsor IRepository pattern to abstract away from the DAL which is LinqToSQL.
The main problem that I can see, is that IRepository only implements IEnumerable. So even the simplest of queries have to load ALL the data from the datatable, to return a single object.
Current usage is as follows
using (IUnitOfWork context2 = IocServiceFactory.Resolve<IUnitOfWork>())
{
KpiFormDocumentEntry entry = context2.GetRepository<KpiFormDocumentEntry>().FindById(id, KpiFormDocumentEntry.LoadOptions.FormItem);
And this uses lambda to filter, like so
public static KpiFormDocumentEntry FindById(this IRepository<KpiFormDocumentEntry> source, int id, KpiFormDocumentEntry.LoadOptions loadOptions)
{
return source.Where( qi => qi.Id == id ).LoadWith( loadOptions ).FirstOrDefault();
}
So it becomes a nice extension method.
My Question is, how can I use this same Interface/pattern etc. but also implement IQueryable to properly support LinqToSQL and get some serious performance improvements?
The current implementation/Interfaces for IRepository are as follows
public interface IRepository<T> : IEnumerable<T> where T : class
{
void Add(T entity);
void AddMany(IEnumerable<T> entities);
void Delete(T entity);
void DeleteMany(IEnumerable<T> entities);
IEnumerable<T> All();
IEnumerable<T> Find(Func<T, bool> predicate);
T FindFirst(Func<T, bool> predicate);
}
and then this is implemented by an SqlClientRepository like so
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
private readonly Table<T> _source;
internal SqlClientRepository(Table<T> source)
{
if( source == null ) throw new ArgumentNullException( "source", Gratte.Aurora.SHlib.labelText("All_TableIsNull",1) );
_source = source;
}
//removed add delete etc
public IEnumerable<T> All()
{
return _source;
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The problem at the moment is, in our example above, the .Where is calling 'GetEnumerator', which then loads all rows into memory, and then looks for the one we need.
If I change IRepository to implement IQueryable, I can't implement the three methods needed, as these are not public in the Table class.
I think I should change the SQLClientRepository to be defined like so
public sealed class SqlClientRepository<T> : IQueryable<T>, IRepository<T> where T : class
And then implement the necessary methods, but I can't figure out how to pass the expressions around etc. as they are private members of the Table class, like so
public override Type ElementType
{
get { return _source.ElementType; } //Won't work as ElementType is private
}
public override Expression Expression
{
get { return _source.Expression; } //Won't work as Expression is private
}
public override IQueryProvider Provider
{
get { return _source.Provider; } //Won't work as Provider is private
}
Any help really appreciated to move this from 'iterate through every row in the database after loading it' to 'select x where id=1'!
If you want to expose linq you can stop using the repository pattern and use Linq2Sql directly. The reason to this is that every Linq To Sql provider has it's own custom solutions. So if you expose LINQ you get a leaky abstraction. There is no point in using an abstraction layer then.
Instead of exposing LINQ you got two options:
Implement the specification pattern
Use the repository pattern as I describe here: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
So, while it may not be a true abstraction any longer, the main point was to get the benefit of linq to sql without updating all the queries already written.
so, I made the IRepository implement IQueryable instead of IEnumerable.
then in the SqlClientRepository implementation, I can call AsQueryable() to cast the Table to IQueryable, and then all is good, like so.
Now everywhere somebody has written IRepository().Where(qi => qi.id = id) or similar, it actually passes the ID to sql server and only pulls back one record, instead of all of them, and loops through looking for the correct one.
/// <summary>Provides the ability to query and access entities within a SQL Server data store.</summary>
/// <typeparam name="T">The type of entity in the repository.</typeparam>
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
private readonly Table<T> _source;
private readonly IQueryable<T> _sourceQuery;
IQueryable<T> Query()
{
return (IQueryable<T>)_source;
}
public Type ElementType
{
get { return _sourceQuery.GetType(); }
}
public Expression Expression
{
get { return _sourceQuery.Expression; }
}
public IQueryProvider Provider
{
get { return _sourceQuery.Provider; }
}
/// <summary>Initializes a new instance of the <see cref="SqlClientRepository{T}"/> class.</summary>
/// <param name="source">A <see cref="Table{T}"/> to a collection representing the entities from a SQL Server data store.</param>
/// <exception cref="ArgumentNullException"><paramref name="source"/> is a <c>null</c> reference (<c>Nothing</c> in Visual Basic).</exception>
internal SqlClientRepository(Table<T> source)
{
if( source == null ) throw new ArgumentNullException( "source", "All_TableIsNull" ) );
_source = source;
_sourceQuery = _source.AsQueryable();
}

How to prevent EF4.1 from creating a DB if it doesn't exist?

I'm using EF4.1 with MVC3 and I need an override to prevent EF from creating a db if it doesn't exist. Instead of creating a new db I would like to catch the error and report that the initial catalog (the database name) is invalid in the connect string.
However, during development I would like to allow for updates for new classes/properties to create according tables/cols in the database.
Is there a best practice or pattern here?
In my application i am completly disable context initializer and handle database mapping and schema manually.
For example :
public class AppDbContext : DbContext
{
public IDbSet<Account> Accounts { get; set; }
public AppDbContext() : base("connection_string")
{
Database.SetInitializer<AppDbContext>(null); // Important! Dont use entity framework initializer !important
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
/* Register custom mapping class */
modelBuilder.Configurations.Add(new AccountMapper());
base.OnModelCreating(modelBuilder);
}
}
And custom mapping :
public class AccountMapper : EntityTypeConfiguration<Account>
{
/// <summary>
/// Employee entity mapper
/// </summary>
public AccountMapper()
{
ToTable("accounts");
HasKey(x => x.Id);
...
}
}
I would suggest looking into the EF database initializer, specifically the IDatabaseInitializer interface.
If you just want it to stop creating the database when it doesn't exist, then just set the Initializer to null. But if you want to log the event or something along those lines then simply create your own IDatabaseInitializer - it's not hard.
You can then set the initializer Application_Start in your global.asax.cs like so:
Database.SetInitializer(new YourCustomInitializer());
As a bonus, here's an example IDatabaseInitializer that I use to run database migrations (using FluentMigrator)... it's extremely handy if I do say so myself!
public class MigrationsDbContextInitializer : IDatabaseInitializer<YourDbContext>
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(MigrationsDbContextInitializer));
public void InitializeDatabase(YourDbContext context)
{
var announcer = new BaseAnnouncer(x => Logger.Info(x));
var runnerContext = new RunnerContext(announcer)
{
Database = "sqlserver2008",
Connection = context.Database.Connection.ConnectionString,
Target = "YourEntitiesNamespace",
PreviewOnly = false,
Task = "migrate"
};
new TaskExecutor(runnerContext).Execute();
}
}