Entity Framework error during update: field is required - entity-framework

I'm using EF 6.2.0, Code First from Database, in a .net 4.5.2 environment.
I have this DbSet:
<Table("Firebird.PLANT4")>
Partial Public Class PLANT4
<Key>
<DatabaseGenerated(DatabaseGeneratedOption.None)>
Public Property ID_PLANT4 As Integer
Public Property STATUS As Integer
<Required>
<StringLength(20)>
Public Property DESCRIPTION1 As String
Public Property COUNTER As Long
Public Property RESET_COUNTER As Integer
End Class
When I execute this code:
Using dbContext As New DbModel
dbContext.Database.Connection.ConnectionString = GetFbConnectionString()
dbContext.Database.Connection.Open()
Dim plant As PLANT4 = dbContext.PLANT4.Find(1)
plant.RESET_COUNTER = 1
dbContext.SaveChanges()
End Using
I get the error: "DESCRIPTION1 field is required".
The exception is throwing during SaveChanges.
I can't understand where the problem is, as if I watch "plant" in debug, all fields are there (ID_PLANT4 = 1 is an existing row), and DESCRIPTION1 in particular is not Nothing.
I can simply remove the "Required" attribute and it works, but the attribute is a consequence of the db column not allowing nulls, so I don't think this is the right way to go.
I can even add this line of code, just after the "Using" statement:
dbContext.Configuration.ValidateOnSaveEnabled = False
and it works, but again I don't think this is the right way to go.
What is the reason of this behavior?

Eventually I find that the problem is: field DESCRIPTION1 is populate by default with 20 spaces. It is not null, but it is a string formed only by spaces. For an unknown reason, during validation this string is treated by EF like null, and an exception is thrown because it's a required field.
"Required" attribute is not needed, but I generate my POCO classes by "Code First from Database", so if a VARCHAR field is declared as "not null" it is automatically generated with the "Required" attribute. Now I think it's better allowing nulls for VARCHAR columns.

Related

How to specify EF byte[] in code first longer than 8000 bytes?

I am using EF 6.1.3. Using code first sets a byte[] property in an entity to max. 8000 bytes. Any attempt to make it greater, that is MAX, fails.
HasMaxLength(null) (yes, the parameter is int?) still sets it to 8000, HasMaxLength(int.MaxValue) or any other value greater than 8000 makes EF throw System.Data.Entity.Core.MetadataException:
Schema specified is not valid. Errors: (0,0) : error 0026: MaxLength
'2147483647' is not valid. Length must be between '1' and '8000' for
'varbinary' type.
SQL server 13.0.2151 (mssqllocaldb) allows for varbinary(max):
This limit seems too severe to me. Trying to find a reason why it is imposed does not yield a good reason for this too. So, my question is
How a byte[] can be mapped to varbinary(max) in EF code first?
PS: The property is also 'required', but I am not sure if an optional property may be set to varbinary(MAX) either. Anyway, i have not tested this case since it does not make much sense to me.
Despite the multiple articles that states the solution is to add the following attribute
[Column(TypeName="image")]
byte[] Photo { get; set; }
I found the correct approach to be, adding instead this attribute
[MaxLength]
public byte[] Photo { get; set; }
With the Column(TypeName) recommendation I'll end up getting the following error with SQLCE:
The field Photo must be a string or array type with a maximum length of '4000'
Well, I found a workaround to this. Specifying HasColumnType("image") solves the problem, but I still think that EF must allow for specifying varbinary(max) as well.
Moreover, not all binary files are images. ;)
And still part of the question remains unanswered, so I will put it this way:
Why a byte[] property cannot be mapped to varbinary(max) in EF code first?
Any comments (or answers of course) are welcome. Thanks in advance.
EDIT (as per comment by Gert): leaving the property without any specs makes EF generate varbinary(max). Surprisingly simple!
It is possible.
Fluent API
.IsMaxLength()
Before you want to update the database take a look in the filename which is generated after you use "add-migration filename"
If you see a method "CreateTable" and see that a field which should te be a binary type with a lenght of MAX, it can be generated as c.Binary(maxLength: 8000), remove the parameter maxLength at all and then use update-database and after that you can check the created table in the SQL server database!

embeddedmap of strings not working after 2.2

I had been developing some base queries for about 6 months prior to the release of 2.2
CREATE CLASS Flag_Definitions EXTENDS V
CREATE PROPERTY Flag_Definitions.V_status EMBEDDEDMAP STRING
CREATE PROPERTY Flag_Definitions.V_branding EMBEDDEDMAP STRING
CREATE PROPERTY Flag_Definitions.Block_type EMBEDDEDMAP STRING
CREATE VERTEX Flag_Definitions SET title = "developer reference for all data flags", V_status = {"ACTIVE":"Normal active record", "SUSPENDED":"Currently inactive record","DELETED":"Discontinued record maintained for archiving"}, Block_type = {"Prop":"Holds text from a data object property","HTML":"Holds basic HTML for content","Container":"Holds other blocks"}
but now I'm getting this error in studio
{"errors":[{"code":400,"reason":400,"content":"Map found but entries are not defined as :\r\n\tDB name=\"TestDB\""}]}
From console, the phrasing is slightly different
Map found but entries are not defined as <key>:<value>
Either way, the format 'SET mapfield = {"key":"val"}' no longer seems to be working, and I can't find an explanation. I even looked into the orient code on github (line 118), but, having 2 parts, the format should be passing the check on line 117.
Solved this one, it has nothing to do with the Flag_Definitions object, but I had a default status flag being applied to all created vertices
CREATE PROPERTY V.flags EMBEDDEDMAP STRING
ALTER PROPERTY V.flags DEFAULT {"status":"ACTIVE"}
The issue is the DEFAULT, which needs to be
DEFAULT '{"status":"ACTIVE"}'
Similarly, I had to change
DEFAULT sysdate() to DEFAULT "sysdate()"

