2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Asp.net Core基于MVC框架实现PostgreSQL操作

Asp.net Core基于MVC框架实现PostgreSQL操作

时间:2023-10-13 21:19:24

相关推荐

Asp.net Core基于MVC框架实现PostgreSQL操作

简单介绍

Core最大的价值在于跨平台、跨平台、跨平台。重要的事情说三遍。但是目前毕竟是在开发初期,虽然推出了1.0.0 正式版,但是其实好多功能还没有完善。比方说编译时的一些文件编码问题,辅助工具Tools的一些Bug,还有一些好用的模板和平台实现尚未完成等一些问题。但这毕竟是一个好的开始,并且在Github上,大家都还在积极的完善,你也可以参与进来。地址:/aspnet

Core在学习的时候,首先你应该跟着微软官方的入门教材来学习,在这里:/en/latest/tutorials/first-mvc-app/start-mvc.html。这个入门教材很浅显易懂的让你了解了 Core mvc框架以及entity framework core的用法。不过缺点是,使用的是Sql compact数据库,也就是SQL Server数据库。要知道,我们使用 的主要目的是实现跨平台部署,所以数据库的选择上,首选肯定不是SqlServer,否则意义何在?当然,目前Entity Framework core暂时还不支持所有数据库。截止7月,支持情况如下:

Database Providers

The following providers are available

Microsoft SQL Server

SQLite

Npgsql (PostgreSQL)

Microsoft SQL Server Compact Edition

IBM Data Servers

InMemory (for Testing)

Devart (MySQL, Oracle, PostgreSQL, SQLite, DB2, SQL Server, and more)

MySQL (Coming Soon)

Oracle (Coming Soon)

所以提供给我们选择的数据库还是有限的(主要是不支持MySql,Devart这东西笔者不了解,不评论)。总得来说,对MS SQL Server的支持肯定是最好的,所以场景允许下,首选Sql server。其次,就DB2和PostgreSQL可选了。笔者不喜欢DB2(很多原因,主要是开发操作管理麻烦,并非说DB2本身存在问题),PostgreSQL其实也不太好用,不过谁叫他免费呢,肯定是好多国内公司首选。

PostgreSQL本身历史悠久,记得好像上世纪80年代就存在了,免费开源,而且是有专门社区维护。设计理念是以健壮性为首选,所以收到光打企业级平台欢迎。关于PostgreSQL和MySQL之间的优缺点,这个其实不太好说,MySQL在损失健壮性的同时,提高了性能,并且支持很多非标准新特性,而PostgreSQL在健壮性上,号称不弱于Oracle,性能优秀,完全支持SQL标准,所以其实并不差。

准备环境

Ubuntu Server(16.04)虚拟机1台,IP:192.168.1.6 预装了PostgreSQL数据库,并配置好防火墙,ssh连接等基础环境。确保能够外部访问。

VS Update3

Putty 和SSH Secure File Transfer Client

服务器环境部署

参考之前的博客:/lanwilliam/article/details/51880124

开始

新建项目,选择 Core Web Application项目模板。

选择Web应用程序模板,然后修改身份验证哪里,选择不进行身份验证。

这里要说一下, core项目中,包含一个Identity子项目,在GitHub上有介绍如下:

这里大家一看就知道了,这就是原来提供的自带的权限框架。这个框架现在其实非常强大了,还支持Google和TWriter等OAuth用法,不过缺点是只支持SQL Server数据库。如果选择了个人用户账户,那么会默认使用这个框架创建项目。我们希望用PostgreSQL,所以不能选他,很遗憾。而且目前创建控制器等一些内置模板用法,都是基于SqlServer,用到这个Identity,大家如果看过微软的GettingStarted,就会看到介绍,所以建议大家首先学习微软GettingStarted。

当然,不要勾选云中托管。

空白项目结构

上图是新建完成的空白项目结构,你会发现Models,Data等文件夹都不存在,这里需要手动新建,并且丢进去一个class。

