使用npgsql

时间:2016-05-30 11:27:32

标签: sql-server asp.net-mvc entity-framework postgresql npgsql

使用npgsql

代码创建表的问题

数据库创建应该从版本2.2.0-beta1开始工作: «DavidKarlaš在EF6 +中增加了对EFMigration和数据库创建的支持 现在可以启动Code First项目而无需预先创建数据库。 EntityFramework和Npgsql将负责处理它。 Emil Lenngren添加了对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做同样的事。

  1. 添加libs:
  2. 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来说已经足够了!

    确定。试试这个:

    EF5 Getting this error message: Model compatibility cannot be checked because the database does not contain model metadata

    1

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
    }
    

    不要真的帮忙。错误是相同的

    1. 公共类MovieDBInitializer:DropCreateDatabaseAlways { }

    2. 新错误:

      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。 在postgresql中删除db操作并不像在localdb.sql中那么容易。

      我找到了关于该错误的几个链接:

      https://groups.google.com/forum/#!topic/npgsql-help/1f5niOiHpGg

      Drop a database being accessed by another users?

      1. npgsql and Entity Framework code first setup problems

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer<MovieDBContext>(null);
        }
        
      2. 再次出现同样的错误:

        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 个答案:

答案 0 :(得分:1)

我使用的库:

  • 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"));
    }

}

迁移历史记录表的默认架构设置为&#34; dbo&#34;。如果你想让它在不同的模式(例如public)中,你必须创建一个自定义的HistoryContext。
目前用 modelBuilder.HasDefaultSchema(&#34)设置默认模式是不可能的。 ;公共&#34;),同时使用自动迁移(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.
    }
}

完成这些步骤后,自动代码首次迁移才能正常运行。

答案 1 :(得分:0)

但是,这里有更多细节。

我有课程:

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中生成然后通过Navicat转换为postgres没有区别...