I have a number of pending changes in my object context when I call SaveChanges. Somewhere in there is an entity with a value for a column that is too long. This results in SqlException: String or binary data would be truncated.
The question is how do I determine offending entity/column?
You could consider using DataAnnotations and building your Buddy Classes for validation. Then you display a friendly validation errors to your user if their data is incorrect.
Imports System.ComponentModel.DataAnnotations
Namespace Domain
#Region "Validation"
<MetadataType(GetType(UserMetaData))> _
Partial Public Class User
End Class
''' <summary>
''' Validation for all User data.
''' </summary>
''' <remarks>All validation is done at the Service Layer</remarks>
Public Class UserMetaData
<DisplayName("name")> _
<Required(ErrorMessage:="Username is required.")> _
<StringLength(30, ErrorMessage:="Username cannot exceed 30 characters.")> _
<RegularExpression("^\w{3,30}$", ErrorMessage:="Not a valid username.")> _
Public Property UserName As String
<DisplayName("email")> _
<StringLength(50, ErrorMessage:="Email Address cannot exceed 50 characters.")> _
<RegularExpression("^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})$", ErrorMessage:="Not a valid email address.")> _
Public Property Email As String
<DisplayName("website")> _
<StringLength(256, ErrorMessage:="Web Address cannot exceed 256 characters.")> _
<RegularExpression("^http(s?)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$", ErrorMessage:="Not a valid website address.")> _
Public Property WebSite As String
<DisplayName("about")> _
<StringLength(2000, ErrorMessage:="Profile cannot exceed 2000 characters.")> _
Public Property About As String
<DisplayName("region")> _
<Required(ErrorMessage:="Region is required.")> _
Public Property UserRegion As Integer
<DisplayName("birthdate")> _
<DisplayFormat(ApplyFormatInEditMode:=True, ConvertEmptyStringToNull:=True, DataFormatString:="{0:MM/dd/yyyy}")> _
Public Property BirthDate As DateTime
End Class
#End Region
End Namespace
More references
http://adventuresdotnet.blogspot.com/2009/08/aspnet-webforms-validation-with-data.html
http://blogs.msdn.com/b/jimoneil/archive/2008/07/08/dynamic-data-annotations.aspx
http://www.ipreferjim.com/site/2010/05/system-componentmodel-dataannotations-for-asp-net-web-forms/
SQL Profiler.
Related
Is there any way to use Strongly-Typed values in Examples table of the scenario? (or alternative solution)
I'd like to know if I made a typo in userType column already during the coding (not during running the test).
UPDATED
file.feature
Scenario Outline: Scenario123
Given Create new user of type "<userType>"
Examples:
| userType |
| PlatinumUser |
| CommonUser |
steps.cs
[Given(#"Create new user of type ""(.*)""")]
public void CreateNewUser(UserTypeEnum userType)
{
// some code like e.g.:
MyUser user = new MyUser(userType);
//...
}
enum UserTypeEnum { CommonUser, PlatinumUser, Spectre }
Looks like its a StepArgumentTransformation that you are after?
https://github.com/techtalk/SpecFlow/wiki/Step-Argument-Conversions
Used somehow along these lines:
[Binding]
public class Transforms
{
[StepArgumentTransformation]
public UserTypeEnum UserTypeTransform(string UserType)
{
// return the string converted into the required Enum
}
}
The step binding will see that it requires a UserTypeEnum as a parameter so it will search for all the available Step Argument Transformations within any classes with the Binding attribute and use this method to perform the conversion.
Specflow supports accepting strongly typed enum values.
Though, the scenario sends it as text (case insensitive).
example:
Scenario: Some enum test
When I send enum "Second"
Then I get the second enum
public enum ChosenOption
{
First,
Second,
Third,
}
[When(#"I send enum ""(.*)""")]
public void WhenISendEnum(ChosenOption option)
{
_scenarioContext.Set(option, nameof(ChosenOption));
}
[Then(#"I get the second enum")]
public void ThenIGetTheSecondEnum()
{
var chosen = _scenarioContext.Get<ChosenOption>(nameof(ChosenOption));
chosen.Should().Be(ChosenOption.Second);
}
I'm implementing Audit Logging 1.1 Grails Plugin to track the changes to my domain classes midway of our project implementation. These are an example domain object for our scenario:
Students need to answer questions. A question can ask for a single or a multiple answers.
class Question {
static auditable = true
Integer id
String content
static hasMany = [
answers: Answer
]
}
class Student {
static auditable = true
Integer id
String name
static hasMany = [
answers: Answer
]
}
class Answer implements Serializable {
static auditable = true
Integer sequence
String value
static belongsTo = [
student: Student,
question: Question
]
static mapping = {
id composite: ["student", "question", "sequence"]
}
}
Every time I perform insert/updates to any of these tables, the plugin fires an event and logs it to my AuditLog table. All DML are successfully logged as expected except for the Answer table. The problem is that the PERSISTED_OBJECT_ID is always null:
+----+---+------------+------------+---------------------+---------------+-----------+-----------+
| ID | … | CLASS_NAME | EVENT_NAME | PERSISTED_OBJECT_ID | PROPERTY_NAME | OLD_VALUE | NEW_VALUE |
+----+---+------------+------------+---------------------+---------------+-----------+-----------+
| … | … | Answer | UPDATE | | value | A | B |
| … | … | Answer | UPDATE | | value | B | A |
+----+---+------------+------------+---------------------+---------------+-----------+-----------+
I tried to include the logIds = true config but it still not persisting. Without that column, I cannot identify which Answer is updated by whom. I'm expecting that this would be the case of all the composite primary keys domain classes that I have.
What can I do to fix this?
I had the same issue with 2.x plugin version when my new/oldValue was domain class object. I decided it by overriding toString() method for domain which was saved as value. Try to override toString() for your "student" and "question" domain.
Update:
I didn't use composite key as Id in my project (it seems it's why your persistedObjectId is empty) and also I used 2.x version of plugin. My decision for problems which looks like your, may be it will help you :
I have domains:
class Manager {
}
class Customer {
}
class Item {
Manager manager
Customer customer
Item parentItem
BigDecimal qtyOnHand
}
I log changes of qtyOnHand and parentItem. With first everything is easy. For second (as I remember default value will be smth like this: "[id:15]Object123402"):
1. overrided toString()
public String toString() {
id
}
2. in configurations: logIds = false => plugin writes only id of object
Also I log managerId and customerId using "uri" for it (for simple it will be):
def getAuditLogUri = {
managerId as String
}
We can write all in uri and than past in beforeInsert:
class Item {
......
def getAuditLogUri = {
getAuditFields()
}
private Map getAuditFields() {
return [managerId: manager.id, customerId: customer.id]
}
....
}
class AuditLog{
String actor
String uri
String className
String persistedObjectId
String propertyName
String oldValue
String newValue
String managerId
String customerId
.....
def beforeInsert() {
getAdditionalFields(uri)
}
private void getAdditionalFields(String fields) {
Map map = Eval.me(fields)
managerId = map.managerId
customerId = map.customerId
}
Everything works in my project, I think the it will work the same for persistedObjectId-field
I have created new MVC project with internet template.
Now I would like to change default required message from "Username is to required" to some text in my language.
But when I try to enter string in required attribute compiler complains with message in title.
Example:
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports System.Globalization
Public Class LogOnModel
Private userNameValue As String
<DisplayName("Banana split")> _
<Required("Text in my language")> _
Public Property UserName() As String
Get
Return userNameValue
End Get
Set(ByVal value As String)
userNameValue = value
End Set
End Property
End Class
I have also tried to put something like:
<Required(ErrorMessage="Text")
This is the correct syntax, notice the : before =
<Required(ErrorMessage:="Text in my language")>
In my unit test under grails 2.2.4 I'm attempting to pass in an invalid enum to see if it gets rejected. It does not.
Here is my enum:
public enum CertificationStatus {
N("No"),
Y("Yes - Unverified"),
V("Yes - Verified")
final String value
CertificationStatus(String value) {
this.value = value
}
public String toString() {
value
}
public String getKey() {
name()
}
public String getValue() {
value
}
}
Here is my domain:
class Profile
CertificationStatus certFosterCertified
static constraints = {
certFosterCertified(blank: true, nullable: true)
}
Here is the unit test:
instance = new Profile(certFosterCertified: '#')
assertFalse instance.validate(['certFosterCertified'])
assertNotNull instance.errors.getFieldError('certFosterCertified')
The instance.validate returns true, but I'm passing in an invalid value for the enum in the Profile constructor ('#'). Shouldn't the validate fail because of the invalid enum? The enum is setup with only Y,N, and V as valid values. I didn't think I had to set those in the constraint because the field is defined as an enum.
With the constructor you set the value of certBackgroundCheck to #.
However, in your domain class your enum is named certFosterCertified. So certFosterCertified should be null, because it isn't initialized. According to the constraints null is a valid state (nullable: true).
Maybe you just need to change certBackgroundCheck to certFosterCertified?
My controller has an object as parameter
Function Search(ByVal model As ItemSearchModel) As ActionResult
Which look something like this
Public Class ItemSearchModel
Public Property SearchQuery As String
And, as you can imagine, the url will look this like
/Search?SearchQuery=test
I want to change the query string to have a small variable, sort of like
/Search?s=test
Is there a built-in way I could keep the same variable name in my class? Something like
Public Class ItemSearchModel
<QueryString(Name:="s")> _
Public Property SearchQuery As String
I think you can use the ActionParameterAlias package from Nuget to accomplish what you want.
You can define two properties, both pointing to the same field. Then you can access that item using either s or SearchQuery from the URL.
Public Class ItemSearchModel
Private _s As String
Public Property s() As String
Get
Return _s
End Get
Set(value As String)
_s = value
End Set
End Property
Public Property SearchQuery() As String
Get
Return _s
End Get
Set(value As String)
_s = value
End Set
End Property
End Class