Entity Framework datetime vs SQL Server date - entity-framework

I'm using Entity Framework 4.3. In my SQL Server 2008 db, I have some dates stored as dates rather than datetime.
I need to retrieve data using the date field, here a test code sample:
public static Applicant Create()
{
var dt = new DateTime(1967, 08, 03);
var r = new CrudRepo<Applicant>(UowHelper.GetUow().Context);
return r.Find(a => a.DateOfBirth == dt).Single();
}
However, I'm getting an issue with 'missing sequence'.
Any ideas as to how I get around this?
I'll also need to update the database too at some point.
Thanks.

The actual result of var dt = new DateTime(1967, 08, 03); is 8/3/1967 12:00:00 AM
The DataType of the DateOfBirth is Date so we need to TruncateTime the time.
msdn: EntityFunctions.TruncateTime Method
public static Applicant Create()
{
var dt = new DateTime(1967, 08, 03);
var r = new CrudRepo<Applicant>(UowHelper.GetUow().Context);
return r.FirstOrDefault(a => a.DateOfBirth == EntityFunctions.TruncateTime(dt));
}
or remove the .Single() method instead use the .FirstOrDefault() Method

FYI, to add to spajce's answer,
System.Data.Entity.Core.Objects.EntityFunctions
has been deprecated to
System.Data.Entity.DbFunctions

Related

Entity Framework 6: is it possible to update specific object property without getting the whole object?

I have an object with several really large string properties. In addition, it has a simple timestamp property.
What I trying to achieve is to update only timestamp property without getting the whole huge object to the server.
Eventually, I would like to use EF and to do in the most performant way something equivalent to this:
update [...]
set [...] = [...]
where [...]
Using the following, you can update a single column:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.SaveChanges();
}
OK, I managed to handle this. The solution is the same as proposed by Seany84, with the only addition of disabling validation, in order to overcome issue with required fields. Basically, I had to add the following line just before 'SaveChanges():
db.Configuration.ValidateOnSaveEnabled = false;
So, the complete solution is:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}

How to filter in execute query by Date range value?

I have to made a Query in executeQuery , and I have to filter by date field,
my code is :
public void executeQuery()
{
utcDateTime dateUTC, datenullUTC;
query q = new Query();
QueryBuildRange qbr;
QueryBuildDataSource qbds ;
QueryRun queryRun;
dateUTC = DateTimeUtil::newDateTime(_dateValue, 0, DateTimeUtil::getCompanyTimeZone());
qbds = q.addDataSource(tableNum(MCRCustCategory) );
qbds.addRange(fieldNum(MCRCustCategory, ValidTo)).value(strFmt ("> %1", dateUTC) );
queryRun = new QueryRun (q);
super();
}
In my init I call the executeQuery, but don't filter in my Form.
How to use the date in the Range ?
Thanks all,
enjoy!
You use a table which use date effective. You assume you have to do the selection yourself, this is not true.
Use this instead:
public void executeQuery()
{
this.queryBuildDataSource().validTimeStateAsOfDate(_dateValue);
super();
}
If you have an interval, use this instead:
this.queryBuildDataSource().validTimeStateDateRange(fromDate, toDate)
Your code as provided in the question does not do anything at all, as the form does not use the query you build. You buildt the wrong query anyway!
This blog post explains it concisely.

The specified type member 'Date' is not supported in LINQ to Entities Exception

