在使用asp.net mvc进行定义 模型类的时候,一般情况下,我们都会定义一个属性为 int iD{get;set;} 或为int ClassNameID {get;set;},在这种情况下

1、Int类型主键

EF的默认约定就是第一个属性如果是类名+id或是id(这两情况下id字母大小写没有关系),并且是int类型的,那么直接设置第一个属性为主键,同时设置自增长。不需要指定[Key]关键字(在 System.ComponentModel.DataAnnotations.Schema命名空间下面)

比如:

public class Person
{
public int ID { get; set; }

public string Name { get; set; }

public int Price { get; set; }

public DateTime Birthday { get; set; }
}

或为

public class Person
{
public int PersonId { get; set; }

public string Name { get; set; }

public decimal Price { get; set; }

public DateTime Birthday { get; set; }
}

此时,如果用脚手架自动创建控制器和视图中,因id或classid已经被认为是主键了,属性在create,index视图中不会显示。

如果在字段加入了[DatabaseGenerated(DatabaseGeneratedOption.None)] 的数据注解,让你自己输入主键值而不是数据库自动创建它。

在新建和编辑视图中自动会将id字段显示出来,供用户输入 。

2、GUiD主键

模型:

public class Person
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]   //此数据注解并可表示可以在数据库中自动生成 GUID值,只是告诉基架 在操作方法中生成创建GUID值的代码。如person.PersonID = Guid.NewGuid();   
public Guid PersonID { get; set; }

public string Name { get; set; }

public int Price { get; set; }

public DateTime Birthdaey { get; set; }

}

利用基架自动创建控制器和视图:

public ActionResult Create()
{
return View();
}

// POST: People/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "PersonID,Name,Price,Birthdaey")] Person person)
{
if (ModelState.IsValid)
{
person.PersonID = Guid.NewGuid();        //基架增加自动创建的代码,指定PersonID GUID属性值。
db.People.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(person);
}

视图:基架生成的视图中已经没有了PersonID 的表单值,因为模型中已经注明 了有数据库自动创建。

using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
<h4>Person</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })

<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>

<div class="form-group">
@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</div>
</div>

3、string类型主键,如果一个模型的属性名为ID或classNameID 它总被认为主键,在映射到数据库总是为主键值,也不需要Key数据注解。不管它的类型是int 还是string,还是GUID。如果是int型,被认为是自增长,自动生成的创建编辑视图不会显示此字段。如果是string类型,不会自增长,需要用户输入或指定,自动生成的创建编辑视图会显示此字段,提示用户输入。

第一种方式:给模型创建一个构造函数指定PersonID为GUID字符串,在Create 视图中,删除脚手架自动生成的PerosnID 表单字段值。在Creater的POST方法中模型绑定自动生成一个Person对象,它的PersonID=GUID的值。这是使用主键类型为string的最佳实践。

模型:

public class Person
{
public string PersonID { get; set; } //由于属性名 为classNameID ,因此被认为主键。但是它不会自增长。需要用户自行生成。

public string Name { get; set; }

public decimal Price { get; set; }

public DateTime Birthday { get; set; }

public Person()
{
PersonID = Guid.NewGuid().ToString();
}

控制器:

// GET: People/Create
public ActionResult Create()
{
return View();
}

// POST: People/Create
// 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
// 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "PersonID,Name,Price,Birthday")] Person person)//是否绑定PersonID都不影响。
{
if (ModelState.IsValid)  //模型绑定将自动创建一个Person对象,调用Person的构造函数生成GuiD 主键值。
{
db.People.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(person);
}

视图:删除自动生成的PerserID表单字段。

@using (Html.BeginForm()) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
<h4>Person</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })   //删除PersonID的表单字段,如果不删除,那么PersonID的值就会要求手动输入,不输入就会绑定到POST方法中的PersonID为空值,保存的数据库就会出错。

<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>

<div class="form-group">
@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</div>
</div>

