Code First: Create Tables but not database - c#

I have ready my model on code first EF and I try it on sql express and it works. But I have a problem translating it to a sql server: I don't have the permissions to recreate a database I can only add tables to an empty database.
I already see this answer but when I'm trying to replicate it I have some troubles with the context part:
public class DropCreateDatabaseTables : IDatabaseInitializer<Context> {
#region IDatabaseInitializer<Context> Members
public void InitializeDatabase(Context context)
I already put the reference to System.Data.Entity but that don't work and the Context class not is the referenced on System.Runtime.Remoting.Contexts
There is something wrong in the code? Or is a better solution with the last tools of EF?
EDIT:
Finally was:
DbContext:
public class PeopleContext: DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Adress> Adresses{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Add Entity type configuration classes
modelBuilder.Configurations.Add(new PersonConfiguration());
modelBuilder.Configurations.Add(new AdressConfiguration());
}
}
Initializer:
public class DropCreateDatabaseTables : IDatabaseInitializer<PeopleContext>
{
public void InitializeDatabase(PeopleContextContext)
{
bool dbExists;
using (new TransactionScope(TransactionScopeOption.Suppress))
{
dbExists = Context.Database.Exists();
}
if (dbExists)
{
// remove all tables
Context.Database.ExecuteSqlCommand("EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'");
Context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable #command1 = \"DROP TABLE ?\"");
// create all tables
var dbCreationScript = ((IObjectContextAdapter)Context).ObjectContext.CreateDatabaseScript();
Context.Database.ExecuteSqlCommand(dbCreationScript);
Context.SaveChanges();
}
else
{
throw new ApplicationException("No database instance");
}
}
}
Call:
class Program
{
static void Main(string[] args)
{
var person= new Person
{
Identifier= "John Doe"
};
Database.SetInitializer(new DropCreateDatabaseTables());
using (var context = new PeopleContext())
{
context.People.Add(person);
context.SaveChanges();
}
}
}
Thanks Lukas Kabrt!

The Context class in the example should be your DbContext class i.e. the class where you specify your DbSet<>s.
Example:
DbContext class
public class DataContext : DbContext {
public DbSet<Customer> Customers { get; set; }
}
DatabaseInitializer
public class DropCreateDatabaseTables : IDatabaseInitializer<DataContext> {
...
}

Related

Invalid object name 'dbo.Tasks'. in Code First approach

I am using code first approach to connect with database and tables but due to some issue enable/add migration command is not creating my tables so I created tables manually. Th application build successfully that means I assume the objDbContext get my table. The name of Table is Task in database.
Below is my code
eDbContext objDbContext = new eDbContext ();
public List<TaskDetail> GetTasks(long eventId)
{
List<TaskDetail> listTask = new List<TaskDetail>();
try {
listTask = (from task in objDbContext.Tasks
where task.EventId==eventId
select new TaskDetail
{
Id = task.Id,
Title = task.Title,
Description = task.Description,
StartDate = task.StartDate,
EndDate = task.EndDate
}
).ToList();
}
catch(Exception ex) {
throw ex;
}
return listTask;
}
Below is database context
public class eDbContext : DbContext
{
public DbSet<Task> Tasks { get; set; }
}
If you have similar problem (plural table names) for other entities, then you should remove PluralizingTableNameConvention (by default EF generates plural table names from entity type names). Add this code to your DbContext class:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
If other tables have plural names, then you should just fix mapping for Task entity as #Valkyriee suggested.
Your DbContext Class should look like this:
public class eDbContext : DbContext
{
public IebContext()
: base("name=ConnectionStringName")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<eDbContext, Migrations.Configuration>("CatalogName"));
}
public DbSet<Task> Tasks{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TaskMap());
}
}
For your Migration you can create a new class like:
internal sealed class Configuration : DbMigrationsConfiguration<eDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
//know this might loss data while its true.
AutomaticMigrationDataLossAllowed = true;
ContextKey = "Path to your DbContext Class";
}
protected override void Seed(eDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
Now using this approach you can create your tables with EF code-first and change them later on. Note that I've added a Map Class for Tasks which means i am using fluent api for Mapping my entity:
public class TaskMap : EntityTypeConfiguration<Task>
{
public TaskMap ()
{
ToTable("Tasks");
HasKey(x => x.Id);
}
}

SQLite Entity Framework 6 not releasing db file

The original problem is to release current db file, delete it and create new one, so database could be completely fresh and clean. Why do I get exception if (as i believe) file should be released when context is disposed?
UPDATE:
Indeed, GC solves the problem.
Now I get another problem which is not obvious to me either. I just disposed context, created new one and tables should've been lazily initialized. server.db file is created but has no tables. Can someone explain please?
class Program
{
static void Main(string[] args)
{
var dbFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "server.db");
if (File.Exists(dbFilename))
File.Delete(dbFilename);
using (var ctx = new CustomContext())
{
ctx.Products.Add(new Product {Cost = 10});
ctx.SaveChanges();
}
// SOLUTION (1)
GC.Collect();
GC.WaitForPendingFinalizers();
if (File.Exists(dbFilename))
File.Delete(dbFilename); // (1) WinIOError : can't access file server.db
using (var ctx = new CustomContext())
{
ctx.Products.Add(new Product {Cost = 10});
ctx.SaveChanges(); // (2) no such table: Products
}
}
}
public class CustomContext : DbContext
{
public DbSet<Product> Products { get; set; }
public CustomContext() : base("ServerConnection")
{
}
// App.config contains:
// <connectionStrings>
// <add name="ServerConnection" connectionString="Data Source=|DataDirectory|\server.db" providerName="System.Data.SQLite" />
// </connectionStrings>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var dbInitializer = new SqliteCreateDatabaseIfNotExists<CustomContext>(modelBuilder);
Database.SetInitializer(dbInitializer);
}
}
public class Product
{
[Key]
public double Cost { get; set; }
}

