I have a POCO that can't have any nullable properties, for various reasons, but the database I'm connecting to has null values for some of these corresponding properties, so I have to handle these and set them to something else in the property getter/setter logic. But I'm still getting...
Constraint Exception was unhandled by user code: The 'DischargeDate' property on 'Visits' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.DateTime'.
...Here's my property logic....
public class Visits
{
private DateTime _dischargeDate;
public DateTime DischargeDate
{
get {
if (this._dischargeDate == null)
{
this._dischargeDate = DateTime.MinValue;
return this._dischargeDate;
}
else
{
return this._dischargeDate;
}
}
set
{
if (value == null)
{
this._dischargeDate = DateTime.MinValue;
}
else
{
this._dischargeDate = value;
}
}
}
...and the DbContext is just straight forward, like...
public class MyDBContext : DbContext
{
public MyDBContext(string connection)
: base(connection)
{
}
public DbSet<Visits> Visits { get; set; }
}
I have no idea why I'm getting this error. It throws when the context is loaded. Or to be more specific, when I try to access the DbSet<Visit> Visits, like _dbcontext.Visits;
DateTime can't be null. So even though your setter is checking for null (which I'm surprised that comparison even passes), a property of DateTime cannot be set to null. So that's why EF is throwing that error and thus that logic won't work.
If the database is going to have nulls in it, you need your POCOs to have DateTime? as their property type so that EF can set it to null.
Simply doing:
public class Visits
{
private DateTime _dischargeDate;
public DateTime? DischargeDate
{
get {
return _dischargeDate;
}
set
{
if (value == null)
{
this._dischargeDate = DateTime.MinValue;
}
else
{
this._dischargeDate = value.Value;
}
}
}
}
would work - _dischargeDate would never be null
Related
I'm using lazy load for "relationship" properties and struggling when saving object because when I check to see if everything is OK before saving, the properties I'm checking get loaded from the db, losing the object's "saving" status.
Consider this pseudo-code:
public class Project
{
private int _ProjectId;
private string _ProjectName;
private ProjectType _ProjectType;
public int ProjectId
{
get { return _ProjectId; }
set { _ProjectId = value; }
}
public string ProjectName
{
get { return _ProjectName; }
set { _ProjectName = value; }
}
public ProjectType ProjectType
{
get
{
if (_ProjectId != 0 && _ProjectType == null)
{
... load _Projectype from db here
}
return _ProjectType;
}
set
{
_ProjectType = value;
}
}
public Project Save()
{
if(this.ProjectType != null) // <<-- if the _projectId is != 0 (typically during updates or delete operations, the prop is loaded from the db!!!
adpt.Save(this);
}
}
When the control is inside the class, I can of course reference the private member to avoid dynamic loading, but what if someone use the object from the outside? A simple test "if(Prj.ProjectType != null)" will inadvertently load the property.
It seems I need a state to inhibit the loading during saving operation and I was wondering if there is a pattern out there to help me.
Many thanks, Antonio
I have a class that should track the last time it was accessed and I have a public property that exposes that last access time value which is set privately.
My class is defined as follows:
internal class DeviceModelCacheItem
{
private int _cacheId;
private List<DeviceModel> _deviceModels;
private DateTime _lastAccess;
public DeviceModelCacheItem(int cacheId, List<DeviceModel> deviceModels)
{
_cacheId = cacheId;
_deviceModels = deviceModels;
_lastAccess = DateTime.UtcNow;
}
...
public List<DeviceModel> DeviceModels
{
get
{
_lastAccess = DateTime.UtcNow;
return _deviceModels;
}
set
{
_lastAccess = DateTime.UtcNow;
_deviceModels = value;
}
}
public DateTime LastAccess
{
get
{
return _lastAccess;
}
}
}
I am accessing this value in a seperate class method as follows:
var cacheItem = _deviceModelCache.SingleOrDefault(x => x.CacheId == deviceTypeId);
if(cacheItem != null && DateTime.UtcNow.Subtract(cacheItem.LastAccess).TotalSeconds > 120)
{
...
}
Where _deviceModelCache is a collection of DeviceModelCacheItem instances.
I'm finding that whenever I try and access this value, the private value will always be updated making it impossible to use it as a tracking value. Why is this being updated?
EDIT
I've included more code showing how I'm access the DateTime value. The collection of DeviceModelCacheItem instances are held in a singleton as follows:
EDIT 2
I've as also added the db access code and also included where I'm updating the _lastAccess property. I figure I may have a deferred execution problem.
public class DeviceModelRepository
{
private List<DeviceModelCacheItem> _deviceModelCache;
private static readonly Lazy<DeviceModelRepository> instance = new Lazy<DeviceModelRepository>(() => new DeviceModelRepository());
public static DeviceModelRepository Instance
{
get
{
return instance.Value;
}
}
private DeviceModelRepository()
{
_deviceModelCache = new List<DeviceModelCacheItem>();
}
public IEnumerable<DeviceModel> GetAllDeviceModelsByDeviceTypeId(int deviceTypeId)
{
return GetAllDeviceModelsByDeviceTypeId(GlobalConfiguration.APP_CACHE_ENABLED, deviceTypeId);
}
private IEnumerable<DeviceModel> GetAllDeviceModelsByDeviceTypeId(bool enableCache, int deviceTypeId)
{
var cacheItem = _deviceModelCache.SingleOrDefault(x => x.CacheId == deviceTypeId);
//Debugger attached here
if(cacheItem != null && DateTime.UtcNow.Subtract(cacheItem.LastAccess).TotalSeconds > 120)
{
...
using (GadgetContext db = new GadgetContext())
{
var deviceModels = db.DeviceModels.Where(x => x.DeviceTypeId == deviceTypeId).ToList();
if (enableCache && deviceModels != null && deviceModels.Count > 0)
{
try
{
if(cacheItem == null)
{
_deviceModelCache.Add(new DeviceModelCacheItem(deviceTypeId, deviceModels));
}
else
{
cacheItem.DeviceModels = deviceModels;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}
}
...
}
...
}
}
As pointed out by #JamesLucas the issue of the DateTime.UtcNow value always being updated was down to a deferred execution error in my code. My date time value was being updated every time entity framework deferred execution to grab items from the DB.
So basically I've come across some readonly properties on this one class that the writer of the class told me I could make settable for a specific task. Problem is, they get their value through manipulation most of the time, not directly from a private variable in the class.
Example:
public decimal? AccruedInterest
{
get
{
if (this.Result != null)
{
return this.GetExchangedCurrencyValue(this.Result.AccruedInterest.GetValueOrDefault(decimal.Zero));
}
return null;
}
}
So if I want to add a setter, I don't want to worry about setting that Result object because I'm not sure if on it's way back out it's going to be drawn correctly.
Would I be able to do something like this?
private decimal? _AccruedInterest;
public decimal? AccruedInterest
{
get
{
if (this._AccruedInterest.HasValue)
{
return this._AccruedInterest.Value;
}
if (this.Result != null)
{
return this.GetExchangedCurrencyValue(this.Result.AccruedInterest.GetValueOrDefault(decimal.Zero));
}
return null;
}
set
{
this._AccruedInterest = value;
}
}
Or do any of you see issues that could arise from this (besides the fact that it's now changeable)?
Well your only problem with this is if they set the value to be null and you want your property to return null rather than evaluate the if statement.
But you might not allow them to set null, in which case you should add a check in the setter.
set
{
if (value == null)
throw new NullArgumentException("AccruedInterest");
this._AccruedInterest = value;
}
If it is valid for them to set null, you probably need another boolean flag to tell if the value has been set.
private bool _accruedInterestSet;
private decimal? _accruedInterest;
public decimal? AccruedInterest
{
get
{
if (this._accruedInterestSet)
{
return this._accruedInterest; //don't return .Value in case they set null
}
if (this.Result != null)
{
return this.GetExchangedCurrencyValue(this.Result.AccruedInterest.GetValueOrDefault(decimal.Zero)) ;
}
return null;
}
set
{
this._accruedInterestSet = true;
this._AccruedInterest = value;
}
}
I don't know how it's supposed to work, but syntactically I don't see anything wrong with your code.
I have a Session that stores an int. I usually do the following...
if(Session["test"] == null)
Now that I am comparing...
public ActionResult NumbersGame(int myNum)
{
if(Session["test"] != myNum)...
How do I do that?
(int)Session["test"] will fail if that session variable is either null or not a number. Use this instead...
var myNumber = Convert.ToInt32(Session["test"]);
myNumber will be 0 if 'test' is null or not a number
Cast it to an int:
if ((int) Session["test"] != myNum) ...
Another way of checking and using the value stored in your Session() object involves using the TryParse feature.
int intTest;
if (int.TryParse(Session["test"].ToString(), out intTest))
{
// intTest will have the value in Session["Test"] stored as an integer
}
I like it because it's compact and simple.
Simple overview of how I would do it:
It may solve other problems too:
First we define interface:
public interface ISessionWrapper
{
int? SomeInteger { get; set; }
}
Then we make HttpContext implementation:
public class HttpContextSessionWrapper : ISessionWrapper
{
private T GetFromSession<T>(string key)
{
return (T) HttpContext.Current.Session[key];
}
private void SetInSession(string key, object value)
{
HttpContext.Current.Session[key] = value;
}
public int? SomeInteger
{
get { return GetFromSession<int?>("SomeInteger"); }
set { SetInSession("SomeInteger", value); }
}
}
Then we define our base controller:
public class BaseController : Controller
{
public ISessionWrapper SessionWrapper { get; set; }
public BaseController()
{
SessionWrapper = new HttpContextSessionWrapper();
}
}
Finally:
public ActionResult NumbersGame(int myNum)
{
if (SessionWrapper.SomeInteger == myNum)
//Do what you want;
}
No need to cast here!! And if you wanted to test your controller, you have no problem with Session. You just Mock ISessionWrapper and pass it to SessionWrapper variable.
I would test for null (to detect Session expiry), then cast:
object value = Session["test"];
if (value == null)
{
// The value is not in Session (e.g. because the session has expired)
// Deal with this in an application-specific way, e.g. set to a default,
// reload the Session variable from the database, redirect to a home page, ...
...
}
else
{
myNumber = (int) value;
}
...
The problem with using Convert.ToInt32 is that it will simply return 0 if your session has expired, which may not be desirable depending on your application.
Simple question, hopefully a simple answer:
I'd like to do the following:
private DateTime m_internalDateTime;
public var DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = value; } // here value is of type DateTime
}
The above is just an example of what I'm trying to do. I'd like to have a public accessor to an internal variable of type x. I want the get that variable as a string, but set it using something of type x.
Is this possible?
--edit--
I just realized I could do something like:
private DateTime m_internalDateTime;
public object DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = (DateTime)value; } // here value is of type DateTime
}
But then, let say I use type y instead of a "string" as my 'get' type. If I want to use "DateTimeProperty" else where in my code, I'd have to cast it.
No. You can obviously add the .ToString() in the calling code, but you can't do what you propose without different names like this:
private DateTime m_internalDateTime;
public DateTime SetDateTime { set { m_internalDateTime = value; } }
public string GetDateTime { get { return m_internalDateTime.ToString(); } }
Or, even better to use methods instead of properties (as noted in the comments):
private DateTime m_internalDateTime;
public void SetDateTime(DateTime dateTime) { m_internalDateTime = dateTime; }
public string GetDateTime() { return m_internalDateTime.ToString(); }
Keep in mind that var is for implicitly, compile-time typed variables, not dynamic variables.
Definitely do not do what you noted in your edit. It introduced a break in convention, possible performance implications (albeit slight), and significant localization problems.
As a property, no this is not possible. You could make Get and Set methods that are of different types, but for a property the types must be the same.
EDIT:
While:
private DateTime m_internalDateTime;
public object DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = (DateTime)value; } // here value is of type DateTime
}
is syntactically correct, will compile and allows you to accept DateTime as input and return a string, this would not be a good plan. It works, but it makes you and anyone accessing this code, perform unneeded validation. Additionally, it is vulnerable to another developer in the future, not knowing, or realizing the implicit rules, for which you have lost compile time safety. Additionally, its hardly any more code to create either two properties, or two methods that accomplish the same goal, in a strongly typed manner.
Personally, I would recommend using two methods (see Jeff Yates comment for a good explanation as to why).
private DateTime m_internalDateTime;
public string GetDateTime()
{
return m_internalDateTime.ToString();
}
public void SetDateTime(DateTime dateTime)
{
m_internalDateTime = dateTime;
}
Not that way, but you can certainly have a second property that accesses the m_internalDateTime field.
public string DateTimeString
{
get { return m_internalDateTime.ToString(); }
}
Maybe that helps
public class TDecimal
{
private decimal? m_value;
public bool HasValue { get { return m_value.HasValue; } }
public decimal Value { get { return m_value.Value; } }
public static implicit operator TDecimal(string a_value)
{
decimal d;
if (decimal.TryParse(a_value, out d))
{
return new TDecimal() {m_value = d};
}
return new TDecimal() {m_value = null};
}
public static implicit operator decimal(TDecimal a_value)
{
if(a_value.HasValue)
{
return a_value.Value;
}
throw new ArgumentNullException("a_value");
}
}
public class A
{
public TDecimal Prop { get; set; }
}
A a = new A();
a.Prop = "123";
if (a.Prop.HasValue)
{
decimal d = a.Prop;
}
Simple answer no, to your outside code your property will behave the exact way that a field would, you can't have a property having different set/get types just as you couldn't have a filed be set with a type and when you request it's value get a different type back.
how about:
private DateTime intDT;
public string DateTimeProperty
{
get { return intDT.ToString(); } // Return a string
set
{
DateTime dt;
if (DateTime.TryParse(value, out dt))
intDT = dt;
else throw new ArgumentException(string.Format(
"{0} cannot be converted to a DateTime.", value);
}
}