C# SQLite object custom getter and setter - c#

I have a class which is also a table of a database SQLite.
I need to work with dates and I thought the best solution was to work with dates as integers, since in sqlite i don't have date operations. The problem is the following: I'm saving DateTime in my db as int using as helper a DateTime parameters which is ignored by db.
This is my class:
public class MYCLASS : Shared
{
[PrimaryKey]
public Guid ID { get; set; }
[Ignore]
public DateTime DATA_ORA
{
get { return DateTime.Parse(this.DATA_ORA_INT.ToString()); }
set { this.DATA_ORA_INT = int.Parse(value.ToString("yyyyMMdd")); }
}
private int DATA_ORA_INT { get; set;}
}
I'm having the app terminating without any exception when I set the DATA_ORA field. Why this code is not working?
EDIT:
this is when I got the crush:
MYCLASS transazione = new MYCLASS
{
ID = Guid.NewGuid(),
DATA_ORA = DateTime.Now
};

Looking at how you create the integer equivalent value of the datetime then, when you need to revert back to a DateTime from a such formatted field you need something like this
public DateTime DATA_ORA
{
get
{
// Add a check to return a default if DATA_ORA_INT is not initialized
return this.DATA_ORA_INT == 0 ? DateTime.Today :
DateTime.ParseExact(this.DATA_ORA_INT.ToString(),
"yyyyMMdd", CultureInfo.InvariantCulture);
}
set { ... }

Related

Hot Chocolate GraphQL - How to resolve field that uses ignored field with projection

I have a data model ItemData as follows :
class ItemData
{
public string StartTime { get; set; }
public string EndTime { get; set; }
// other fields here
}
I would like to expose those two as a single field Duration like this. Without exposing the StartTime and EndTime
{
"duration": {
"start": "12:34",
"end": "23:45"
},
// other fields here
}
And types ItemType and DurationType
ItemType defined a field "duration" like this
descriptor.Ignore(x=> x.EndTime);
descriptor.Ignore(x=> x.StartTime);
descriptor.Field("duration")
.ResolveWith<TheResolver>(resolver => resolver.GetDuration(default!))
.Type<DurationType>();
// other configurations here
The endpoint is marked with UseProjection and use EFCore data context.
When TheResolver.GetDuration() gets called it did not fetch the value for StartTime and EndTime from database. I think it's because the UseProjection tell it not to.
Is there any way to configure the Hot Chocolate to use projection on ignored fields StartTime and EndTime when the query requests duration field?
Specifying descriptor.Field(x => x.StartTime).IsProjected(true) does not work if the field specified as ignored.
UPDATE : Just found an issue on their github, looks like they're working on it (Issue #4192 - It's not possible to project an ignored property)
As a workaround for the issue in your particular case, you could make the selection with duration directly from queryable like:
dbContext.Items.Select(i => new ItemData { Duration = new Duration { Start = i.StartTime, End = i.End } })
And that IQueryable with the ready duration field to return further to [UseProjection] and whatever.
#ademchenko's workaround works. But what I ended up with was to add a Duration property in the ItemData class with calculated getter/setter in a partial class to separate from original code. Inspired by that answer.
partial class ItemData
{
public string StartTime { get; set; }
public string EndTime { get; set; }
// other fields here
}
partial class ItemData
{
public Duration ItemDuration
{
get => new Duration { Start = this.StartTime, End = this.EndTime };
set => (this.StartTime, this.EndTime) = (value.StartTime, value.EndTime);
}
}
Use property name ItemDuration to distinguish the type name and property name in this example

InvalidCastException when getting data from Database as a datetime

