ASP.NET Dynamic Data Entities + primary key on DateTime column = FormatException - entity-framework

I am trying to build a simple website using an "ASP.NET Dynamic Data Entities Web Application" project template in VS 2012 (C#). It is pretty much the standard template setup, with an entity where DateTime type property is part of a primary key (the underlying table has also the SQL DateTime type on the mapped column). I get FormatException when I try to see the Details page, or edit a row:
String was not recognized as a valid DateTime. Description: An
unhandled exception occurred during the execution of the current web
request. Please review the stack trace for more information about the
error and where it originated in the code.
Exception Details: System.FormatException: String was not recognized
as a valid DateTime.
Source Error:
An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.
Stack Trace:
[FormatException: String was not recognized as a valid DateTime.]
System.Web.UI.WebControls.EntityDataSourceView.ExecuteSelect(DataSourceSelectArguments
arguments) +965
System.Web.UI.DataSourceView.Select(DataSourceSelectArguments
arguments, DataSourceViewSelectCallback callback) +21
System.Web.UI.WebControls.DataBoundControl.PerformSelect() +138
System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +30
System.Web.UI.WebControls.FormView.DataBind() +4
System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +105
System.Web.UI.WebControls.FormView.EnsureDataBound() +178
System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls()
+75 System.Web.UI.Control.EnsureChildControls() +83 System.Web.UI.Control.PreRenderRecursiveInternal() +42
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Control.PreRenderRecursiveInternal() +168
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+974
I tried setting the culture in <globalization> node in web.config but it did not help.
The URL for Details page contains the columns in query string, looking like this: &Created=09%2F30%2F2013 16%3A10%3A33&Updated=09%2F30%2F2013 23%3A10%3A40 for a row where Created is '30-09-2013 16:10:33' and Updated '30-09-2013 23:10:40'.
It is my first Dynamic Data project so I do not really know what to do... Thanks in advance for any help.
Edit:
Adding
<globalization uiCulture="en-US" culture="en-US"/>
to system.web node of the main web.config caused the exception to disappear, but now the Details can't find the correct row, saying "No such item."

Since you have defined datetime as primary key, it is url-encoded by browser while sending get request. You should decode this value in your view before using it. Framework is trying to parse the encoded value as datetime and because of this giving exception.

You could be having localization issues, the datetime format can be different for different countries and also different between what you use in c# and sql
Try submitting in invariant format like yyyy-mm-dd
Also you should use datetimeoffset as your datetime instead, it has more precision and takes the same space if i remember correct, or at least use datetime2 as your sql data type since that has more precision and takes the same or less space.
Update:
It might be an issue with parsing the values as Adarsh suggests, you can change your culture programatically:
// Put the using statements at the beginning of the code module
using System.Threading;
using System.Globalization;
// Put the following code before InitializeComponent()
// Sets the culture to French (France)
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
// Sets the UI culture to French (France)
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR");
Taken from msdn
You can try that to see if that is perhaps the issue, then you can look into setting it from config or maybe look at different modelbinding for datetime, there are several solutions depending on what is right for you.

I managed to resolve the issue. Turns out the underlying table did not have primary key defined, so all the NOT NULL columns (including two DateTime columns) inferred Entity Key properties in the Entity Framework entity for that table. After setting "Entity Key" property to False for these two properties everything started to work as it should.
This is not a universal solution, but more of a workaround for this particular case, where rows are uniquely identified by other columns than those with DateTime type. If I really had a table where DateTime column would be the primary key, I guess I would run into the same issue again.
Regarding FormatException, setting <globalization culture="en-US" /> in web.config under system.web node fixed it, but after removing the Entity Key property from the DateTime columns even this was unnecessary, since DateTime values were not used to construct the URI anymore.

Related

operator does not exist: # timestamp without time zone

In a parameterized query issued from c# code to PostgreSQL 10.14 via dotConnect 7.7.832 .NET connector, I select either a parameter value or the local timestamp, if the parameter is NULL:
using (var cmd = new PgSqlCommand("select COALESCE(#eventTime, LOCALTIMESTAMP)", connection)
When executed, this statement throws the error in subject. If I comment out the corresponding parameter
cmd.Parameters.Add("#eventTime", PgSqlType.TimeStamp).Value = DateTime.Now;
and hardcode
using (var cmd = new PgSqlCommand("select COALESCE('11/6/2020 2:36:58 PM', LOCALTIMESTAMP)", connection)
or if I cast the parameter
using (var cmd = new PgSqlCommand("select COALESCE(cast(#eventTime as timestamp without time zone), LOCALTIMESTAMP)", connection)
then it works. Can anyone explain what # operator in the error is referring to and why the error?
In the case that doesn't work, your .Net connection library seems to be passing an SQL command containing a literal # to the database, rather than substituting it. The database assumes you are trying to use # as a user defined operator, as it doesn't know what else it could possibly be. But no such operator has been defined.
Why is it doing that? I have no idea. That is a question about your .Net connection library, not about PostgreSQL itself, so you might want to add tag.
The error message you get from the database should include the text of the query it received (as opposed to the text you think it was sent) and it is often useful to see that in situations like this. If that text is not present in the client's error message (some connection libraries do not faithfully pass this info along) you should be able to pull it directly from the PostgreSQL server's log file.

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.

Does Codefluent Entities support method overloading?

I want to create 2 methods with the same name, same return type, but different parameters.
When I attempted this using the Model the following happened:
No error message was immediately generated when adding the second method to the model.
The second method did not appear in the GUI for the Model.
Both methods do appear in the XML file generated by the Model.
When I attempt to build the model I got the following error message:
Error 1 CF0075: Procedure
'_PR01_PayrollEmployeeFile_LoadBySocialSecurityNumber' for method
'LoadBySocialSecurityNumber(System.String socialSecurityNumber,
System.String companyCode)' with body 'LOAD(string
socialSecurityNumber, string companyCode) RAW' already exists. Try to
change method name or method
persistenceName. 0 0 Amikids.DataProWarehouse.Model
To the good support people at Softfluent: Give me 24 hours and check back to make sure the following solution fully works and I don't have any other issues.
I think I have the solution but have not fully tested and noticed something quirky in the XML after I did a build, but suspect I may have corrupted the XML file and don't have time to fully explore.
The solution (I think):
Set the persistenceName in the XML file. The persistenceName corresponds to the generated stored procedure name.
<cf:method name="TestMethod" body="LOAD(string x) ORDER BY FirstName" persistenceName="TestMethod1" />
<cf:method name="TestMethod" body="LOAD(string x, string y) ORDER BY LastName" persistenceName="TestMethod2" />

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!

Entity Framework .Include does not support paths with more than 8 dot-separated names

I've opened a bug on Microsoft Connect for this, but no response (see edit below for their response) in a long while. So here it goes:
When trying to request an entity framework with its relation using the "Include" function in the linq query, it's impossible to request a relation through a path of more than 8 steps (8 . dot characters in the path). This prevents me from completing some of my dynmically generated queries that require access to more than that level of redirection.
Instead of completing the query successfully I get the following exception:
"Foo.Bar.Baz...(some more path string here)", the current limit of "8" is insufficient.
at System.Data.Common.MultipartIdentifier.IncrementStringCount(String name, String[] ary, Int32& position, String property)
at System.Data.Common.MultipartIdentifier.ParseMultipartIdentifier(String name, String leftQuote, String rightQuote, Char separator, Int32 limit, Boolean removequotes, String property, Boolean ThrowOnEmptyMultipartName)
at System.Data.Objects.Span.ParsePath(String path)
at System.Data.Objects.Span.Include(String path)
at System.Data.Objects.Span.IncludeIn(Span spanToIncludeIn, String pathToInclude)
Has anyone figured why this is so, or a way around this? Looking at the code (with Reflector) of ParsePath it seems that they hard-coded the magic number 8 in there...
UPDATE: Microsoft's response:
Thank you for raising this issue. We plan to remove the limit of the number of elements in an Include path in the next release.
UPDATE 2: Despite Microsoft's response quoted above, the bug was not fixed in EF 4.1
UPDATE 3: According to Microsoft, should be fixed in .NET 4.5, but I didn't test the developer preview to see if it works.
probably fixed in latest .net 4.5
https://connect.microsoft.com/VisualStudio/feedback/details/640423/entity-framework-include-strings-are-arbitrarily-limited-to-a-path-of-depth-8#tabs
I have not seen this, but here are 2 possible work arounds:
Loop through the data and use Load for each row. Note this will create a call to the database for each row, so it is really slow.
Flatten the data in a view and then select from the view. This creates a lot of redundant data, so more memory and network use.