当值不为 Null 时,MVC Identity 想要将 Null 插入 table
MVC Identity wants to insert Null into table when value is not Null
我最近刚刚发布了一个关于 的问题,现在这个问题由此而来:
现在 ApplicationUser
的 FirstName
和 LastName
属性是 AspNetUsers table 中的字段。但是当我去注册为新用户时,我得到这个错误:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into
column 'LastName', table
'aspnet-CustomUserProps-20151019035309.dbo.AspNetUsers'; column does
not allow nulls. INSERT fails.
这是我在 AccountController
中的注册 Post:
Public Async Function Register(model As RegisterViewModel) As Task(Of ActionResult)
If ModelState.IsValid Then
Dim user = New ApplicationUser() With {
.UserName = model.Email,
.Email = model.Email,
.FirstName = model.FirstName,
.LastName = model.LastName
}
Dim result = Await UserManager.CreateAsync(user, model.Password)
用户 DO 的 FirstName
和 LastName
属性包含预期值,但此错误发生在“Dim result =
...”行。
我在注册视图中添加了名字和姓氏字段,如下所示:
<div class="form-group">
@Html.LabelFor(Function(m) m.Email, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.Email, New With {.class = "form-control"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(m) m.FirstName, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.FirstName, New With {.class = "form-control"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(m) m.LastName, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.LastName, New With {.class = "form-control"})
</div>
</div>
然后像这样注册视图模型:
<Required>
<Display(Name:="First Name")>
Public Property FirstName As String
<Required>
<Display(Name:="Last Name")>
Public Property LastName As String
我还缺少什么?
这里是堆栈跟踪的顶部(最后)几行,如果有帮助的话:
[SqlException (0x80131904): Cannot insert the value NULL into column
'LastName', table
'aspnet-CustomUserProps-20151019035309.dbo.AspNetUsers'; column does
not allow nulls. INSERT fails. The statement has been terminated.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection, Action'1 wrapCloseInAction) +1787814
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection, Action'1 wrapCloseInAction)
+5341674 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +546
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj, Boolean& dataReady) +1693
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) +275
System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader() +220
System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult
asyncResult) +738
System.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult
asyncResult) +147
它必须是您将额外列添加到身份数据库的方式。
您需要扩展 IdentityUser
并重新定义 DbContext
,方法是使用新的扩展 IdentityUser
class 作为其通用参数从 IdentityDbContext
扩展.操作方法如下:
Public Class YourApplicationUser
Inherits IdentityUser
Public Property LastName() As String
Get
Return m_LastName
End Get
Set
m_LastName = Value
End Set
End Property
Private m_LastName As String
Public Function GenerateUserIdentityAsync(manager As UserManager(Of YourApplicationUser)) As Task(Of ClaimsIdentity)
' Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me, DefaultAuthenticationTypes.ApplicationCookie)
' Add custom user claims here
Return userIdentity
End Function
End Class
Public Class YourApplicationIdentityDbContext
Inherits IdentityDbContext(Of YourApplicationUser)
Public Sub New()
MyBase.New("IdentityConnection", throwIfV1Schema := False)
End Sub
Public Shared Function Create() As YourApplicationIdentityDbContext
Return New YourApplicationIdentityDbContext()
End Function
Protected Overrides Sub OnModelCreating(modelBuilder As System.Data.Entity.DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
modelBuilder.Entity(Of YourApplicationIdentityDbContext)().ToTable("IdentityUser").[Property](Function(p) p.Id).HasColumnName("UserId")
modelBuilder.Entity(Of IdentityUserRole)().ToTable("IdentityUserRole").HasKey(Function(p) New From { _
p.RoleId, _
p.UserId _
})
modelBuilder.Entity(Of IdentityUserLogin)().ToTable("IdentityUserLogin").HasKey(Function(p) New From { _
p.LoginProvider, _
p.ProviderKey, _
p.UserId _
})
modelBuilder.Entity(Of IdentityUserClaim)().ToTable("IdentityUserClaim").HasKey(Function(p) p.Id).[Property](Function(p) p.Id).HasColumnName("UserClaimId")
modelBuilder.Entity(Of IdentityRole)().ToTable("IdentityRole").[Property](Function(p) p.Id).HasColumnName("RoleId")
End Sub
End Class
请注意,这还允许您将数据库 table 名称更改为您选择的任何名称 - 因为您使用自己的 DbContext 覆盖。
感谢 A. Burak Erbora - 您的建议确实让我走上了正确的道路。但是我做的不完全一样...有点不同:
从头开始一个新项目,首先我创建了一个新用户 class 和上下文,但没有 OnModelCreating 函数:
Imports Microsoft.AspNet.Identity.EntityFramework
Imports System.Threading.Tasks
Imports System.Security.Claims
Imports Microsoft.AspNet.Identity
Public Class AppUser
Inherits IdentityUser
Private m_FirstName As String
Public Property FirstName() As String
Get
Return m_FirstName
End Get
Set(value As String)
m_FirstName = value
End Set
End Property
Private m_LastName As String
Public Property LastName() As String
Get
Return m_LastName
End Get
Set(value As String)
m_LastName = value
End Set
End Property
Public Async Function GenerateUserIdentityAsync(manager As UserManager(Of AppUser)) As Task(Of ClaimsIdentity)
' Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me, DefaultAuthenticationTypes.ApplicationCookie)
' Add custom user claims here
Return userIdentity
End Function
End Class
Public Class MyAppIdentityDbContext
Inherits IdentityDbContext(Of AppUser)
Public Sub New()
MyBase.New("IdentityConnection", throwIfV1Schema:=False)
End Sub
Public Shared Function Create() As MyAppIdentityDbContext
Return New MyAppIdentityDbContext()
End Function
End Class
然后我删除了 IdentityModels(AppUser 替换了它)。
是否在项目范围内将 "ApplicationUser" 全部替换为 "AppUser"。
然后在项目范围内将所有 "ApplicationDbContext" 替换为 "MyAppIdentityDbContext"。
确保在 Web.config 中 connectionString 的名称与新上下文 ("IdentityConnection") 的名称相同。
修改了 RegisterViewModel、Register View 和 Account Controller 以包含添加到 AppUser 的字段。
从那里所有用户的东西都是一样的。例如,我想在用户登录时在导航栏中显示名字而不是电子邮件地址,所以这是 _LoginPartial 视图:
@Imports Microsoft.AspNet.Identity
@Code
Dim db = New MyAppIdentityDbContext
Dim curUserID = User.Identity.GetUserId()
Dim myFirstName As String = (From users In db.Users Where users.Id = curUserID Select users.FirstName).FirstOrDefault
End Code
@If Request.IsAuthenticated
@Using Html.BeginForm("LogOff", "Account", FormMethod.Post, New With { .id = "logoutForm", .class = "navbar-right" })
@Html.AntiForgeryToken()
@<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " + myFirstName + "!", "Index", "Manage", routeValues:=Nothing, htmlAttributes:=New With {.title = "Manage"})
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
End Using
Else
@<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("Register", "Register", "Account", routeValues := Nothing, htmlAttributes := New With { .id = "registerLink" })</li>
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues := Nothing, htmlAttributes := New With { .id = "loginLink" })</li>
</ul>
End If
我最近刚刚发布了一个关于
现在 ApplicationUser
的 FirstName
和 LastName
属性是 AspNetUsers table 中的字段。但是当我去注册为新用户时,我得到这个错误:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'LastName', table 'aspnet-CustomUserProps-20151019035309.dbo.AspNetUsers'; column does not allow nulls. INSERT fails.
这是我在 AccountController
中的注册 Post:
Public Async Function Register(model As RegisterViewModel) As Task(Of ActionResult)
If ModelState.IsValid Then
Dim user = New ApplicationUser() With {
.UserName = model.Email,
.Email = model.Email,
.FirstName = model.FirstName,
.LastName = model.LastName
}
Dim result = Await UserManager.CreateAsync(user, model.Password)
用户 DO 的 FirstName
和 LastName
属性包含预期值,但此错误发生在“Dim result =
...”行。
我在注册视图中添加了名字和姓氏字段,如下所示:
<div class="form-group">
@Html.LabelFor(Function(m) m.Email, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.Email, New With {.class = "form-control"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(m) m.FirstName, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.FirstName, New With {.class = "form-control"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(m) m.LastName, New With {.class = "col-md-2 control-label"})
<div class="col-md-10">
@Html.TextBoxFor(Function(m) m.LastName, New With {.class = "form-control"})
</div>
</div>
然后像这样注册视图模型:
<Required>
<Display(Name:="First Name")>
Public Property FirstName As String
<Required>
<Display(Name:="Last Name")>
Public Property LastName As String
我还缺少什么?
这里是堆栈跟踪的顶部(最后)几行,如果有帮助的话:
[SqlException (0x80131904): Cannot insert the value NULL into column 'LastName', table 'aspnet-CustomUserProps-20151019035309.dbo.AspNetUsers'; column does not allow nulls. INSERT fails. The statement has been terminated.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action'1 wrapCloseInAction) +1787814
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action'1 wrapCloseInAction) +5341674 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +546
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +1693
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +275
System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader() +220
System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult) +738
System.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult) +147
它必须是您将额外列添加到身份数据库的方式。
您需要扩展 IdentityUser
并重新定义 DbContext
,方法是使用新的扩展 IdentityUser
class 作为其通用参数从 IdentityDbContext
扩展.操作方法如下:
Public Class YourApplicationUser
Inherits IdentityUser
Public Property LastName() As String
Get
Return m_LastName
End Get
Set
m_LastName = Value
End Set
End Property
Private m_LastName As String
Public Function GenerateUserIdentityAsync(manager As UserManager(Of YourApplicationUser)) As Task(Of ClaimsIdentity)
' Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me, DefaultAuthenticationTypes.ApplicationCookie)
' Add custom user claims here
Return userIdentity
End Function
End Class
Public Class YourApplicationIdentityDbContext
Inherits IdentityDbContext(Of YourApplicationUser)
Public Sub New()
MyBase.New("IdentityConnection", throwIfV1Schema := False)
End Sub
Public Shared Function Create() As YourApplicationIdentityDbContext
Return New YourApplicationIdentityDbContext()
End Function
Protected Overrides Sub OnModelCreating(modelBuilder As System.Data.Entity.DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
modelBuilder.Entity(Of YourApplicationIdentityDbContext)().ToTable("IdentityUser").[Property](Function(p) p.Id).HasColumnName("UserId")
modelBuilder.Entity(Of IdentityUserRole)().ToTable("IdentityUserRole").HasKey(Function(p) New From { _
p.RoleId, _
p.UserId _
})
modelBuilder.Entity(Of IdentityUserLogin)().ToTable("IdentityUserLogin").HasKey(Function(p) New From { _
p.LoginProvider, _
p.ProviderKey, _
p.UserId _
})
modelBuilder.Entity(Of IdentityUserClaim)().ToTable("IdentityUserClaim").HasKey(Function(p) p.Id).[Property](Function(p) p.Id).HasColumnName("UserClaimId")
modelBuilder.Entity(Of IdentityRole)().ToTable("IdentityRole").[Property](Function(p) p.Id).HasColumnName("RoleId")
End Sub
End Class
请注意,这还允许您将数据库 table 名称更改为您选择的任何名称 - 因为您使用自己的 DbContext 覆盖。
感谢 A. Burak Erbora - 您的建议确实让我走上了正确的道路。但是我做的不完全一样...有点不同:
从头开始一个新项目,首先我创建了一个新用户 class 和上下文,但没有 OnModelCreating 函数:
Imports Microsoft.AspNet.Identity.EntityFramework
Imports System.Threading.Tasks
Imports System.Security.Claims
Imports Microsoft.AspNet.Identity
Public Class AppUser
Inherits IdentityUser
Private m_FirstName As String
Public Property FirstName() As String
Get
Return m_FirstName
End Get
Set(value As String)
m_FirstName = value
End Set
End Property
Private m_LastName As String
Public Property LastName() As String
Get
Return m_LastName
End Get
Set(value As String)
m_LastName = value
End Set
End Property
Public Async Function GenerateUserIdentityAsync(manager As UserManager(Of AppUser)) As Task(Of ClaimsIdentity)
' Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me, DefaultAuthenticationTypes.ApplicationCookie)
' Add custom user claims here
Return userIdentity
End Function
End Class
Public Class MyAppIdentityDbContext
Inherits IdentityDbContext(Of AppUser)
Public Sub New()
MyBase.New("IdentityConnection", throwIfV1Schema:=False)
End Sub
Public Shared Function Create() As MyAppIdentityDbContext
Return New MyAppIdentityDbContext()
End Function
End Class
然后我删除了 IdentityModels(AppUser 替换了它)。
是否在项目范围内将 "ApplicationUser" 全部替换为 "AppUser"。
然后在项目范围内将所有 "ApplicationDbContext" 替换为 "MyAppIdentityDbContext"。
确保在 Web.config 中 connectionString 的名称与新上下文 ("IdentityConnection") 的名称相同。
修改了 RegisterViewModel、Register View 和 Account Controller 以包含添加到 AppUser 的字段。
从那里所有用户的东西都是一样的。例如,我想在用户登录时在导航栏中显示名字而不是电子邮件地址,所以这是 _LoginPartial 视图:
@Imports Microsoft.AspNet.Identity
@Code
Dim db = New MyAppIdentityDbContext
Dim curUserID = User.Identity.GetUserId()
Dim myFirstName As String = (From users In db.Users Where users.Id = curUserID Select users.FirstName).FirstOrDefault
End Code
@If Request.IsAuthenticated
@Using Html.BeginForm("LogOff", "Account", FormMethod.Post, New With { .id = "logoutForm", .class = "navbar-right" })
@Html.AntiForgeryToken()
@<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " + myFirstName + "!", "Index", "Manage", routeValues:=Nothing, htmlAttributes:=New With {.title = "Manage"})
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
End Using
Else
@<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("Register", "Register", "Account", routeValues := Nothing, htmlAttributes := New With { .id = "registerLink" })</li>
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues := Nothing, htmlAttributes := New With { .id = "loginLink" })</li>
</ul>
End If