I'm trying to pull some data from my Database, but when it comes to Datetime I get an
InvalidCastException
This is my Database (SQL SERVER)
Create table Timeline(
start date,
end date
)
table Timeline
start(date) end(date)
03/07/2020 NULL
NULL 10/07/2020
15/07/2020 25/07/2020
This is my query
SELECT Timeline.start, Timeline.end FROM Timeline
This is my c# code
public class Timeline
{
public DateTime? startDate;
public DateTime? endDate;
public static Timeline fromRow(DataRow r)
{
Timeline a = new Timeline();
a.startDate = r.Field<DateTime?>("start");
a.endDate = r.Field<DateTime?>("end");
return a;
}
}
When I pull a NULL value it works, but when I pull a real date like 03/07/2020 It gives me InvalidCastException. Is there a way to check the value before putting it into the variable?
This is because the column type does not match up with what you are
trying to cast to here, my guess is it is being referenced as a varchar
type constructor public DataColumn (string columnName), which is
fine we can just parse the date safely as a string, you may lose a few
cycles on this but this is not 1995 anymore. If you want to cast safely
than offer the column the correct type so constructor public
DataColumn (string columnName, Type type)
// Change Names to match C# nameing conventions
public class TimeLine
{
// Since this class is just a strongly typed object for rows of your table values should not be able to change.
public DateTime? StartDate { get; private set; }
public DateTime? EndDate { get; private set; }
public static TimeLine FromRow(DataRow r)
{
// Casting will depend if we know the DataColumns type, if we dont we can just parse the string value
return new TimeLine
{
StartDate = DateTime.TryParse(r.Field<string>("start"), out var sd) ? sd : (DateTime?)null,
EndDate = DateTime.TryParse(r.Field<string>("end"), out var ed) ? ed : (DateTime?)null,
};
}
}

Moving app.config settings to db and using value type to dynamically set the return data type

I have a windows service application that I want to manage setting for from a asp.net site. As my application has grown, my list of settings in the app.config file has grown as well. So, I have decided to move these setting to a table in my SQLDB to be able to track them and give me a way to modify the settings from the admin site. I ran into an issue where I am trying to store the setting value type in the table and then use it to change the value property to the type stored. For instance I have quite a few TimeSpan defined. In the SQL table the data would look like this.
guid settingName settingValue settingType
936767f5-63b5-4844-9991-29f6f92c53f2 SMTimeStart 12:00:00 TimeSpan
Im trying to use the following code to pull the settings and return it in the correct type.
public class SettingDataValue
{
public Guid guid { get; set; }
public string SettingName { get; set; }
public string SettingValue { get; set; }
public string SettingType { get; set; }
}
public static dynamic getSettingFromDB(string name)
{
SettingDataValue s = new SettingDataValue();
using (IDbConnection _db = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString), commandTimeout = null)
{
s = _db.Query<SettingDataValue>("Select Guid, SettingName, SettingValue ,SettingType from SiteSettings where settingName = '" + name + "'").SingleOrDefault();
}
PropertyInfo propertyInfo = s.GetType().GetProperty(s.SettingType);
propertyInfo.SetValue(s, Convert.ChangeType(s.SettingValue, propertyInfo.PropertyType), null);
return s.SettingValue;
}
However when I run this I get a null reference exception on the
propertyInfo.SetValue(s, Convert.ChangeType(s.SettingValue, propertyInfo.PropertyType), null);
I know the query works when I test it and watch it with the sql profiler. Any thoughts or suggestions?
So couple things I had wrong. As David mentioned, I didnt need to use reflection to get the type. Instead I needed to use the Type.GetType method to parse the text. Also the second thing was that the data types have to be the namespace recorded with them.
Here is the updated code that is working now.
public class SettingDataValue
{
public Guid guid { get; set; }
public string SettingName { get; set; }
public string SettingValue { get; set; }
public string SettingType { get; set; }
}
public static dynamic getSettingFromDB(string name)
{
SettingDataValue s = new SettingDataValue();
using (IDbConnection _db = new SqlConnection(ConfigurationManager.ConnectionStrings["NetworkCafeConnectionString"].ConnectionString))
{
s = _db.Query<SettingDataValue>("Select guid, SettingName, SettingValue ,SettingType from SiteSettings where SettingName = '" + name + "'").FirstOrDefault();
}
Type type = Type.GetType(s.SettingType);
var converter = TypeDescriptor.GetConverter(type);
return converter.ConvertFrom(s.SettingValue);
}
Here is a sample of the data in the sql table.
guid SettingName SettingValue SettingType
95473a84 SMCreateTime 00:12:00 System.TimeSpan
81037bdc SMCreateEnabled True System.Boolean
99e06df7 SMUsername Username System.String
The problem you're having isn't that you aren't getting data back, but that the PropertyInfo is null.
The line:
PropertyInfo propertyInfo = s.GetType().GetProperty(s.SettingType);
Is actually trying to find the property "TimeSpan" on the SettingDataValue object (using the line of data you provided). Since this property does not exist it is returning null. Then you're trying to set the value of the property and getting the null reference exception.
I think what you're trying to do is convert the string value to the type of value in the setting type. You don't need to use reflection for that. I'd recommend adding a read only property to your SettingDataValue object:
public object Value
{
get
{
return SomeMethodThatConvertsYourStringValueToTarget();
}
}
Then a private method to actually do the conversion.
private object SomeMethodThatConvertsYourStringValueToTarget();
{
switch (SettingType)
{
case "TimeSpan":
//conversion code
break;
}
}
Then change your getSettingsFromDb method to return object instead of dynamic. Then you can use it like:
TimeSpan ts = (TimeSpan)getSettingsFromDb("SMTimeStart");
Alternatively you may create a method for each data type so you don't have to case it when using it. So you could use it like:
TimeSpan ts = getTimeStampFromDb("SMTimeStart");

