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.
Related
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
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");
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 { ... }
Long Description: I'm writing a basic search by filter function from an entity, so I can do something like this:
public Entity GetEntityBy(Entity filter)
{ }
public IList<Entity> GetEntitiesBy(Entity filter)
{ }
The problem is with non nullable types (int, float, etc), and I don't want to "force" all properties to be written as nullables. I want to avoid any kinds of rules (such as applying attributes or implementing my own get/set) so I can write the entity just as usual and simply use this filter function.
The code looks like this:
public class Entity
{
public int EntityID { get; set; }
public string Name { get; set; }
public DateTime RegisterDate { get; set; }
//Other properties
}
public IList<Entity> GetEntitiesBy(Entity filter)
{
if (filter != null)
{
if (filter.EntityID > 0)
{
//Add criteria to filter by ID
//In this case it works because there shouldn't have any IDs with 0
}
//this won't work because DateTime can't be null
//I can't check the default value as well because there are some searchs using the default value and I don't want to ignore that
if (RegisterDate != null)
{
}
}
}
It's supposed to be a simple equal filter depending on the values found in the filter parameter, but as it is now I don't know when I should ignore the default values or not.
I already have a SCRUD manager sort of class, so I want to add a function call to the class that it belongs so I can check when a property has been read/written to.
Short Description: How do I add a function call before a property's get or set acessor is called on a dynamic class? Is this even possible?
I am using BlogEngine.NET and need to set the BlogId to a specific Guid (blogIdstr). I can't seem to figure out how to change it from the default blogId. This is the code I have at the moment but it is giving me a StackOverflowException...
These two are in the base class...
public virtual TKey Id { get; set; }
public Guid BlogId
{
get
{
return BlogId; <-- Stack Overflow
}
set
{
string blogIdstr = "FCA96EFB-D51C-4C41-9F85-3EEB9C50BDE7";
Guid blogIdGuid = Guid.Empty;
blogIdGuid = Guid.Parse(blogIdstr);
}
}
And this one is in blog.cs...
public override Guid Id
{
get { return base.Id; }
set
{
base.Id = value;
base.BlogId = value;
}
}
How can I set the blogId and avoid the StackOverflowException? Thanks in advance.
For the first one, in BlogId, you're returning BlogId, which fires the Getter that returns... BlogId. Boom, stack overflow. Return blogIdGuid in your public getter instead of BlogId.
I'm guessing the second one is related to the first, but without more code I can't tell offhand.
Edit: Whoops, misread the code. Yeah, use a backing class-level property called _blogId and set that in the setter and return it in the getter.
You just need to introduce a backing variable
private Guid _blogId; and be sure to set that field in your set method
public Guid BlogId
{
get
{
return _blogId;
}
set
{
string blogIdstr = "FCA96EFB-D51C-4C41-9F85-3EEB9C50BDE7";
Guid blogIdGuid = Guid.Empty;
blogIdGuid = Guid.Parse(blogIdstr);
_blogId = value;
}
}
Your get method is calling itself, and your set method is essentially issuing a no-op by setting a value local to the method. You need a backing field for your property if you want to do something inside of the getter and setter:
private Guid _blogId;
public Guid BlogId
{
get
{
return _blogId;
}
set
{
//some operation against value here, Validate(value), etc.
_blogId = value;
}
}
If you have no action to take in the getter/setter, you can use an auto property, which will generate the backing field for you:
public Guid BlogId { get; set; }
What you can't do, and what it appears you're really trying to do here, is pass a different type into a property - to do that you'd need a method on the class, i.e.:
public bool TrySetBlogId(string newId)
{
Guid id;
var stringIsGuid = Guid.TryParse(newId, out id);
if (stringIsGuid)
{
BlogId = id;
}
return stringIsGuid;
}