I got a exception while implementing the following statements.
DateTime result;
if (!DateTime.TryParse(rule.data, out result))
return jobdescriptions;
if (result < new DateTime(1754, 1, 1)) // sql can't handle dates before 1-1-1753
return jobdescriptions;
return jobdescriptions.Where(j => j.JobDeadline.Date == Convert.ToDateTime(rule.data).Date );
Exception
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
I know what the exception means but i don't know how to get rid of it. Any help?
You can use the TruncateTime method of the EntityFunctions to achieve a correct translations of the Date property into SQL:
using System.Data.Objects; // you need this namespace for EntityFunctions
// ...
DateTime ruleData = Convert.ToDateTime(rule.data).Date;
return jobdescriptions
.Where(j => EntityFunctions.TruncateTime(j.JobDeadline) == ruleData);
Update: EntityFunctionsis deprecated in EF6, Use DbFunctions.TruncateTime
LINQ to Entities cannot translate most .NET Date methods (including the casting you used) into SQL since there is no equivalent SQL.
The solution is to use the Date methods outside the LINQ statement and then pass in a value. It looks as if Convert.ToDateTime(rule.data).Date is causing the error.
Calling Date on a DateTime property also cannot be translated to SQL, so a workaround is to compare the .Year .Month and .Day properties which can be translated to LINQ since they are only integers.
var ruleDate = Convert.ToDateTime(rule.data).Date;
return jobdescriptions.Where(j => j.Deadline.Year == ruleDate.Year
&& j.Deadline.Month == ruleDate.Month
&& j.Deadline.Day == ruleDate.Day);
For EF6 use DbFunctions.TruncateTime(mydate) instead.
"EntityFunctions.TruncateTime" or "DbFunctions.TruncateTime" in ef6 Is Working but it has some performance issue in Big Data.
I think the best way is to act like this:
DateTime ruleDate = Convert.ToDateTime(rule.data);
DateTime startDate = SearchDate.Date;
DateTime endDate = SearchDate.Date.AddDay(1);
return jobdescriptions.Where(j.Deadline >= startDate
&& j.Deadline < endDate );
it is better than using parts of the date to. because query is run faster in large data.
Need to include using System.Data.Entity;. Works well even with ProjectTo<>
var ruleDate = rule.data.Date;
return jobdescriptions.Where(j => DbFunctions.TruncateTime(j.Deadline) == ruleDate);
What it means is that LINQ to SQL doesn't know how to turn the Date property into a SQL expression. This is because the Date property of the DateTime structure has no analog in SQL.
It worked for me.
DateTime dt = DateTime.Now.Date;
var ord = db.Orders.Where
(p => p.UserID == User && p.ValidityExpiry <= dt);
Source: Asp.net Forums
I have the same problem but I work with DateTime-Ranges.
My solution is to manipulate the start-time (with any date) to 00:00:00
and the end-time to 23:59:59
So I must no more convert my DateTime to Date, rather it stays DateTime.
If you have just one DateTime, you can also set the start-time (with any date) to 00:00:00 and the end-time to 23:59:59
Then you search as if it were a time span.
var from = this.setStartTime(yourDateTime);
var to = this.setEndTime(yourDateTime);
yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);
Your can do it also with DateTime-Range:
var from = this.setStartTime(yourStartDateTime);
var to = this.setEndTime(yourEndDateTime);
yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);
As has been pointed out by many here, using the TruncateTime function is slow.
Easiest option if you can is to use EF Core. It can do this. If you can't then a better alternative to truncate is to not change the queried field at all, but modify the bounds. If you are doing a normal 'between' type query where the lower and upper bounds are optional, the following will do the trick.
public Expression<Func<PurchaseOrder, bool>> GetDateFilter(DateTime? StartDate, DateTime? EndDate)
{
var dtMinDate = (StartDate ?? SqlDateTime.MinValue.Value).Date;
var dtMaxDate = (EndDate == null || EndDate.Value == SqlDateTime.MaxValue.Value) ? SqlDateTime.MaxValue.Value : EndDate.Value.Date.AddDays(1);
return x => x.PoDate != null && x.PoDate.Value >= dtMinDate && x.PoDate.Value < dtMaxDate;
}
Basically, rather than trimming PoDate back to just the Date part, we increment the upper query bound and user < instead of <=

MongoDB DateTime Format