必须要丢进去个class文件,让类定义的时候声明出Models和Data的命名空间,否则待会生成models文件的时候会报错。

增加项目引用

core项目有两种方法增加引用,一种是直接修改project.json,另一种是nuget。

上述方法打开控制台

输入如下命令

会发现最后的Tools安装不了,可能nuget没同步过来,可以在project.json中手动添加。

最后的文件如下:

主要是圈选中的部分。可以看到这里我们用来操作PostgreSQL的Provider是Npgsql,这是aspnet下的一个子项目。可以在github找到。

其他EntityFrameworkCore的引用,是从示例项目中搬来的。

生成Models文件

这里要说明一下,微软MVC教程中时使用的模板创建的Controller,他会自动创建ApplicationDBContext和对应的Views视图文件,以及一些其他的内容。因为他更新了ApplicationDBContext文件和ApplicationDbContextModelSnapshot文件,所以控制台执行dotnet ef命令才会正常完成,这里无法用到这些方法。因为没选"个人用户账户",这里请自行尝试。

dotnet ef migrations add Initial

dotnet ef database update

由于自行写DBContext类实现太麻烦,我们这里采取开发中常用的办法,首先设计数据库,然后根据数据库生成类。

在数据库新建表如下:(测试用,看看就好)

然后回到VS,在Nuget程序包控制台输入:

Scaffold-DbContext "Server=192.168.1.6;Database=testdb;User ID=test;Password=test;" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir Models

这个命令不用解释了吧?数据库连接,使用的数据库provider和输出目录。

顺利完成的话,Models下会出现几个类文件。

如果报错的话,请根据错误提示进行处理。处理原则,首先保证程序能够编译通过,然后确保Models下面没有存在本次要生成的同名文件,然后确认目前系统没有其他DBContext存在。现在dotnet core的好多工具都在完善中,健壮性都有待提高。

打开看看生成的文件:

usingSystem;

usingMicrosoft.EntityFrameworkCore;

usingMicrosoft.EntityFrameworkCore.Metadata;

namespacePostgresSqlDemo.Models

{

publicpartialclasstestdbContext:DbContext

{

protectedoverridevoidOnConfiguring(DbContextOptionsBuilderoptionsBuilder)

{

#warningTo protect potentially sensitive information in your connection string, you should move it out of source code. See /fwlink/?LinkId=723263 for guidance on storing connection strings.

optionsBuilder.UseNpgsql(@"Server=192.168.1.6;Database=testdb;User ID=test;Password=test;");

}

protectedoverridevoidOnModelCreating(ModelBuildermodelBuilder)

{

modelBuilder.Entity<Blog>(entity =>

{

entity.ToTable("blog");

entity.Property(e => e.Id)

.HasColumnName("id")

.ValueGeneratedNever();

entity.Property(e => e.Title)

.IsRequired()

.HasColumnName("title")

.HasColumnType("varchar")

.HasMaxLength(300);

entity.Property(e => e.Url)

.IsRequired()

.HasColumnName("url")

.HasColumnType("varchar")

.HasMaxLength(300);

});

modelBuilder.Entity<TbUser>(entity =>

{

entity.HasKey(e => e.Userid)

.HasName("PK_tb_user");

entity.ToTable("tb_user");

entity.Property(e => e.Userid)

.HasColumnName("userid")

.ValueGeneratedNever();

entity.Property(e => e.Age).HasColumnName("age");

entity.Property(e => e.Name)

.IsRequired()

.HasColumnName("name")

.HasColumnType("varchar")

.HasMaxLength(30);

});

}

publicvirtualDbSet<Blog> Blog {get;set; }

publicvirtualDbSet<TbUser> TbUser {get;set; }

}

}

Entityframework中,默认是一个数据库使用唯一一个DBContext类进行管理。

修改DBContext文件

模板已经提示给你,需要修改这部分代码,实现动态配置连接的目的。

进行如下修改:

注释掉OnConfiguring方法,增加构造函数,我们把注册放到Startup中去完成。