在Asp.net Identity 中默认使用的String 类型的主键值,也是相同的实现方法。只不过,我们在访问Applicationuser 的时候绑定用的大多数是ViewModel,而不是直接的ApplicationUser或基类IdentityUser 类。

查看到ApplicationUser class(和用户相关的类)继承了IdentityUser.cs (位于Microsoft.Asp.Net.Identity.EntityFramework.dll) 反编译后源码如下:

 1 namespace Microsoft.AspNet.Identity.EntityFramework
2 {
3 using Microsoft.AspNet.Identity;
4 using System;
5
6 public class IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
7 {
8 public IdentityUser()
9 {
10 this.Id = Guid.NewGuid().ToString();
11 }
12
13 public IdentityUser(string userName) : this()
14 {
15 this.UserName = userName;
16 }
17 }
18 }

观察 IdentityUser.cs 它有继承了IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>这个泛型,所以我们也需要有对应的Int类型的 IdentityUserLogin, IdentityUserRole, IdentityUserClaim泛型类。

第二种方式:直接在控制器Crate POST方法中指定一个PersonID 值。

模型类保持不变,不使用构造函数

public class Person
{
public string PersonID { get; set; }

public string Name { get; set; }

public decimal Price { get; set; }

public DateTime Birthday { get; set; }

}

控制器:

Create 的Get方法保持与脚手架一致,不作改动。

POst方法去除对PersonID的绑定,(不去也无所谓。)

public ActionResult Create()
{
return View();
}

