Ошибки с созданием таблиц по первой модели кода с npgsql
Проблема с созданием таблиц по первой модели кода с npgsql
Создание базы данных должно работать с версии 2.2.0-бета1: "Дэвид Карлаш добавил поддержку EFMigration и создание базы данных в EF6+. Теперь можно запускать проекты Code First без необходимости заранее создавать базу данных. EntityFramework и Npgsql позаботятся об этом. Эмиль Леннгрен добавил поддержку многих недостающих функций EntityFramework. " https://www.nuget.org/packages/Npgsql/2.2.0-beta1
Но когда я попытался сделать это, я столкнулся с проблемами.
Во-первых, я сделал простой проект, который работает с SqlServer: я создал проект Asp.Net MVC (VS2013) и добавил немного кода:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
}
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
public class MovieDBInitializer : DropCreateDatabaseIfModelChanges<MovieDBContext>
{
}
public class HomeController : Controller
{
private MovieDBContext db = new MovieDBContext();
public ActionResult Index()
{
List<Movie> objs = db.Movies.ToList();
return View(objs);
}
WebConfig:
<connectionStrings>
<add name="MovieDBContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=MovieCreateDbInSql;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\MovieDB.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
<contexts>
<context type="MovieCreateDbInSql.Models.MovieDBContext, MovieCreateDbInSql">
<databaseInitializer type="MovieCreateDbInSql.Models.MovieDBInitializer, MovieCreateDbInSql" />
</context>
</contexts>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
При запуске проекта создается база данных MovieDB.
Все работает.
Мы можем увидеть эту базу данных в папке App_Data в проекте. Хорошо.
Затем я попытался сделать то же самое с npgsql.
- Добавить библиотеки:
EntityFramework6.Npgsql.dll (версия 3.1.0.0)
Npgsql.dll (версия 3.1.2.0)
2.
Чем изменить WebConfig:
<connectionStrings><add name="MovieDBContext" connectionString="Server=127.0.0.1;Port=5432;Database=postgres;User Id=postgres;Password=postgres000;" providerName="Npgsql" /></connectionStrings>
<entityFramework>
<contexts>
<context type="MovieCreateDbInSql.Models.MovieDBContext, MovieCreateDbInSql">
<databaseInitializer type="MovieCreateDbInSql.Models.MovieDBInitializer, MovieCreateDbInSql" />
</context>
</contexts>
<defaultConnectionFactory type="Npgsql.NpgsqlFactory, Npgsql" />
<providers>
<provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql"></provider>
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="Npgsql" />
<add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql"
type="Npgsql.NpgsqlFactory, Npgsql" />
</DbProviderFactories>
</system.data>
Начните. Ошибка:
System.NotSupportedException was unhandled by user code
HResult=-2146233067
Message=Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations.
Source=EntityFramework
Но такой конфигурации было достаточно для SqlServer!
Хорошо. Попробуй это:
1.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
Не очень помогает Ошибка та же
открытый класс MovieDBInitializer: DropCreateDatabaseAlways { }
Новая ошибка:
Npgsql.PostgresException was unhandled by user code
HResult=-2147467259
Message=55006: база данных "postgres" занята другими пользователями
Source=Npgsql
ErrorCode=-2147467259
BaseMessage=база данных "postgres" занята другими пользователями
Code=55006
Detail=Эта база данных используется ещё в 1 сеансе.
(error 55006 database is being accessed by other user)
Эта ошибка тоже не хорошо. Насколько я понимаю, эта ошибка связана с тем, что мы имеем серьезную базу данных posgresql в отличие от примитива localdb.sql. И удаление операции db в postgresql не так просто, как в localdb.sql.
Я нашел несколько ссылок на эту ошибку:
https://groups.google.com/forum/
Удалить базу данных, к которой обращаются другие пользователи?
Проблемы с первой установкой кода npgsql и Entity Framework
protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.SetInitializer<MovieDBContext>(null); }
Та же ошибка снова:
System.NotSupportedException was unhandled by user code
HResult=-2146233067
Message=Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations.
Source=EntityFramework
Что я должен сделать, чтобы иметь возможность создавать таблицы по первой модели кода?
Конечно, я могу создать базу данных в SqlServer и затем конвертировать скрипты в postgresql, но я хочу сделать это с помощью npgsql.
2 ответа
Библиотеки, которые я использую:
- EntityFramework.6.1.3
- EntityFramework6.Npgsql.3.1.0
- Npgsql.3.1.3
Контекст моей базы данных:
public class CustomContext : DbContext
{
public CustomContext()
: base("name=CustomContext")
{
Database.SetInitializer(
new MigrateDatabaseToLatestVersion<CustomContext, Configuration>());
}
public DbSet<Movie> Movies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Change schema name from "dbo" => "public" for all entities (except MigrationHistory).
// MigrationHistory schema name is modified in custom HistoryContext
modelBuilder.Types().Configure(c => c.ToTable(c.ClrType.Name, "public"));
}
}
В таблице истории миграции по умолчанию установлена схема "dbo". Если вы хотите, чтобы он был в другой схеме (например, общедоступной), вам нужно создать собственный HistoryContext.
В настоящее время невозможно установить схему по умолчанию с modelBuilder.HasDefaultSchema("public") при использовании автоматической миграции (AFAIK).
public class CustomHistoryContext : HistoryContext
{
public CustomHistoryContext(DbConnection existingConnection, string defaultSchema)
: base(existingConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Change schema from "dbo" to "public"
modelBuilder.Entity<HistoryRow>()
.ToTable(tableName: "__MigrationHistory",
schemaName: "public");
}
}
Наконец, мой класс конфигурации миграции выглядит так:
internal sealed class Configuration : DbMigrationsConfiguration<CustomContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
// Setting custom historyContext factory.
// Used for modify __MigrationHistory table schema name from "dbo" to "public"
this.SetHistoryContextFactory("Npgsql",
(connection, defaultSchema) =>
new CustomHistoryContext(connection, defaultSchema));
}
protected override void Seed(CustomContext context)
{
// This method will be called after migrating to the latest version.
}
}
После этих шагов автоматические коды первой миграции работают корректно.
Однако, здесь есть немного больше деталей.
У меня есть занятия:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime IssueDay { get; set; }
public decimal EarnedMoney { get; set; }
public virtual ICollection<Actor> Actors { get; set; }
}
public class Actor
{
public int ID { get; set; }
public int MovieID { get; set; }
public DateTime BirthDay { get; set; }
public string Name { get; set; }
}
И я получил сценарии:
CREATE TABLE "Movie"
(
"ID" serial NOT NULL,
"Title" text,
"IssueDay" timestamp without time zone NOT NULL DEFAULT '0001-01-01 00:00:00'::timestamp without time zone,
"EarnedMoney" numeric(18,2) NOT NULL DEFAULT 0,
CONSTRAINT "PK_public.Movie" PRIMARY KEY ("ID")
)
WITH (
OIDS=FALSE
);
ALTER TABLE "Movie"
OWNER TO postgres;
CREATE TABLE "Actor"
(
"ID" serial NOT NULL,
"MovieID" integer NOT NULL DEFAULT 0,
"Name" text,
"BirthDay" timestamp without time zone NOT NULL DEFAULT '0001-01-01 00:00:00'::timestamp without time zone,
CONSTRAINT "PK_public.Actor" PRIMARY KEY ("ID"),
CONSTRAINT "FK_public.Actor_public.Movie_MovieID" FOREIGN KEY ("MovieID")
REFERENCES "Movie" ("ID") MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
ALTER TABLE "Actor"
OWNER TO postgres;
CREATE INDEX "Actor_IX_MovieID"
ON "Actor"
USING btree
("MovieID");
И эти сценарии требуют дополнительной обработки, конечно.
Вот почему, в общем, нет никакой разницы: генерировать скрипты непосредственно в postgres или генерировать в sqlServer, а затем конвертировать в postgres, например, с помощью Navicat…