Stuck in loading data from database

In making this appointment calendar, I wanted to use access database to save and retrieve my appointments. However I have more than one property type (Strings, Ints, DateTime) and more than one type of boxes (ComboBox, ListBox, DateTimePicker) to display in the windows forms.
I have managed to write my code for the database with the following code (part of it):
foreach(var appointment in listOfAppointments)
{
OleDbCommand DbCommand = new OleDbCommand(
"INSERT INTO NewAppointmentDatabase " +
"([Start], [Length], [DisplayableDescription], [OccursOnDate], [Location], [IsRecurring], [Frequency], [Occurence]) " +
"VALUES(#Start, #Length, #DisplayableDescription, #OccursOnDate, #Location, #IsRecurring, #Frequency, #Occurence)",
SaveAppntAccess);
DbCommand.Connection = SaveAppntAccess;
DbCommand.Parameters.AddWithValue("#Start", appointment.Start); //is a short time in DateTime
DbCommand.Parameters.AddWithValue("#Length", appointment.Length); //is an int
DbCommand.Parameters.AddWithValue("#DisplayableDescription", appointment.DisplayableDescription); //is a long string
DbCommand.Parameters.AddWithValue("#OccursOnDate", appointment.OccursOnDate(date)); //is a boolean with DateTime as argument
DbCommand.Parameters.AddWithValue("#Location", appointment.Location); //is a string
DbCommand.Parameters.AddWithValue("#IsRecurring", appointment.IsRecurring); //is a boolean with yes/no tickbox
DbCommand.Parameters.AddWithValue("#Frequency", appointment.Frequency); //is a string
DbCommand.Parameters.AddWithValue("#Occurence", appointment.Occurence); //is an int
I have to note that the word date in appointment.OccursOnDate(date) is reddened in visual studio which is kind of weird because the boolean parameter is inherited.
And then comes the tricky part: I want to load my data! But I want to take my values from the database and assign them to each property first, and then take those and display them in the ComboBoxes and TextBoxes and DateTimePickers.
The code goes like this (part of it):
if(LoadAppntAccess.State == ConnectionState.Open)
{
OleDbCommand DbCommand = new OleDbCommand(
"SELECT * FROM NewAppointmentDatabase", LoadAppntAccess);
OleDbDataReader reader = null;
DbCommand.Connection = LoadAppntAccess;
reader = DbCommand.ExecuteReader();
foreach (var appointment in listofAppointments)
{
while (reader.Read())
{
//code to complete
}
}
}
How will I assign the values from each field to each property? I was thinking something like this:
appointment.Start.Add(reader["Start"].ToString());
appointment.Length.Add((reader["Length"].ToString());
appointment.DisplayableDescription(reader["DisplayableDescritpion"].ToString());
But I get errors in all of those - what is the right syntax?
EDIT : I forgot to mention that "start" although it's assigned as DateTime, I used as a ShortTime value because I wanted a ComboBox with time and 30 minute intervals. So it's not exactly a Date. For OccursOnDate it was written as:
public bool OccursOnDate(DateTime date)
{
return date.Date == date;
}
and to retrieve a date I used a DateTimePicker.
2nd edit for more info
My class looks like this:
public class Appointment : IAppointment
{
public DateTime Start { get; set; }
public int Length { get; set; }
public string DisplayableDescription { get; set; }
public bool OccursOnDate(DateTime date)
{
return date.Date == date;
}
//custom members
public int ID { get; }
public string Location { get; set; }
public bool IsRecurring { get; set; }
public string Frequency { get; set; }
public int Occurence { get; set; }
public Appointment()
{
}
but unfortunately it inherits the parameters from IAppointment which has this code.
int ID { get; }
DateTime Start { get; }
int Length { get; }
string DisplayableDescription { get; }
bool OccursOnDate(DateTime date);
//custom members
string Location { get; set; }
bool IsRecurring { get; set; }
string Frequency { get; set; }
int Occurence { get; set; }
The custom members are my addition since I had to put some extra stuff according to the specs.
However I managed to find a syntax based on your answers below.
appointment.Start.((DateTime)reader["Start"]);
appointment.Length.((int)reader["Length"]);
appointment.DisplayableDescription.((string)reader["DisplayableDescritpion"]);
appointment.OccursOnDate((DateTime)reader["OccursOnDate"]);
appointment.Location.((string)reader["Location"]);
appointment.IsRecurring.((bool)reader["IsRecurring"]);
appointment.Frequency.((string)reader["Frequency"]);
appointment.Occurence.((int)reader["Occurence"]);
I still get this message:
Any clues?
From the info you have given i would guess something like this:
appointment.Start = (DateTime)reader["Start"];
appointment.Length = (int)reader["Length"];
appointment.DisplayableDescription = (string)reader["DisplayableDescritpion"];
This is just a simple example, we would need more info to give a better answer. If any of the columns can have a null value you need to handle that as well etc..
access reader's columns like this, using column index (column index 0 is first column from your SELECT clause, 1 is second... etc). As you can see, call reader's right method to get appropriate type of data.
appointment.Start = reader.GetDateTime(0);
appointment.Length = reader.GetInt32(1);
appointment.DisplayableDescription= reader.GetString(2);
you can also get data by specifiying column name.
appointment.Start = reader.GetDateTime(reader.GetOrdinal("Start"));
appointment.Length = reader.GetInt32(reader.GetOrdinal("Length"));
appointment.DisplayableDescription = reader.GetString(reader.GetOrdinal("DisplayableDescritpion"));
I posted in a comment but since it wasn't made clear with no picture I am posting now my previous try that didn't work and explain.
This is the code mentioned both by #Nino and #FsDaniel
If you see the Interface's parameters (in my initial post), they only have the get property which makes Start, Length and DisplaybleDescritption readonly. Thus the error. The rest is ok because they are my custom members and I gave them get and set properties. I do not wish to make any alterations in the Interface, that's why I am asking to find if there can be another solution.

Assign current date to a property in MVC

I am creating a model for users and I want that property joined was set to Now(). Here's my code:
[DefaultValue(DateTime.Now)]
public DateTime joined {get; set;}
I get error:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.
What am I doing wrong? And what's the best way to do what I want?
DateTime.Now is not a constant, but a property that's computed at runtime, which is why you can't do what you're suggesting.
You can do what you're proposing with either:
public class MyClass {
public DateTime joined { get; set; }
public MyClass() {
joined = DateTime.Now;
}
}
Or:
public class MyClass {
private DateTime _joined = DateTime.Now;
public DateTime joined { get { return _joined; } set { _joined = value; } }
}
You could try this in your model class:
private DateTime _joined = DateTime.Now;
public DateTime Joined
{
get { return _joined; }
set { _joined = value; }
}
You can not set expressions to the default value attribute. Because dataannotaions are not runtime attributes. You should set default value by like this
private DateTime _joined = DateTime.Now;
public DateTime Joined
{
get {
return _joined;
}
set {
_joined = value;
}
}
You can do it like what the others suggest, but another alternative is to set it in your action method, after your mapping from view model to domain and just before adding it to the database (if this is what you need to do):
[HttpPost]
public ActionResult Create(YourViewModel viewModel)
{
// Check if view model is not null and handle it if it is null
// Do mapping from view model to domain model
User user = ... // Mapping
user.DateJoined = DateTime.Now;
// Do whatever else you need to do
}
Your domail model for user:
public class User
{
// Other properties here
public DateTime DateJoined { get; set; }
}
I personally would have set it in the action method because the date and time would be more closer to when the user is actually added to the database (assuming this is what you wanted to do). Let says you create your user object at 12:00 then this will be your time when the user is added to the database, but what if you only click the submit button at 12:30? I would much rather prefer 12:30 than 12:00.

Categories

Resources