Does Entity Framework call property setters with null when rehydrating entities for columns with DB NULL? - entity-framework

I have a string property
public string XYZ
{
get => // do stuff
set => // do stuff which handles null
}
because I'm hoping it will get called....
But will it really?
(EF6.4)

It appears it will. If you implement the property with a backing field it's easy to test this by putting a breakpoint in the setter. EG
private string xyz;
public string XYZ
{
get
{
return xyz;
}
set
{
xyz = value;
}
}
And I think it would have to, as EF does not know whether your entities have a non-standard default value for a property. eg you could write
private string xyz = "none";
public string XYZ
{
get
{
return xyz;
}
set
{
xyz = value;
}
}
And so the hydration code would need to run the setter to get a correct result.

Related

Basic working of getter setter when they are called

If we are Sending a [GET] Request to API then then as per my understanding setter will be called and it will set the value of the respective data members.
Will Get be also called here or what is the working ?
If we are sending a [POST[ request to API then as per my understanding the getter will be called and the data members data will be send to the API as per getter.
Will Set also be called here or what is the working?
In case of Get Request refer below class getter setter:
public class Car
{
private string _speed;
public string Speed
{
get { return _speed; }
set {
if (value >= 0 && value <= 100)
{
_speed = value;
}
}
}
}
Will Get be also called here?
In case of [POST] Request refer below code of getter setter
public class Student
{
private string _name;
public string Name
{
get { return _name.toUpperCase(); }
set {
_name = value;
}
}
}
Will Set also be called here?
Please help me understand this basic concept.

How can I use an extended entity to create a new property in my EF6 class with property changed notification?

I have a table in my entity model called prices. It has several fields named value0, value1, value2, value3, value4... (these are their literal names, sigh..). I cannot rename them or in any way change them.
What I would like is to use an extended entity to create a new property called values. This would be a collection containing value1, value2 etc...
To get access to the values I would then simply need to write prices.values[1]
I need property changed notification for this.
So far I have tried this;
public partial class Prices
{
private ObservableCollection<double?> values = null;
public ObservableCollection<double?> Values
{
get
{
if (values != null)
values.CollectionChanged -= values_CollectionChanged;
else
values = new ObservableCollection<double?>(new double?[14]);
values[0] = value0;
values[1] = value1;
values[2] = value2;
values.CollectionChanged += values_CollectionChanged;
return values;
}
private set
{
value0 = value[0];
value1 = value[1];
value2 = value[2];
}
}
private void values_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Values = values;
}
}
The issue comes when trying to set values. if I try to set a value by writing
prices.values[0] = someValue;
The new value is not always reflected in the collection (i.e. when I have previously set value and then try to overwrite the value).
I am willing to try any approach that would achieve my goal, I am not precious about having my solution fixed (although if anyone can explain what I'm missing that would be great!)
You could implement an indexer on Prices class without using a collection.
You can use switch to select the property to write or you can use reflection.
In this case I use reflection.
public double? this[int index]
{
get
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
return (double?)GetType().GetProperty(propertyName).GetValue(this);
}
set
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
GetType().GetProperty(propertyName).SetValue(this, value);
// Raise your event here
}
}

OData + EF. Writing geography types