添加数据库连接配置项

打开appsetting.json文件,增加如下配置:

其实这就相当于原来中的Web.config中的ConnectionStrings。

注册DBContext

打开StartUP.cs 文件,找到ConfigureServices方法,添加选中代码:

到这里就看明白了吧,注册DBContext,使用Npgsql,并给出数据库连接字符串。

增加控制器Controller

在Controller文件夹下新建Controller文件,并添加如下代码:

usingMicrosoft.AspNetCore.Mvc;

usingPostgresSqlDemo.Data;

usingPostgresSqlDemo.Models;

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Threading.Tasks;

usingMicrosoft.EntityFrameworkCore;

namespacePostgresSqlDemo.Controllers

{

publicclassTbUserController:Controller

{

privatereadonlytestdbContext_context;

publicTbUserController(testdbContextcontext)

{

_context = context;

}

// GET: tbusers

publicasyncTask<IActionResult> Index()

{

returnView(await_context.TbUser.ToListAsync());

}

publicasyncTask<IActionResult> Details(Guid? id)

{

if(id ==null)

{

returnNotFound();

}

vartbuser =await_context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

if(tbuser ==null)

{

returnNotFound();

}

returnView(tbuser);

}

// GET: tbusers/Create

publicIActionResultCreate()

{

returnView();

}

// POST: tbusers/Create

// To protect from overposting attacks, please enable the specific properties you want to bind to, for

// more details see /fwlink/?LinkId=317598.

[HttpPost]

[ValidateAntiForgeryToken]

publicasyncTask<IActionResult> Create([Bind("Userid,Name,Age")]TbUsertbuser)

{

if(ModelState.IsValid)

{

tbuser.Userid =Guid.NewGuid();

_context.Add(tbuser);

await_context.SaveChangesAsync();

returnRedirectToAction("Index");

}

returnView(tbuser);

}

// GET: tbusers/Edit/5

publicasyncTask<IActionResult> Edit(Guid? id)

{

if(id ==null)

{

returnNotFound();

}

vartbuser =await_context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

if(tbuser ==null)

{

returnNotFound();

}

returnView(tbuser);

}

// POST: tbusers/Edit/5

// To protect from overposting attacks, please enable the specific properties you want to bind to, for

// more details see /fwlink/?LinkId=317598.

[HttpPost]

[ValidateAntiForgeryToken]

publicasyncTask<IActionResult> Edit(Guidid, [Bind("Userid,Name,Age")]TbUsertbuser)

{

if(id != tbuser.Userid)

{

returnNotFound();

}

if(ModelState.IsValid)

{

try

{

_context.Update(tbuser);

await_context.SaveChangesAsync();

}

catch(DbUpdateConcurrencyException)

{

if(!tbuserExists(tbuser.Userid))

{

returnNotFound();

}

else

{

throw;

}

}

returnRedirectToAction("Index");

}

returnView(tbuser);

}

// GET: tbusers/Delete/5

publicasyncTask<IActionResult> Delete(Guid? id)

{

if(id ==null)

{

returnNotFound();

}

vartbuser =await_context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

if(tbuser ==null)

{

returnNotFound();

}

returnView(tbuser);

}

// POST: tbusers/Delete/5

[HttpPost,ActionName("Delete")]

[ValidateAntiForgeryToken]

publicasyncTask<IActionResult> DeleteConfirmed(Guidid)

{

vartbuser =await_context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

_context.TbUser.Remove(tbuser);

await_context.SaveChangesAsync();

returnRedirectToAction("Index");

}

privatebooltbuserExists(Guidid)

{

return_context.TbUser.Any(e => e.Userid == id);

}

}

}

如果你看过Getting Started core MVC的话,相信应该能够看懂,基本是把使用新增Controller模板生成的方法修改了一下拿过来用了。

core mvc中,默认路由名成为(name)Controller,所以我们这里叫TbUserController,访问的时候是http://youip/TbUser这样。并且默认是触发Index方法。

