I am trying to read information from my DAL and am wondering what built in types am I suppose to use in C# to extract the DATE Data Type in MySql to retrieve information. Am I suppose to use DateTime and convert the DateTime to Date or is there a way in C# where we can retrieve specified information when calling upon it. I have an image of the DS at the bottom
DATA_ACCESS_LAYER CODE SNIPIT
using MySqlConnector;
...
...
private IObject ReadInformation(MySqlDataReader reader, IObject object)
{
try
{
while (reader.Read)
{
((Object)object).Birthday = reader.getDateOnly("Birthday");
// ^ My Current issue of questioning what Data type
// do I have to use under the reader and do I have to change the
// IObject.Birthday datatype.
}
}
// catch code
}
Object Interface
class IObject
{
string FirstName;
...
DateOnly Birthday;
}
Object Class
class Object : IObject
{
public string FirstName { get; set; } = string.Empty;
...
public DateOnly Birthday { get; set; }
}
Image of the MySQL Database Field
class IObject
{
string FirstName;
...
DateTime Birthday; // Changed DateOnly to DateTime within the model
}
The Answer was my initial assumption that I must change the datatype from DateOnly -> DateTime. -- Answered by Flydog57
Related
I'm building a parser for some data that's given as XML, something similar to:
Get file in path %windir%\system32\calc.exe and retrieve it's CreationTime
The small problem that I have is that the type of object that I'm retrieving (FileInfo in example above) and the data type of the property I'm reading (CreationTime which is DateTime in example above) isn't always the same.
For example: on a FileInfo object alone I could be asked for:
bool Exists
DateTime CreationTime
DateTime LastWriteTime
long Size
Version Version
Other object types could be things like FolderInfo, RegistryKey and RegistryValue
With that in mind, I created the following code:
public interface IPropertyRetriever<out T>
{
public string Name { get; }
public Property Property { get; }
public T RetrieveProperty();
}
public enum Property
{
Count,
DateCreated,
DateModified,
RegistryKeyExists,
RegistryValueExists,
Size,
Value,
Version
}
public class FilePropertyRetriever<T> : IPropertyRetriever<T>
{
public FilePropertyRetriever(string name, Property property, string path, bool is64Bit)
{
Name = name;
Property = property;
Path = path;
Is64Bit = is64Bit;
}
public string Name { get; }
public Property Property { get; }
public string Path { get; }
public T RetrieveProperty()
{
var file = ...
// Do something to retrieve FileInfo,
// assumes if it got to code below FileInfo.Exists is true
return (T) (object) (Property switch
{
Property.Count => file.Exists,
Property.DateCreated => file.CreationTime,
Property.DateModified => file.LastWriteTime,
Property.Size => file.Length,
Property.Version => Version.TryParse(FileVersionInfo.GetVersionInfo(Path).ProductVersion,
out var version)
? version
: null
});
}
}
I know that my T RetrieverProperty() method isn't exactly very good programming - I'm telling my method what type I want it to return when in fact it knows already and using generics to cast to the correct type (and boxing it first if DateTime/long/int), but I really can't think of a better way of doing this.
Any suggestions on how to improve this?
PS: The reason why the RetrieveProperty() accepts no parameters and instead uses properties is because the device where the object is created and where the method are run is not the same, the object is serialised and sent over.
why can't IPropertyRetriever just be this:
public interface IPropertyRetriever
{
public string Name { get; }
public int Count {get;}
public DateTime DateCreated {get;}
public DateTime DateModified {get;}
public bool RegistryKeyExists {get;}
public bool RegistryValueExists {get;}
public long Size {get;}
//etc
}
And call it something different IFileInformation. Or have different interfaces returned for different objects with a base interface as not all the above properties are relevant to all objects.
Let's say we got a class like this one:
public class Person
{
[JsonConstructor]
public Person(string name, DayOfWeek bornOnDay) => (Name, BornOnDay) = (name, bornOnDay);
public string Name { get; protected set; }
public DayOfWeek BornOnDay { get; protected set; }
}
And an endpoint like this one:
[HttpPost]
[Route("api/people")]
public IHttpActionResult PostPerson([FromBody]List<Person> people)
{
// whatever
}
I've noticed that if I make a typo in enum type when making a request - no error occurs, only the object that has the erroneous enum won't be deserialized.
For instance, the request body may look like this:
[{"name":"John", "bornOnDay":"Moonday",},
{"name":"Mark", "bornOnDay":"Friday",},]
Endpoint will receive the list containing one Person, Mark, born on Friday.
I would like to make the post operation either happen completely, or fail, not with only with the objects without enum typos.. Is there a way to do it, without receiving a string instead of DayOfWeek, and then using Enum.TryParse(...) to determine that the input was erroneous?
Edit:
I actually want the error to occur, and be detectable, so I can return 400 code to the client.
you can do like this , you can create enum value from string you have inputted
public class Person
{
private string day;
[JsonConstructor]
public Person(string name, string bornOnDay){
this.Name = name;
this.day = bornOnDay;
}
public string Name { get; protected set; }
public DayOfWeek BornOnDay {
get {
DayOfWeek weekday;
if(Enum.TryParse(day, true, out weekday))
return weekday;
else
return DayOfWeek.None;//add none if no able to parse
}
}
Note : None is added according to Null Object Pattern to avoid issues related to null value in system.
What about this:
public class Person
{
[JsonProperty]
public string Name { get; protected set; }
[JsonProperty]
private string _BornOnDay { set {
//try parse the string, if not successful, throw a nicely
//formatted error with the original string and what you expect,
//if parse is successful, set the value to BornOnDay;
}}
[JsonIgnore]
public DayOfWeek BornOnDay { get; protected set; }
}
Not sure about the JsonConstructor attribute, never needed to use it. If you do need it and if I understand it correctly you can have something similar with it. Deserializer should give a string into constructor, and then inside of it, you do parsing logic for the enum yourself.
I'm using NodaTime Instant for date/time storage in my DTOs with ServiceStack. I have specified the SQL type in the DTO as datetimeoffset, and ServiceStack correctly creates the table with that type. However, upon saving, I get an InvalidCastException.
Simple example:
public class ItemWithInstant
{
public int Id { get; set; }
public string Name { get; set; }
[CustomField("DateTimeOffset")
public Instant DateCreated { get; set; }
}
In the service:
public object Post(CreateItemWithInstant request)
{
var dto = request.ConvertTo<ItemWithInstant>();
Db.Save(dto); // ERROR here
return dto;
}
The specific error is an InvalidCastException with the detail of Failed to convert parameter value from a Instant to a String.
No idea why it's converting to a string when the database type is DateTimeOffset. Do I need to tell ServiceStack how to convert the value to something that works with the SQL type?
Update
Thanks to #mythz answer, I created a custom converter. I also ended up going to DATETIME2 for the SQL data type (don't think that makes much of a difference):
public class SqlServerInstantToDatetimeConverter : OrmLiteConverter
{
public override string ColumnDefinition { get { return "DATETIME2"; } }
public override DbType DbType { get { return DbType.DateTimeOffset; } }
public override object ToDbValue(Type fieldType, object value)
{
var instantValue = (Instant) value;
return instantValue.ToDateTimeUtc();
}
public override object FromDbValue(Type fieldType, object value)
{
var datetimeValue = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
return Instant.FromDateTimeUtc(datetimeValue);
}
}
I then registered it in my AppHost.cs file:
Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(Settings.Default.LocalSqlConnectionString, SqlServerDialect.Provider));
SqlServerDialect.Provider.RegisterConverter<Instant>(new SqlServerInstantConverter());
Don't forget the FromDbType override. I forgot it initially and the field wasn't being output.
One other caveat -- since ServiceStack wants to localize all dates, I had to use the info in this answer to force all dates to a DateTimeKind.Local
[CustomField] just tells OrmLite what column definition to use when creating the table, i.e. it doesn't provide any indication on how OrmLite should treat unknown types.
You can support new fields types by registering a Custom Type Converter that's now available in the latest v4.0.44 release.
I've read a bunch about auto implemented properties but I still don't quite get it. I have and entity:
public class News
{
public int NewsId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Date { get; set; }
}
Now I don't want the user to set date himself every time a new entity of News type is created. I want the record to be saved automatically with the datetime it's created. Thinking about it I suggest that it's enough to just modify the set for my property to something like :
public DateTime Date
{
get;
set
{
Date = DateTime.Now;
}
}
But reading about the topic I saw that the standard way is to create private variable and use it instead in the implementation. That's where I get a little bit lost.
private DateTime _date = null;
public DateTime Date
{
Well I'm not sure for the getter and setter implementations. It seems reasonable to have something like : set { _date = DateTime.Now;} and I have no idea how to deal with the get part since I want this data to be fetched from the database so something like : get {return _date;} doesn't make much sense to me even though almost every example with auto implementedset` returns the private variable. But I think that if the property is an entity this is not making a lot of sense.
Some ways to return the current date:
public DateTime Date { get { return DateTime.Now; } }
or
public class News
{
public News()
{
Date = DateTime.Now;
}
public DateTime Date { get; private set; }
}
The first one will always return the current date/time, even if that instance was created some time ago. The second one will return the date/time the instance was created. Both prevent the user from setting that Date value.
You could add a constructor to your class and then initialize there your property.
public class News
{
// properties goes here
public News()
{
Date=DateTime.Now;
}
}
A far better constructor would be the following
public News(int newsId, string title, string content)
{
NewsId=newsId;
Title=title;
Content=content;
Date=DateTime.Now;
}
That way you could create an object of type News in a single line of code.
News news = new News(1,"title1","whatever");
Don't touch the getter and setter! They are auto generated from a template and will be overridden every once and a while. Instead, as you might have noticed the generated entities are declared partially, create a partial class and declare a constructor there that sets the _date or Date of you r entity to DateTime.Now on construction (just as you desired).
public partial class News
{
public News()
{
this.Date = DateTime.Now;
}
}
I'm xml-serializing a object with a large number of properties and I have two properties with DateTime types. I'd like to format the dates for the serialized output. I don't really want to implement the IXmlSerializable interface and overwrite the serialization for every property. Is there any other way to achieve this?
(I'm using C#, .NET 2)
Thanks.
For XML serialization you would have to implement IXmlSerializable and not ISerializable.
However you can workaround this by using a helper property and by marking the DateTime properties with the XmlIgnore attribute.
public class Foo
{
[XmlIgnore]
public DateTime Bar { get; set; }
public string BarFormatted
{
get { return this.Bar.ToString("dd-MM-yyyy"); }
set { this.Bar = DateTime.ParseExact(value, "dd-MM-yyyy", null); }
}
}
You can use a wrapper class/struct for DateTime that overrides ToString method.
public struct CustomDateTime
{
private readonly DateTime _date;
public CustomDateTime(DateTime date)
{
_date = date;
}
public override string ToString()
{
return _date.ToString("custom format");
}
}