How to handle DataAnnotation RequiredField(ErrorMessage...) using EntityTypeConfiguration

I have EF poco classproperty which has the DataAnnotatins. They include the FK, mandatory, maxlength conditions.
[Required(ErrorMessage = "Company name cannot be empty")]
[StringLength(128, ErrorMessage = "The CompanyName should be less than 128 characters or less.")]
[Index(IsUnique = true)]
public string CompanyName { get; set; }
I am trying to move all these into EntityTypeConfigurations and am struggling to move the ErrorMessages.
Can any one give me a pointer on how to get this done>
As you can read here, constraints configured by fluent mappings will by evaluated only in the context. They don't trickle through to the UI, as data annotations do (when used with the correct framework). So the EF team figured it wouldn't make sense to craft a user-friendly error message here. The validation will just throw a standard DbValidationError saying something like
The field Name must be a string or array type with a maximum length of '128'
So you need the annotations if you want your own custom messages.

Grails Grom + mongoDb get during save OptimisticLockingException

I try in Grails service save an object to mongodb:
Cover saveCover = new Cover()
saveCover.id = url
saveCover.url = url
saveCover.name = name
saveCover.sku = sku
saveCover.price = price
saveCover.save()
Cover domain looks like this:
class Cover {
String id
String name
String url
String sku
String price
}
So I want to have custom id based on url, but during save process I get error:
Could not commit Datastore transaction; nested exception is
org.grails.datastore.mapping.core.OptimisticLockingException: The
instance was updated by another user while you were editing
But if I didn`t use setters and just pass all values in constructor, the exception is gone. Why?
As reported in the documentation here:
Note that if you manually assign an identifier, then you will need to use the insert method instead of the save method, otherwise GORM can't work out whether you are trying to achieve an insert or an update
so you need to use insert method instead of save when id generator is assigned
cover.insert(failOnError: true)
if you do not define the mapping like this:
static mapping = {
id generator: 'assigned'
}
and will use insert method you'll get an auto-generated objectId:
"_id" : "5496e904e4b03b155725ebdb"
This exception occurs when you assign an id to a new model and try to save it because GORM thinks it should be doing an update.
Why this exception occurs
When I ran into this issue I was using 1.3.0 of the grails-mongo plugin. That uses 1.1.9 of the grails datastore core code. I noticed that the exception gets generated on line 847(ish) of NativeEntryEntityPersister. This code updates an existing domain object in the db.
Above that on line 790 is where isUpdate is created which is used to see if it's an update or not. isInsert is false as it is only true when an insert is forced and readObjectIdentifier will return the id that has been assigned to the object so isUpdate will end up evaluating as true.
Fixing the exception
Thanks to && !isInsert on line 791 if you force an insert the insert code will get called and sure enough the exception will go away. However when I did this the assigned id wasn't saved and instead a generated object id was used. I saw that the fix for this was on line 803 where it checks to see if the generator is set to "assigned".
To fix that you can add the following mapping.
class Cover {
String id
String name
String url
String sku
String price
static mapping = {
id generator: 'assigned'
}
}
A side effect of this is that you will always need to assign an id for new Cover domain objects.

Breeze property validation using data annotations in entity framework

Within my entity framework model I have:
<Required(), Range(0, Double.MaxValue, ErrorMessage:="Weight must be numeric and cannot be negative")> _
Public Property Weight() As Double
<Required(), Range(0, Double.MaxValue, ErrorMessage:="Recycled content must be numeric and between 0 and 100")> _
Public Property RecycledContent() As Double
And in my viewmodel I have:
if (!editComponent().entityAspect.validateProperty("recycledContent")) {
/* do something about errors */
var msg = 'Recycled content is invalid!';
logger.logError(msg, error, system.getModuleId(lt_articleEdit), true);
}
And yet when I enter a value greater than 100 (in the recycled content field) it still passes validation somehow! I have used the script debugger to step through and in the breeze validation routine there are two validators registered which are "required" and "number" but nothing that I can see mentions the range.
Can breeze do range validation? All I'm trying to do is pick up a data validation error based on metadata from the data annotations of the model and use this to trigger a client-side highlight on the field in error and log an error message.
It's a very reasonable request but we aren't quite there yet.
Right now Breeze doesn't YET pick up Range validations from Entity Framework metadata. Please vote for this on the Breeze User Voice . This matters because we do prioritize our work based on this venue.