Controller中,每个方法,都相当于一个客户端Form的Action。没有特殊声明的方法,默认为HttpGet,可以直接请求。需要Post数据的,请手动增加[HttpPost]声明。

Async是C# 5.0后提供的关键字,是自动实现一个异步的方法,需要配合await关键字使用。Await会被自动转换为一个async的异步请求,后面的代码,会被自动放到completed方法中执行。这样处理能够极大的提高服务器的并发性能,具体请自行学习。

增加Views页面

增加对应的页面如下:

Index.cshtml

@modelIEnumerable<PostgresSqlDemo.Models.TbUser>

@{

ViewData["Title"] ="Index";

}

<h2>Index</h2>

<p>

<aasp-action="Create">Create New</a>

</p>

<tableclass="table">

<thead>

<tr>

<th>

@Html.DisplayNameFor(model => model.Userid)

</th>

<th>

@Html.DisplayNameFor(model => model.Name)

</th>

<th>

@Html.DisplayNameFor(model => model.Age)

</th>

<th></th>

</tr>

</thead>

<tbody>

@foreach(variteminModel)

{

<tr>

<td>

@Html.DisplayFor(modelItem => item.Userid)

</td>

<td>

@Html.DisplayFor(modelItem => item.Name)

</td>

<td>

@Html.DisplayFor(modelItem => item.Age)

</td>

<td>

<aasp-action="Edit"asp-route-id="@item.Userid">Edit</a>|

<aasp-action="Details"asp-route-id="@item.Userid">Details</a>|

<aasp-action="Delete"asp-route-id="@item.Userid">Delete</a>

</td>

</tr>

}

</tbody>

</table>

Create.cshtml

@modelPostgresSqlDemo.Models.TbUser

@{

ViewData["Title"] ="Create";

}

<h2>Create</h2>

<formasp-action="Create">

<divclass="form-horizontal">

<h4>TbUser</h4>

<hr/>

<divasp-validation-summary="ModelOnly"class="text-danger"></div>

<divclass="form-group">

<labelasp-for="Name"class="col-md-2 control-label"></label>

<divclass="col-md-10">

<inputasp-for="Name"class="form-control"/>

<spanasp-validation-for="Name"class="text-danger"/>

</div>

</div>

<divclass="form-group">

<labelasp-for="Age"class="col-md-2 control-label"></label>

<divclass="col-md-10">

<inputasp-for="Age"class="form-control"/>

<spanasp-validation-for="Age"class="text-danger"/>

</div>

</div>

<divclass="form-group">

<divclass="col-md-offset-2 col-md-10">

<inputtype="submit"value="Create"class="btn btn-default"/>

</div>

</div>

</div>

</form>

<div>

<aasp-action="Index">Back to List</a>

</div>

@section Scripts {

@{awaitHtml.RenderPartialAsync("_ValidationScriptsPartial");}

}

Delete.cshtml

@modelPostgresSqlDemo.Models.TbUser

@{

ViewData["Title"] ="Delete";

}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>

<div>

<h4>Blog</h4>

<hr/>

<dlclass="dl-horizontal">

<dt>

@Html.DisplayNameFor(model => model.Userid)

</dt>

<dd>

@Html.DisplayFor(model => model.Userid)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Name)

</dt>

<dd>

@Html.DisplayFor(model => model.Name)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Age)

</dt>

<dd>

@Html.DisplayFor(model => model.Age)

</dd>

</dl>

<formasp-action="Delete">

<divclass="form-actions no-color">

<inputtype="submit"value="Delete"class="btn btn-default"/>|

<aasp-action="Index">Back to List</a>

</div>

</form>

</div>

Details.cshtml

@modelPostgresSqlDemo.Models.TbUser

@{

ViewData["Title"] ="Details";

}

<h2>Details</h2>

<div>

<h4>Blog</h4>

<hr/>

<dlclass="dl-horizontal">

<dt>

@Html.DisplayNameFor(model => model.Userid)

