How to handle DataAnnotation RequiredField(ErrorMessage...) using EntityTypeConfiguration - entity-framework

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.

Related

FallBack Mapping in Mapstruct

I am currently using mapstruct in my project. I have a target field 't1' which could be either mapped to source field 's1' or 's2', initially it should try to map the source field 's1' to target field 't1', in case it is null it should then fallback to source field 's2' for mapping it to the target field 't1'. And the source field objects in both cases are nested and would need some processing before it is mapped to the target. I've been looking around however I wasn't able to find any solution for this. Does Mapstruct support fallback Mapping? Below is an example, Here UserRequest is the target object and User is the source. In case I would like map id of the userRequest to user.address.postal primarily and in case it's null the id should be mapped to location.id of the overrideLocation. Can anyone please help me with this.
UserRequest{
String id;
}
User{
String name;
Address adress;
OverrideLocation location;
}
Address{
String postalCode;
}
OverrideLocation{
String id;
}
For now I've been using the AfterMapping in mapstruct to accomplish this. The primary mapping I specified as part of the #Mapping and the fallback mapping I've specified under AfterMapping. However I was wondering if there is a better way to deal with it. I looked into defaultValue and default expression as well, however I wasn't able to use it in this case

Entity Framework error during update: field is required

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.

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!

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.

PowerShell ParameterSets not being recognized

I have a powershell cmdlet, and I can't seem to get the parameter sets to work.
This cmdlet has 31 possible parameters and it can go down two possible processing paths.
All 31 parameters are optional, 18 are common to both paths, 9 are unique to the "right" path and 4 are unique to the "left" path. What I'm trying to accomplish is to use powershell's ParameterSet attributes to specify which parameter can be used when. But it's not working.
Below is a mock-up of my attempt. Names have been changed to protect the innocent.
[Parameter]
public string SomeString1 { get; set; }
[Parameter]
public string SomeString2 { get; set; }
[Parameter(ParameterSetName = "left")]
public string LeftName { get; set; }
[Parameter(ParameterSetName = "left")]
public string LeftDomain { get; set; }
[Parameter(ParameterSetName = "right")]
public string RightID { get; set; }
[Parameter(ParameterSetName = "right")]
public string RightIP { get; set; }
So when I run this, I try to check my parameter lists using get-help, and all I see is one big clump of parameters when it should split them up into two lists, one including the two "left" parameters plus the two unnamed ones, and another including the "right" parameters plus the unnamed ones.
The hilarious part is that we have another cmdlet that lets me do this just fine, no problems, perfect output. But for some reason this one isn't letting me. Same includes, same syntax, just different names. So I know our setup is correct, because it works sometimes. But it doesn't work all of the time, so I'm stumped.
I've tried changing some/all of the parameters to Mandatory, I've tried using a DefaultParameterSetName at the header. I've tried doubling up on sets, like including a set named "both" and making every parameter part of that set. I've read through the MSDN article on parameter sets, I've read through the first 40 articles that google returns, but I can't get it working. Half of my team has stood behind my desk watching me do it, and they're all stumped as well.
What can I do to:
figure out why it isn't recognizing my parameter sets
make it so that it does
prevent this from happening in the future
Keith Hill, thanks for the tip - I tried commenting out all but the most minimal parameters and I noticed that when I ran the get-help on the cmdlet that it still returned all of the parameters. I knew something goofy was going on, and it turns out that the help file was not getting updated when I compiled the cmdlet.
When I worked that issue out, it appears that everything was functioning exactly as I expected it to, it was that the get-help was using old information. That's why nobody else could figure it out, either. I was doing it right, so there were no bugs, just poor documentation.
Major facepalm moment, but I got it worked out. The lesson is: always make sure your help is automatically generating.