In mongodb adhoc query, before executing the query, how to format the date type element to dd\mm\yyyy format and then execute the query?
I solved this by inserting the datetime as integer using the getTime() method in java.
EG:
Date dt=new Date();
long integer_date=dt.getTime();
I used the above line of code to insert date as integer.With this it was easy to fetch records between a particular date.
I asked a similar question a little while back...this might be what you're looking for: What is the syntax for Dates in MongoDB running on MongoLab?
If you are using Java, you can create Date objects from strings using the parse method of the DateFormat class.
The Java documentation on the DateFormat Class may be found here:
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/DateFormat.html
The specific section on the parse method is here:
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/DateFormat.html#parse%28java.lang.String%29
The Java documentation on the Date object may be found here:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Date.html
As per the "Constructor Summary" section, the ability to pass a string into the constructor is "Deprecated. As of JDK version 1.1, replaced by DateFormat.parse(String s)."
While I was researching the above, I also came across the Calendar class, which may be used for converting a Date object and a set of integers. It may not be necessary for this application, but I thought it might be useful to include a link to the documentation:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Calendar.html
Integers for year, month, day, hour, etcetera may be passed in via the set method:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Calendar.html#set%28int,%20int,%20int,%20int,%20int%29
By way of example, here is a short Java Program that creates a number of Date objects, stores them in a Mongo collection, and then executes a query similar to what you have described. Hopefully it will help you to accomplish your goal. NOTE: This program drops a collection named "dates", so be sure to change the collection name if you already have such a collection in your database!
public static void main(String[] args) throws UnknownHostException, MongoException {
Mongo m = new Mongo( "localhost:27017" );
DB db = m.getDB("test");
DBCollection coll = db.getCollection("dates");
coll.drop();
DateFormat df = DateFormat.getInstance();
String dateString = new String();
Date myDate = new Date();
// Save some test documents
for(int i=1; i<11; i++){
dateString = "04/" + String.valueOf(i) + "/12 11:00 AM, EST";
BasicDBObject myObj = new BasicDBObject("_id", i);
try {
myDate = df.parse(dateString);
} catch (ParseException e) {
e.printStackTrace();
}
myObj.put("date", myDate);
System.out.println(myDate);
coll.save(myObj);
}
// Build the query
Date startDate = new Date();
Date endDate = new Date();
try {
startDate = df.parse("04/4/12 11:00 AM, EST");
endDate = df.parse("04/6/12 11:00 AM, EST");
} catch (ParseException e) {
e.printStackTrace();
}
BasicDBObject dateQuery = new BasicDBObject();
dateQuery.put("$gte", startDate);
dateQuery.put("$lte", endDate);
System.out.println("---------------");
//Execute the query
DBCursor myCursor = coll.find(new BasicDBObject("date", dateQuery));
//Print the results
while(myCursor.hasNext()){
System.out.println(myCursor.next().toString());
}
}
This is use full to format code to date format from simple date time format and the reverse steps also supporting this way to retrieve date from MongoDB.
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date fDate = formatter.parse((String) metaData.getValue());
newMeta.setValue(fDate);[![In this image you can see how is the save scenario process in mongoDB][1]][1]
Date class has a before(date) or after(date) method... It is easy to use: no conversion to seconds/milliseconds.
public void execute(Tuple input) {
try {
date=(Date) input.getValueByField("date");
boolean before = date.before(myDate); // compare the data retrieved with your date.
if (before) {
...
} else {
...
}
} catch (Exception e) {
logger.error("Error...", e);
}
This approach is easier than the accepted answer..

Changing schema name on runtime - Entity Framework

I need to change the storage schema of the entities on runtime.
I've followed a wonderful post, available here:
http://blogs.microsoft.co.il/blogs/idof/archive/2008/08/22/change-entity-framework-storage-db-schema-in-runtime.aspx?CommentPosted=true#commentmessage
This works perfectly, but only for queries, not for modifications.
Any idea why?
Well, I was looking for this piece of code all around the Internet. In the end I had to do it myself. It's based on Brandon Haynes adapter, but this function is all you need to change the schema on runtime - and you don't need to replace the autogenerated context constructors.
public static EntityConnection Create(
string schema, string connString, string model)
{
XmlReader[] conceptualReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".csdl")
)
};
XmlReader[] mappingReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".msl")
)
};
var storageReader = XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".ssdl")
);
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl";
var storageXml = XElement.Load(storageReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet"))
{
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null)
{
schemaAttribute.SetValue(schema);
}
}
storageXml.CreateReader();
StoreItemCollection storageCollection =
new StoreItemCollection(
new XmlReader[] { storageXml.CreateReader() }
);
EdmItemCollection conceptualCollection = new EdmItemCollection(conceptualReader);
StorageMappingItemCollection mappingCollection =
new StorageMappingItemCollection(
conceptualCollection, storageCollection, mappingReader
);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories
.GetFactory(connectionData.Provider)
.CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
The resulting EntityConnection should be passed as a parameter when instantiating the context. You can modify it, so all ssdl models are modified by this function, not only the specified one.
I've managed to resolve this issue by using a brilliant library, located in CodePlex (courtesy of Brandon Haynes), named "Entity Framework Runtime Model Adapter", available here:
http://efmodeladapter.codeplex.com/
I've tweaked it a bit, to fit our needs and without the need of replacing the designer code at all.
So, I'm good.
Thanks anyways, and especially to Brandon, amazing job!
I need import data from postgres database. It by default use schema "public". So I use Entity Framework CTP 4 "Code first". It by default use schema "dbo". To change it in runtime I use:
public class PublicSchemaContext : DbContext
{
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder builder)
{
builder.Entity<series_categories>().MapSingleType().ToTable("[public].[series_categories]");
}
public DbSet<series_categories> series_categories { get; set; }
}
It work for select, insert, update and delete data. So next test in pass:
[Test]
public void AccessToPublicSchema()
{
// Select
var db = new PublicSchemaContext();
var list = db.series_categories.ToList();
Assert.Greater(list.Count, 0);
Assert.IsNotNull(list.First().series_category);
// Delete
foreach (var item in db.series_categories.Where(c => c.series_category == "Test"))
db.series_categories.Remove(item);
db.SaveChanges();
// Insert
db.series_categories.Add(new series_categories { series_category = "Test", series_metacategory_id = 1 });
db.SaveChanges();
// Update
var test = db.series_categories.Single(c => c.series_category == "Test");
test.series_category = "Test2";
db.SaveChanges();
// Delete
foreach (var item in db.series_categories.Where(c => c.series_category == "Test2"))
db.series_categories.Remove(item);
db.SaveChanges();
}
Not an answer per se but a followup on Jan Matousek's Create[EntityConnection] method showing how to use from a DbContext. Note DB is the DbContext type passed to the generic repository.
public TxRepository(bool pUseTracking, string pServer, string pDatabase, string pSchema="dbo")
{
// make our own EF database connection string using server and database names
string lConnectionString = BuildEFConnectionString(pServer, pDatabase);
// do nothing special for dbo as that is the default
if (pSchema == "dbo")
{
// supply dbcontext with our connection string
mDbContext = Activator.CreateInstance(typeof(DB), lConnectionString) as DB;
}
else // change the schema in the edmx file before we use it!
{
// Create an EntityConnection and use that to create an ObjectContext,
// then that to create a DbContext with a different default schema from that specified for the edmx file.
// This allows us to have parallel tables in the database that we can make available using either schema or synonym renames.
var lEntityConnection = CreateEntityConnection(pSchema, lConnectionString, "TxData");
// create regular ObjectContext
ObjectContext lObjectContext = new ObjectContext(lEntityConnection);
// create a DbContext from an existing ObjectContext
mDbContext = Activator.CreateInstance(typeof(DB), lObjectContext, true) as DB;
}
// finish EF setup
SetupAndOpen(pUseTracking);
}
I was able to convert the solution from Jan Matousek to work in vb.net 2013 with entity framework 6. I will also try to explain how to use the code in vb.net.
We have a JD Edwards Database which uses different Schema's for each environment (TESTDTA, CRPDTA, PRODDTA). This makes switching between environments cumbersome as you have to manually modify the .edmx file if you want to change environments.
First step is to create a partial class that allows you to pass a value to the constructor of your entities, by default it uses the values from your config file.
Partial Public Class JDE_Entities
Public Sub New(ByVal myObjectContext As ObjectContext)
MyBase.New(myObjectContext, True)
End Sub
End Class
Next create the function that will modify your store schema .ssdl file in memory.
Public Function CreateObjectContext(ByVal schema As String, ByVal connString As String, ByVal model As String) As ObjectContext
Dim myEntityConnection As EntityConnection = Nothing
Try
Dim conceptualReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".csdl"))
Dim mappingReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".msl"))
Dim storageReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".ssdl"))
Dim storageNS As XNamespace = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl"
Dim storageXml = XDocument.Load(storageReader)
Dim conceptualXml = XDocument.Load(conceptualReader)
Dim mappingXml = XDocument.Load(mappingReader)
For Each myItem As XElement In storageXml.Descendants(storageNS + "EntitySet")
Dim schemaAttribute = myItem.Attributes("Schema").FirstOrDefault
If schemaAttribute IsNot Nothing Then
schemaAttribute.SetValue(schema)
End If
Next
storageXml.Save("storage.ssdl")
conceptualXml.Save("storage.csdl")
mappingXml.Save("storage.msl")
Dim storageCollection As StoreItemCollection = New StoreItemCollection("storage.ssdl")
Dim conceptualCollection As EdmItemCollection = New EdmItemCollection("storage.csdl")
Dim mappingCollection As StorageMappingItemCollection = New StorageMappingItemCollection(conceptualCollection, storageCollection, "storage.msl")
Dim workspace = New MetadataWorkspace()
workspace.RegisterItemCollection(conceptualCollection)
workspace.RegisterItemCollection(storageCollection)
workspace.RegisterItemCollection(mappingCollection)
Dim connectionData = New EntityConnectionStringBuilder(connString)
Dim connection = DbProviderFactories.GetFactory(connectionData.Provider).CreateConnection()
connection.ConnectionString = connectionData.ProviderConnectionString
myEntityConnection = New EntityConnection(workspace, connection)
Return New ObjectContext(myEntityConnection)
Catch ex As Exception
End Try
End Function
Make sure that the storageNS namespace hardcoded value matches the one used in your code, you can view this by debugging the code and examining the storageXML variable to see what was actually used.
Now you can pass a new schema name, and different database connection info at runtime when you create your entities. No more manual .edmx changes required.
Using Context As New JDE_Entities(CreateObjectContext("NewSchemaNameHere", ConnectionString_EntityFramework("ServerName", "DatabaseName", "UserName", "Password"), "JDE_Model"))
Dim myWO = From a In Context.F4801 Where a.WADOCO = 400100
If myWO IsNot Nothing Then
For Each r In myWO
Me.Label1.Text = r.WADL01
Next
End If
End Using
These were the .net libraries used:
Imports System.Data.Entity.Core.EntityClient
Imports System.Xml
Imports System.Data.Common
Imports System.Data.Entity.Core.Metadata.Edm
Imports System.Reflection
Imports System.Data.Entity.Core.Mapping
Imports System.Data.Entity.Core.Objects
Imports System.Data.Linq
Imports System.Xml.Linq
Hope that helps anyone out there with the same issues.
I had a lot of problems getting this to work when using EF6 with an OData Data Service, so I had to find an alternate solution. In my case, I didn't really need to do it on the fly. I could get away with changing the schema when deploying to some test environments, and in the installer.
Use Mono.Cecil to rewrite the embedded .ssdl resources straight in the DLLs. This works just fine in my case.
Here is a simplified example of how you can do this:
var filename = "/path/to/some.dll"
var replacement = "Schema=\"new_schema\"";
var module = ModuleDefinition.ReadModule(filename);
var ssdlResources = module.Resources.Where(x => x.Name.EndsWith(".ssdl"));
foreach (var resource in ssdlResources)
{
var item = (EmbeddedResource)resource;
string rewritten;
using (var reader = new StreamReader(item.GetResourceStream()))
{
var text = reader.ReadToEnd();
rewritten = Regex.Replace(text, "Schema=\"old_schema\"", replacement);
}
var bytes = Encoding.UTF8.GetBytes(rewritten);
var newResource = new EmbeddedResource(item.Name, item.Attributes, bytes);
module.Resources.Remove(item);
module.Resources.Add(newResource);
}