C# MVC4 noob - define interface with DbContext Entry method included

I am trying to learn C# coming from a classic ASP/VBScript background.
Up front (just in case someone can answer without all the following background info and code) - My DbContext interface doesn't allow me to do this:
_dbcontext.Entry(model).State = EntityState.Modified;
It balks at me trying to use the Entry method with the following error:
'MyNamespace.Models.IMyDataContext' does not contain a definition for 'Entry' and no extension method 'Entry' accepting a first argument of type 'MyNamespace.Models.IMyDataContext' could be found (are you missing a using directive or an assembly reference?)
How can I properly define my interface so that it will include the Entry method from the DbContext class?
BACKGROUND
I had someone who (supposedly) knows their stuff help me get the following code setup for connecting to MSSQL or MySQL based on data we retrieve from a common connection info table. The schema in MSSQL and MySQL is identical for the data model.
public interface IMyDataContext
{
DbSet<MyModel> ModelData { get; set; }
}
public class dbMySQL : DbContext, IMyDataContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var table = modelBuilder.Entity<MyModel>().ToTable("tablename");
table.HasKey(t => t.Id);
table.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
table.Property(t => t.Key);
table.Property(t => t.Value);
base.OnModelCreating(modelBuilder);
}
public dbMySQL(DbConnection existingConnection, boolcontextOwnsConnection) : base(existingConnection, contextOwnsConnection) { }
public DbSet<MyModel> ModelData { get; set; }
}
public class dbMSSQL : DbContext, IMyDataContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var table = modelBuilder.Entity<MyModel>().ToTable("tablename");
table.HasKey(t => t.Id);
table.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
table.Property(t => t.Key);
table.Property(t => t.Value);
base.OnModelCreating(modelBuilder);
}
public dbMSSQL(string connectionString) : base(connectionString) { }
public DbSet<MyModel> ModelData { get; set; }
}
Using the above code, I have been able to successfully grab connection info from a table and return a DbContext as follows:
private IMyDataContext selectDbProvider(int Id)
{
// Get database connection info
var connInfo = _db.ConnModel.Find(Id);
string dbProvider = connInfo.dbType.ToString();
IMyDataContext _dbd;
if (dbProvider == "MySql.Data.MySqlClient")
{
var connectionStringBuilder = new MySqlConnectionStringBuilder();
connectionStringBuilder.Server = connInfo.dbServer;
connectionStringBuilder.UserID = connInfo.dbUser;
connectionStringBuilder.Password = connInfo.dbPassword;
connectionStringBuilder.Database = connInfo.dbName;
connectionStringBuilder.Port = 3306;
_mysqlconn = new MySqlConnection(connectionStringBuilder.ConnectionString);
_dbd = new dbMySQL(_mysqlconn, false);
}
else
{
var connectionStringBuilder = new SqlConnectionStringBuilder();
connectionStringBuilder.DataSource = connInfo.dbServer;
connectionStringBuilder.UserID = connInfo.dbUser;
connectionStringBuilder.Password = connInfo.dbPassword;
connectionStringBuilder.InitialCatalog = connInfo.dbName;
_dbd = new dbMSSQL(connectionStringBuilder.ConnectionString);
}
return _dbd;
}
Using all of the above, I can successfully access data in either MySQL or MSSQL:
_dbd = selectDbProvider(Id);
model = _dbd.ModelData.ToList();
However, when I try to do an update operation, I get the error message I mentioned at the top. How can I properly define my interface so that it will include the Entry method from the DbContext class?
Add a method to your interface for it.
DbEntityEntry Entry(Object entity)
https://msdn.microsoft.com/en-us/library/gg696238(v=vs.113).aspx
EDIT:
public class dbMyContext : DbContext
{
//snip
public dbMyContext(DbConnection existingConnection, boolcontextOwnsConnection) : base(existingConnection, contextOwnsConnection) { }
public dbMyContext(string connectionString) : base(connectionString) { }
//snip
}
Adjust your selectDbProvider class to use dbMyContext instead of dbMySQL and dbMSSQL.
Now you're using an O/RM properly. :)