</dt>

<dd>

@Html.DisplayFor(model => model.Userid)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Name)

</dt>

<dd>

@Html.DisplayFor(model => model.Name)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Age)

</dt>

<dd>

@Html.DisplayFor(model => model.Age)

</dd>

</dl>

</div>

<div>

<aasp-action="Edit"asp-route-id="@Model.Userid">Edit</a>|

<aasp-action="Index">Back to List</a>

</div>

Edit.cshtml

@modelPostgresSqlDemo.Models.TbUser

@{

ViewData["Title"] ="Edit";

}

<h2>Edit</h2>

<formasp-action="Edit">

<divclass="form-horizontal">

<h4>Blog</h4>

<hr/>

<divasp-validation-summary="ModelOnly"class="text-danger"></div>

<inputtype="hidden"asp-for="Userid"/>

<divclass="form-group">

<labelasp-for="Name"class="col-md-2 control-label"></label>

<divclass="col-md-10">

<inputasp-for="Name"class="form-control"/>

<spanasp-validation-for="Name"class="text-danger"/>

</div>

</div>

<divclass="form-group">

<labelasp-for="Age"class="col-md-2 control-label"></label>

<divclass="col-md-10">

<inputasp-for="Age"class="form-control"/>

<spanasp-validation-for="Age"class="text-danger"/>

</div>

</div>

<divclass="form-group">

<divclass="col-md-offset-2 col-md-10">

<inputtype="submit"value="Save"class="btn btn-default"/>

</div>

</div>

</div>

</form>

<div>

<aasp-action="Index">Back to List</a>

</div>

@section Scripts {

@{awaitHtml.RenderPartialAsync("_ValidationScriptsPartial");}

}

增加验证脚本引用View文件

<environmentnames="Development">

<scriptsrc="~/lib/jquery-validation/dist/jquery.validate.js"></script>

<scriptsrc="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

</environment>

<environmentnames="Staging,Production">

<scriptsrc="/ajax/jquery.validate/1.14.0/jquery.validate.min.js"

asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"

asp-fallback-test="window.jQuery && window.jQuery.validator">

</script>

<scriptsrc="/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"

asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"

asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive">

</script>

</environment>

修改Layout.cshtml文件

增加如上两个连接。Blog的添加参考TbUser。这里主要是想让大家看出来DBContext的用法,所以特意弄了两个实体类。

然后vs里面可以运行了,效果如下:

这里没有改默认的页面。

再看我们加的页面。

并且 mvc默认使用了bootstrap,所以我们可以用chrome的手机模式看看。

改成中文显示

改一下TbUser.cs

usingSystem;

usingSystem.Collections.Generic;

ponentModel.DataAnnotations;

namespacePostgresSqlDemo.Models

{

publicpartialclassTbUser

{

[Display(Name ="用户编号")]

publicGuidUserid {get;set; }

[Display(Name ="用户姓名")]

publicstringName {get;set; }

[Display(Name ="用户年龄")]

publicint? Age {get;set; }

}

}

再看看页面

加一下验证

改成中文验证

[Display(Name ="用户姓名")]

[StringLength(10, MinimumLength = 3,ErrorMessage ="字段{0}长度不能小于3,总长度不能大于10")]

[Required]

publicstringName {get;set; }

最后就是部署到Ubuntu服务器了。

将WebApp项目发布出来,使用SSH Secure File Transfer上传到服务器,然后参照前文发布。

前文:/lanwilliam/article/details/51880124

总结:

Core 目前来说功能性还不完善,暂时不建议大型应用往上迁移,但是如果是小型项目,比较简单,可以在仔细论证后尝试使用。注意仔细论证,因为目前.net core并不是所有类库都能够实现跨平台。简单来说,System.Drawing就无法使用,所以后台画水印就需要其他三方库,这个请自行仔细论证。不过小项目发布到linux虚拟机上面,确实可以省一笔钱。

原文地址:/lanwilliam/p/5663931.html

.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。