// POST: People/Create
// 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关
// 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Name,Price,Birthday")] Person person)  
{
if (ModelState.IsValid)
{
person.PersonID = Guid.NewGuid().ToString();     //在POST方法中创建一个GUID值,转换成字符串,并赋值给PersonID属性。
db.People.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(person);
}

视图中删去显示输入PersornID的表单字段。

第三种方式:在Create Get方法中创建一个空的对象,自动调用构造函数生成主键值,返给视图,然后提交表单,将ID值通过模型绑定再传给Create Post方法。这种方式相对于前两种方式暴露给了用户GUID的值了。

控制器:

模型

public class Person
{
public string PersonID { get; set; }  //由于属性名  为classNameID ,因此被认为主键。但是它不会自增长。需要用户自行生成。

public string Name { get; set; }

public decimal Price { get; set; }

public DateTime Birthday { get; set; }

public Person()
{
PersonID = Guid.NewGuid().ToString();

}

public ActionResult Create()
{
Person person = new Person();  //可以在脚手架代码加入此项,调用 自定义的构造函数给 Create视图中的对象返回一个GUID值。
return View(person);
}

// POST: Desks/Create

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = PersonID,Name,Price,Birthday")] Person person) //绑定表单传过来的personID值。
{
if (ModelState.IsValid)
{
db.People.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(person);
}

}

Create视图代码:

@Html.ValidationSummary(true, "", new { @class = "text-danger" })

<div class="form-group">
@Html.LabelFor(model => model.PersonID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.PersonID, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.PersonID, "", new { @class = "text-danger" })
</div>
</div>

为了不让主键字段在Create 视图中显示,可以使用@html.HiddenFor(model =>model.personID) 辅助方法代替上面的视图代码。

总结:在使用asp.net MVC codefirst进行开的时候,模型POCO类的主键可定义为int类型,GUID类型(避免主键值在各表中重复,String类型(由GUID值转换)。可以方便的利用基架自动生成 控制器的CRUD操作方法和相应的视图。

如果一个模型的属性名为ID或classNameID 它总被认为主键,在映射到数据库总是为主键值,也不需要Key数据注解。

asp.net MVC Model 类的主键 int类型、string类型、GUID类型。的更多相关文章

  1. ASP.NET MVC Model验证(三)

    ASP.NET MVC Model验证(三) 前言 上篇中说到在MVC框架中默认的Model验证是在哪里验证的,还讲到DefaultModelBinder类型的内部执行的示意图,让大家可以看到默认的M ...

  2. ASP.NET MVC Model绑定(二)

    ASP.NET MVC Model绑定(二) 前言 上篇对于Model绑定的简单演示想必大家对Model绑定的使用方式有一点的了解,那大家有没有想过Model绑定器是在什么时候执行的?又或是执行的过程 ...

  3. ASP.NET MVC Model元数据(五)

    ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...

  4. ASP.NET MVC Model验证(五)

    ASP.NET MVC Model验证(五) 前言 上篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现, 然而在MVC框架中还给我们提供了其它 ...

  5. ASP.NET MVC Model验证(四)

    ASP.NET MVC Model验证(四) 前言 本篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而Mod ...

  6. ASP.NET MVC Model验证(二)

    ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决这个问题的,并且会描述一下 ...

  7. ASP.NET MVC Model验证(一)

    ASP.NET MVC Model验证(一) 前言 前面对于Model绑定部分作了大概的介绍,从这章开始就进入Model验证部分了,这个实际上是一个系列的Model的绑定往往都是伴随着验证的.也会在后 ...

  8. ASP.NET MVC Model绑定(六)

    ASP.NET MVC Model绑定(六) 前言 前面的篇幅对于IValueProvider的使用做个基础的示例讲解,但是没并没有对 IValueProvider类型的实现做详细的介绍,然而MVC框 ...

  9. ASP.NET MVC Model绑定(五)

    ASP.NET MVC Model绑定(五) 前言 前面的篇幅对于IValueProvider的获取位置和所处的生成过程做了讲解,本篇将会对IValueProvider的使用做个基础的示例讲解,读完本 ...

随机推荐

  1. 【Java源码】集合类-LinkedList

    一.类继承关系 LinkedList和ArrayList都实现了List接口.所以有List的特性,同时LinkedList也实现了Deque,所以它也具有双端队列和栈的特性. public clas ...

  2. 洛谷—— P1133 教主的花园

    https://www.luogu.org/problem/show?pid=1133 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都 ...

  3. 几道hash题

    1: UVa 10887 - Concatenation of Languages map 可以做 ,但是输入实在恶心,有空串之类的HASH模板: int Hash(char *s){   int s ...

  4. [Bzoj3631][JLOI2014]松鼠的新家 (树上前缀和)

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2350  Solved: 1212[Submit][Sta ...

  5. Javascript小数取整方法收集

    1.丢弃小数部分,保留整数部分 parseInt(7/2) 2.向上取整,有小数就整数部分加1 Math.ceil(7/2) 3.四舍五入 Math.round(7/2) 4.向下取整 Math.fl ...

  6. 前端开发数据mock神器 -- xl_mock

    1.为什么要实现数据 mock 要理解为什么要实现数据 mock,我们可以提供几个场景来解释, 1.现在的开发很多都是前后端分离的模式,前后端的工作是不同的,当我们前端界面已经完成,但是后端的接口迟迟 ...

  7. DATASNAP高效的FIREDAC数据序列和还原

    变量定义: varFDConnection: TFDConnection;qCustomers: TFDQuery; qOrders: TFDQuery;FDSchemaAdapter: TFDSch ...

  8. 【APUE】一个fork的面试题及字符设备、块设备的区别

    具体内容见:http://coolshell.cn/articles/7965.html 字符设备.块设备主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,而块设备则不然, ...

  9. iOS国际化:NSLocalizedString的使用

    因为iOS和XCode版本号更新得太快的原因,导致网上非常多文章都失去了时效性,或许再过两三个月我这篇文章也将走上这条路,但起码能够让现阶段看到的人对iOS的国际化有个比較清楚的认识. NSLocal ...

  10. android事件分发(二)

    非常早之前写过一篇android事件分发的博客,主要写的是它是怎样分发的,具体非常多原理的东西都没有涉及到.今天就从源代码看android怎样控制它的分发机制. 鉴于手机屏幕的限制,所以android ...