Entity Framework 6.1 Discriminator TPH

I am looking to implement Table-per-Hierarchy using EF6 similar to the instructions found here:
example.
I have an abstract base class of User with the following derived types:
Student
Contact
Instructor
When I examine the database table Users the discriminator column value is (Undefined) when I pass a student object into my Save method below. Instead I would expect the value to be Student. Otherwise my data is saved correctly in both the Users and Students tables.
While troubleshooting the problem I added a UserType enumerator Get property to the classes to ensure that I am casting from User to Student.
In my UserRepository class my Save method is below.
public void Save(User user)
{
if (Exists(user.Id))
UpdateUser(user);
else
{
switch (user.Role)
{
case UserType.Role.Base:
_db.Users.Add(user);
break;
case UserType.Role.Student:
_db.Users.Add(user as Student);
break;
case UserType.Role.Instructor:
_db.Users.Add(user as Instructor);
break;
case UserType.Role.Contact:
_db.Users.Add(user as Contact);
break;
}
}
_db.SaveChanges();
}
Failed Alternative
I've tried code like the following to explicitly create a new Student.
private void MapToStudent(User user)
{
_db.Users.Add(new Student()
{
FirstName = user.FirstName,
LastName = user.LastName,
//...
});
}
Question
I am not downcasting correctly? Or rather what is the proper/preferred way to save subclasses using EF?
User Base Class
public abstract class User
{
public int Id { get; set; }
//...
}
internal class UserNotFound: User
{
public override UserType.Role Role
{
get
{
return UserType.Role.Base;
}
}
}
public class Student : User
{
//...
public override UserType.Role Role
{
get { return UserType.Role.Student; }
}
}
public class Contact : User
{
//...
public override UserType.Role Role
{
get { return UserType.Role.Contact; }
}
}
public class Instructor : User
{
//...
public override UserType.Role Role
{
get { return UserType.Role.Instructor; }
}
}
DatabaseContext Mapping
public class DatabaseContext : Context
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>().ToTable("Students");
modelBuilder.Entity<Contact>().ToTable("Contacts");
modelBuilder.Entity<Instructor>().ToTable("Instructors");
}
}
It appears your mappings are incorrect for TPH. The linked example in your questions shows:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BillingDetail>()
.Map<BankAccount>(m => m.Requires("BillingDetailType").HasValue("BA"))
.Map<CreditCard>(m => m.Requires("BillingDetailType").HasValue("CC"));
}
which modeled after your question might look like:
modelBuilder.Entity<User>()
.Map<Student>(m => m.Requires("Discriminator").HasValue("STU"))
.Map<Instructor>(m => m.Requires("Discriminator").HasValue("INS"));

Optimize the use of Generic Repository using linq to sql c#

I've Generic Repository Class like this:
public class Repository : IDisposable
{
public static DataContext context { get; set; }
public static void Insert<T>(T item) where T : class
{
try
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
catch (Exception)
{
throw;
}
}
public void Dispose()
{
context.Dispose();
}
}
Above one is my Generic Class for Inserting Entity using Linq to sql.
I've total 10 entities in my datacontext and i'm writing 10 Insert methods like this(Example i'm providing 3 methods).
public void AddStudent(Student st)
{
Repository.Insert<Student>(st);
}
public void AddEmployee(Employee emp)
{
Repository.Insert<Employee>(emp);
}
public void AddStudent(Product prod)
{
Repository.Insert<Product>(prod);
}
like this I've 10 methods. is there a way to optimize this code. like this
I want to create a class with Add method and i'll use this add method entire my app where ever it is required.
public class Class1
{
public void Add(Table table)
{
Repository.Insert<Table>(table);
}
}
I want to use like this Class1 cls1 = new Class1(); cls1.Add(StudentObject);
can please suggest the way to implement class.
You could define a generic class rather than just a method:
public class Repository<T> : IDisposable
{
public static DataContext context { get; set; }
public static void Insert(T item)
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
public void Dispose()
{
context.Dispose();
}
}
And you then get the following, rather than all the additional methods:
var repo = new Repository<Product>();
repo.Insert(aProduct);

Categories

Resources