I have an Odata service which exposes an EF6 code first model. Some of these entities include DbGeography fields. I can GET these field, despite the DbGeography fields having quite an ugly serialized format, but I cannot figure out how to POST or PUT an entity to the service. The DbGeography type seems to struggle with deserialization.
Can anyone provide an example or link for how to do this?
I've had this problem too. Its a bug apparently.
Either two choices here - drop down to EF5 for the old System.Data.Entity.DbGeography (rather than System.Data.Entity.Spatial.DbGeography), or wait until they patch it.
Edit: Its been a long time, and so far the only hack I've come up with is this as a way to write to the properties and hide the ugly serialised format (however still cannot query against it.
private bool hasSetLongitude = false;
private bool hasSetLatitiude = false;
private double? longitude = null;
private double? latitiude = null;
/// <summary>
/// Get or set the coordinates.
/// </summary>
[Column("engi_coord"), Required]
public DbGeography Coordinates { get; set; }
/// <summary>
/// Get or set the lang coordinates.
/// </summary>
[Column("engi_lng"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double? Longitude
{
get
{
return this.Coordinates != null ? this.Coordinates.Longitude : (double?)null;
}
set
{
this.longitude = value;
this.hasSetLongitude = true;
if (this.hasSetLongitude)
{
if (this.longitude.HasValue &&
this.latitiude.HasValue)
{
this.Coordinates = DbGeography.PointFromText(string.Format("POINT({0} {1})", this.longitude.Value, this.latitiude.Value), 4326);
}
else
{
this.Coordinates = null;
}
}
}
}
/// <summary>
/// Get or set the lat coordinates.
/// </summary>
[Column("engi_lat"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double? Latitude
{
get
{
return this.Coordinates != null ? this.Coordinates.Latitude : (double?)null;
}
set
{
this.latitiude = value;
this.hasSetLatitiude = true;
if (this.hasSetLatitiude)
{
if (this.longitude.HasValue &&
this.latitiude.HasValue)
{
this.Coordinates = DbGeography.PointFromText(string.Format("POINT({0} {1})", this.longitude.Value, this.latitiude.Value), 4326);
}
else
{
this.Coordinates = null;
}
}
}
}
Migrate to add the computed columns:
this.Sql("ALTER TABLE dbo.engi_engineer ADD engi_lng AS engi_coord.Long");
this.Sql("ALTER TABLE dbo.engi_engineer ADD engi_lat AS engi_coord.Lat");
Now ignore the coordinates property from API:
this.EntityType.Ignore(p => p.Coordinates);
Well it has been over a year now and it doesn't look like this is getting fixed anytime soon. Especially with EF7 coming out very soon.
So, I would like to approach this another way.
What if the DbGeography type was not exposed as a property on the class and instead we expose a Latitude and Longitude property that are not mapped and then on their GET / SET we update the hidden DbGeography property?
I have tried this but have been unsuccessful with EF.
What you can do is inside the POST / PUT controller calls is use a stored procedure or SQL text to update the data.
If I find out how to get this to work with EF I will post here.

Setting Field Within Class using Reflection

This should be easy but it's managed to confound me a few times. I'm trying to set a Value within a class using Reflection.
public class EngineeringValueClass<T> {
public T Value { get { } set { } }
}
Then in a calling class I have:
public class MyClass {
EngineeringValueClass<double> Value1;
EngineeringValueClass<double> Value2;
// Along with many others.
public void SetValueByName(object FieldName,object FieldValue) {
// Get the "Value" field of a generic EngineeringValueClass<double>
PropertyInfo MyValuePropRef =
typeof(EngineeringValueClass<double>).GetProperty("Value");
// Get the field within this class I want to set.
FieldInfo MyNameFieldRef = typeof(MyClass).GetField(FieldName.ToString());
MyValuePropRef.SetValue(MyNameFieldRef.GetValue,
FieldValue,
null);
}
}
My goal is to have
SetValueByName("Value1",2.3);
set Value1's "Value" using the set accessor. I presume my problem is that MyNameFieldRef.GetValue doesn't return an object reference but rather a "Value", but I'm not sure how to work around that. I don't want to pass "this" because that's not right either.
Okay, I finally figured this out:
public void SetValueByName(object FieldName, object FieldValue) {
Type t = typeof(MyClass);
FieldInfo PrimaryField = t.GetField(FieldName.ToString());
object ValueField = PrimaryField.GetValue(this);
// To get the type of Value
MethodInfo TypeValueField = ValueField.GetType().GetMethod("GetValueType");
Type ValueType = (Type) TypeValueField.Invoke(ValueField, null);
// I added a "GetValueType () { return typeof(T); } to EngineeringValueClass
if (ValueType == typeof(Int16))
{
((EngineeringValueClass<Int16>)ValueField).Value = Int16.Parse(FieldValue.ToString());
}...
}

How to compare all properties values from a two equal classes

I've a class defined as follows:
Public Class DeviceConfig
Private _maxNumCodesGlobal As Integer
Private _maxNumCodesDataMatrix As Integer
Private _maxNumCodesQR As Integer
Private _maxNumCodesBarcode As Integer
Private _partialResults As String
Private _allowIdenticalSymbols As String
Private _datamatrixValidation As Integer
Private _datamatrixValidationType
'AND MUCH MORE PROPERTIES
'GETTERS & SETTERS
End Class
as you can see it's a long list of properties in this class.
I need to compare the values of the properties from an instance with the values of the properties of another instance.
Is there a way to iterate through all of them, or even better, just comparing both classes and get true/false if they have the same properties values or not?
if instance1=instance2 then true
Thank you
I encountered the same problem and created this method. Hopefully it will help you.
It uses reflections to iterate through the public fields, ignoring those with the JsonIgnore annotation.
This method is not considering fields as List, Set, etc.
You can change it to work for properties instead of fields.
protected <T> boolean equals(T object1, T object2) {
Field[] fields = object1.getClass().getFields();
for (Field field : fields) {
if (field.getAnnotation(JsonIgnore.class)!= null) continue; //do not check the fields with JsonIgnore
Object value1;
Object value2;
try {
value1 = field.get(object1);
value2 = field.get(object2);
} catch (Exception e) {
logger.error("Error comparing objects. Exception: " + e.getMessage());
return false;
}
//comparing
if (value1 == null) {
if (value2 != null)
return false;
} else if (!value1.equals(value2))
return false;
}
return true;
}