Entity Framework and System.Data.Sqlite Datetime issue - entity-framework

I have a problem with mapping existing sqlite3 database (over system.data.sqlite) with entity framework (version 5) code first.
There is a table in database called notes that I map to my entity class:
public class Note
{
[Column("ZNAME")
public string Name { get; set; }
[Column("ZDATE")]
public DateTime Date { get; set; }
[Column("ZNOTE")]
public string Description { get; set; }
}
In database for example I have 2 rows, one has ZDATE field empty, other has some date (example: 30/12/1899 21:00:05).
When I unit test it, and when trying to get whole collection or this first row with empty datetime field I get the infamous exception: "String was not recognized as a valid DateTime." Trying to get only other row (with date), my test passes.
At first I thought that changing DateTime to string will solved the problem, but it gives me the same exception. I tried using DateTime?, same error.
It looks like, maybe I'm wrong, that System.Data.Sqlite tries to convert that field to datetime (because of name or something).
This is the stacktrace of my exception:
at System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style)
at System.DateTime.ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText, SQLiteDateFormats format, DateTimeKind kind)
at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText)
at System.Data.SQLite.SQLiteConvert.ToDateTime(IntPtr ptr, Int32 len)
at System.Data.SQLite.SQLite3.GetDateTime(SQLiteStatement stmt, Int32 index)
at System.Data.SQLite.SQLite3.GetValue(SQLiteStatement stmt, Int32 index, SQLiteType typ)
at System.Data.SQLite.SQLiteDataReader.GetValue(Int32 i)
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetUntypedValueDefault(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
Can someone give me some insight how to solve this problem.

You need to use DateTime? as the type
[Column("ZDATE")]
public DateTime? Date { get; set; }
This will allow null values for the Date field

In SQLite, dates must have the format yyyy-mm-dd.

Related

Entity Framework insert failed with date column

I have a problems with Entity Framework (V 6.1.0), if a DateTime property is annotated as a Date type:
Column(TypeName = "Date")
public class MyTable
{
[DatabaseGenerated]
public Guid Id { get; set; }
[Key, Column(TypeName = "Date"), DataType(DataType.Date)]
public DateTime DateKey { get; set; }
[Required]
public string SomeProperty { get; set; }
}
The column of my table in SQL is created correctly as a DATE column.
Now if I try to insert a new row and set my date property e.g. with DateTime.Now() I get following error:
Store update, insert, or delete statement affected an unexpected
number of rows (0). Entities may have been modified or deleted since
entities were loaded. Refresh ObjectStateManager entries.
The problem is in the generated SQL code by EF:
exec sp_executesql N'
INSERT [dbo].[MyTable]([DateKey], [SomeProperty]) VALUES (#0, #1)
SELECT [Id] FROM [dbo].[MyTable]
WHERE ##ROWCOUNT > 0 AND [DateKey] = #0',
N'#0 datetime2(7), #1varchar(max)',
#0='2014-03-26 08:58:07',
#1='abcdef'
The parameter for DateKey is declared as DATETIME2. I think, This should be DATE.
This select statement cannot return any row, if there is any time part. If I change parameter #0 to DATE (as it is annotated in my model, I get no error even if time part is still included.
Is this a bug in EF?
Regards,
Daniel
EDIT:
I don't know if this is relevant for my question. I'm configured in OnModelCreating all my date column as DATETIME2 by default:
modelBuilder.Properties().Configure(p => p.HasColumnType("datetime2"));
EDIT on 2014-03-27
Providing a complete repro:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFDateColumnAsKey
{
class Program
{
static void Main(string[] args)
{
MyContext ctx = new MyContext();
ctx.CalendarItems.Add(new CalendarItem() { StartDate = DateTime.Now.Date }); // This works
ctx.SaveChanges();
ctx.CalendarItems.Add(new CalendarItem() { StartDate = DateTime.Now }); // This not !!
ctx.SaveChanges();
ctx.Dispose();
}
public class MyContext : DbContext
{
public DbSet<CalendarItem> CalendarItems { get;set; }
}
public class CalendarItem
{
[DatabaseGenerated( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Key, Column(Order = 1), DataType(DataType.Date)]
public DateTime StartDate { get; set; }
}
}
}
I have added some details to bug #2185. In summary, when we create a SqlCommand for the INSERT operation we define a parameter of type DATETIME2 for any property of type System.DateTime, but for compatibility reasons when we create the database schema by default we will create a column of type DATETIME.
The SQL we generate for the insert looks like this:
INSERT [dbo].[CalendarItems]([StartDate]) VALUES (#0);
SELECT [Id] FROM [dbo].[CalendarItems] WHERE ##ROWCOUNT > 0 AND [StartDate] = #0;
When you pass an arbitrary System.DataTime instance as a DATETIME2 parameter the least significant digits will be preserved, but as soon as the value of the DATETIME2 parameter gets stored in a DATETIME column, the value will be truncated.
Since the value stored in StartDate no longer matches the value of parameter #0, the second statement (i.e. the SELECT query we use to detect rows affected) will return zero rows and the command will fail, the transaction will get rolled back, etc.
As you already found, the possible workarounds are:
Use a surrogate identity key instead of declaring a key of type DateTime
Use DateTime2 for the column
Truncate the value in-memory before sending it to the database.
Hope this helps,
Diego

Error Occured while deserializing the property of class, Mongo db with c#

I have written a class which has the fields name,Reg_No,etc.
public int Reg_No { get; set; }
public string Name { get; set; }
my case reg no will be like " 1", "be01 " in mongo db the field type will be int32 for value 1 and string for be01
in my class i have tried both string and int data type, I' am facing the following error.
An error occurred while de serializing the Reg_No property of class Mongo_Studentattendance: Input string was not in a correct format.
Please help me to solve this and guide me to proceed further.
just change the data type of your property Reg_No to dynamic. your reg_no property should be as shown here
public dynamic Reg_No { get; set; }

Cannot convert IQueryable<T> AsEnumerable because T has a Guid property

I have the following EF class:
class Product
{
public Guid ProductGuid { get; set; }
public string ProductName { get; set; }
}
derived from a DB class where ProductGuid is a uniqueidentifier and ProductName is a nvarchar.
Consider productContext as the context:
var products = productContext.Products;
productList = products.ToList();
OR
productList = products.AsEnumerable();
The first instruction is executed correctly the second (both) launches an exception at runtime (it compiles correctly):
Unable to cast the type 'System.Guid' to type 'System.Object'. LINQ to
Entities only supports casting Entity Data Model primitive types.
I tried everything it does not work. I have other tables with Guid field but it never launches such exception. What can be the cause?
Do you really need to use the GUID type in that property? Wouldn't string do it for you anyway?
try replacing GUID. use String instead.

Nullability for strings vs other data types in columns created by Entity Framework Code First

When defining a string in a class using Code First, the default for the columns in the generated database allows nulls.
public string MyString { get; set; }
creates this column:
MyString (nvarchar(max), null)
I can change this to "not null" by using the [Required] attribute or by using the .IsRequired() method in the Fluent API.
The default for other data types does not allow nulls.
public int MyInt { get; set; }
public DateTime MyDateTime { get; set; }
public float MyFloat { get; set; }
public decimal MyDecimal { get; set; }
public bool MyBool { get; set; }
creates these columns:
MyInt (int, not null)
MyDateTime (datetime, not null)
MyFloat (real, not null)
MyDecimal (decimal(18,2), not null)
MyBool (bit, not null)
I can change these to allow nulls by using the .IsOptional() method in the Fluent API. Is there an attribute that will do the same thing?
I can also change the data types in the class definition to allow nulls (int?, DateTime?, etc.) which results in columns that allow nulls in the database.
What is the rationale for allowing nulls by default for strings but not for other data types?
You kind of answered this yourself. You cannot have a null reference to any of the other data types that you listed. So, if the code cannot handle a null, then it is going to make sure the database enforces that, also.
Just to make this perfectly clear, as you are focusing specifically on a string versus other value types. Here is the MDSN article on strings, if you search for null, you will see this line:
By contrast, a null string does not refer to an instance of a System.String object and any attempt to call a method on a null string causes a NullReferenceException
However, unless an int is nullable, it will never throw a NullReferenceException since it must always have a default value.
Useful to add that not only strings are nullable in EF Code First, but also classes.

How do I add a RowVersion attribute to a EF4 class

I am using EF4 and creating classes through the Entity design surface then generating the database from them. I want to add an attribute to some of the classes to show the timestamp they were last updated.
I have added a Version attribute to them, but I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
Any ideas?
You use byte[] type for rowversion/timestamp
Example use: http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html
If you are in the designer, just type in byte[] or System.Byte[], I think the field types dropdown selection on EF designer can be typed-in upon.
Given this DDL
create table Movie
(
MovieId int identity(1,1) not null primary key,
MovieName varchar(100) not null unique,
MovieDescription varchar(100) not null unique,
YearReleased int not null,
Version rowversion -- rowversion and timestamp are alias of each other
);
This is the class mapping:
public class Movie
{
    [Key]
    public virtual int MovieId { get; set; }
     
    [   Required, Display(Name="Title")
    ]   public virtual string MovieName { get; set; }
     
    [   Required, Display(Name="Description")
    ]   public virtual string MovieDescription { get; set; }
     
    [   Required, Display(Name="Year Released"), Range(1900,9999)
    ]   public virtual int? YearReleased { get; set; }
     
    [Timestamp]
// byte[] is the rowversion/timestamp .NET type
    public virtual byte[] Version { get; set; }
 
     
    public virtual IList<Genre> Genres { get; set; }             
}
As far as I know, rowversion is a relative binary value, not an actual time value. It increments for every insert and update that occurs. This allows you to compare values to determine which record is newer. Since it is relative, given a single rowversion value, you will know nothing, but given two rowversion values, you will know which is older and which is newer, but not by how much.
I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
I'm not sure, but most likely there isn't a datatype that will give you rowversion when going from model to database. You will have to change the database field type yourself, or add the field to the DB and bring the record up to your model. You could also generate the DDL and then modify it before creating the DB with it.
There is also another method where you can extend the functionality of the EF process by deriving from it's classes. You can then choose it yourself, but I'm not too familiar with how to do that.