POCO's, ORM and immutability. How to make them work together? - c#

Let's say I have the following C# class that I want to be immutable. You can only set it by using the parametrized constructor.
public class InsulineInjection
{
private InsulineInjection()
{
// We don't want to enable a default constructor.
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; private set; }
public DateTime DateTime { get; private set; }
public Millilitre Millilitre { get; private set; }
}
Now I would like to use an ORM to create this POCO. However, as far as I can see all .NET ORM's expects properties to be accessible and have a public constructor to be able to create this POCO. So I would have to change my POCO into this:
public class InsulineInjection
{
public InsulineInjection()
{
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get; set; }
}
This however makes my POCO mutable again. Someone using it could simply change any property afterwards which is not wat I want.
As far as I can see it, I could solve this in two different ways:
Write my own data access layer (or modify an orm) to be able to create correct POCO instances using the constructor I created.
Create some kind of mapper. Let the ORM create simple DTO objects and use the mapper to convert the DTO objects to my POCO at the appropriate time.
I'm leaning towards solution 2. Does someone have an example on how to do this? Or does someone have a better solution than the ones I describe above?

Many OR/Ms work as long as there is a default constructor and setters (no matter if they are public or not, they just have to exist)
So this wont work (no default constructor):
public class InsulineInjection
{
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
_millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get { return _millilitre; } }
}
or this (no setter for the last property)
public class InsulineInjection
{
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
_millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get { return _millilitre; } }
}
While this will work:
public class InsulineInjection
{
protected InsulineInjection()
{
// works with many OR/Ms
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; private set; }
public DateTime DateTime { get; private set; }
public Millilitre Millilitre { get; private set; }
}

To avoid the constructor being used by your own code, you can use the Obsolete attribute
[Obsolete("Default constructor only here for the ORM", true)]
public InsulineInjection() {}
Passing true in the attribute will yield a compiler error if you actually call this constructor.

Not all .NET ORMs require public property access to write data.
NHibernate supports writing data to private fields or setters. However, you need to follow one of allowed naming conventions for fields so that it can deduce field name from the property name.
Check out NHibernate documentation about property mapping, particularly take a look at tables Table 5.1. Access Strategies and Table 5.2. Naming Strategies. Look at nosetter access strategy and pick naming strategy which fits your coding style.

This scenario is handled natively by dapper-dot-net.
You just need the order and type of the query fields to match the order and type of the constructor arguments. So for your class the query would be something like:
select millilitre,
,dateTime
,remark
from injections
Unfortunately dapper won't know how to convert something from decimal to millilitre.

Related

Is it possible to point DateTimeOffset custom format for object's property?

Is it possible to point DateTimeOffset custom format for object's property? This object will be serialized/deserialized (JSON) in ASP.NET controller's action.
I thought it can be done through attribute, like `[Required], but I didn't find it.
public abstract class EventDto
{
public EventDto(EventTypes eventType)
{
EventType = eventType;
}
[Required]
public EventTypes EventType { get; }
[Required]
public Guid SessionId { get; set; }
[Required]
// Something like this: [JsonFormat("YYYY-mm-DD HH:MM:SS.FFFFFFFF zzz")]
public DateTimeOffset Timestamp { get; set; }
}
Try something like this
public class Test
{
public DateTime date { get; set; }
public string Timestamp
{
get { return date.ToString("YYYY-mm-DD HH:MM:SS.FFFFFFFF zzz");}
set { date = DateTime.ParseExact(value, "YYYY-mm-DD HH:MM:SS.FFFFFFFF zzz", System.Globalization.CultureInfo.InvariantCulture)}
}
}

How to define initial values according to generic value?

I have a generic entity class.
if T is guid, I want to initialize new guid value .
if T is int, I want to initialize id =0;
if T is string I want to initialize id =string.empty
What is the most suitable way to do this ?
public class BaseEntity<T>{
public string Id { get; set; } ;
public DateTime? CreatedAt { get; set; } = DateTime.Now;
public DateTime? UpdatedAt { get; set; }= DateTime.Now;
public DateTime? DeletedAt { get; set; }
}
You may want to consider using the default keyword to create an instance of any given type at runtime. However, with your given examples, your intentions may not simply be limited to avoiding unset properties.
Given that possibility, you could dynamically create the desired type and box/unbox it to trick the compiler - such as the example I've provided below.
This isn't generally recommended becuase of it's limited scope and general un-maintainability and error-pronedness.
You have other options as well such as creating generic instances using reflection, this may not be ideal since you have very specific "default" values that using reflection may just increase the complexity of the problem more than using a switch()(depending on your target framework, or if/else(like the example i've provided below.)
public class BaseEntity<T>
{
public T Id { get; set; } = (T)GetDefault<T>();
public DateTime? CreatedAt { get; set; } = DateTime.Now;
public DateTime? UpdatedAt { get; set; } = DateTime.Now;
public DateTime? DeletedAt { get; set; }
private static object GetDefault<U>()
{
Type paramType = typeof(U);
if(paramType == typeof(string))
{
return string.Empty;
}
else if(paramType == typeof(Guid))
{
return Guid.NewGuid();
}
return default(U);
}
}

DbContext Set with where query using database first approach EF

I have a database first project with ADO.NET Entity Data model generated classes. All of my classes have same boolean and datetime fields, Ok and Date. I want to create generic method for retrieving T class from DbContext but i'm not sure how to use where in that query since i cant access Ok and Date fields.
note: i can't change generated classes, and i would want to avoid using Linq.Dynamic
ADO.Net generated
public partial class First
{
public int Id { get; set; }
public string NameFirst { get; set; }
public DateTime Date { get; set; }
public bool Ok { get; set; }
}
public partial class Second
{
public int Id { get; set; }
public string NameSecond { get; set; }
public DateTime Date { get; set; }
public bool Ok { get; set; }
}
Retrieve data
public List<SomeModel> LoadFromDatabase<T>(bool ok, DateTime date)
{
var dbData = DbContext.Set(typeof(T)).AsNoTracking().Where(x => x.Ok ??? );
//remap to some model and return it
...
return someModel;
}
Edit 1:
public List<SomeModel> LoadFromDatabase<T>(bool ok, DateTime date) where T : IDateOk
{
var dbData = DbContext.Set(typeof(T)).AsNoTracking().Where(x => x.Ok &&);
//remap to some model and return it
...
return someModel;
}
public interface IDateOk {
DateTime Date { get; set; }
bool Ok { get; set; }
}
Edit 2:
I was missing class in method so it should be like this
public List<SomeModel> LoadFromDatabase<T>(bool ok, DateTime date) where T : class IDateOk
Define an interface for the common properties:
public interface IDateOk {
DateTime Date { get; set; }
bool Ok { get; set; }
}
Here is a tutorial how to add the interface to the generated classes:
Getting the Entity Framework to Generate an Interface for Mocking
Constrain your method to require this interface:
public List<SomeModel> LoadFromDatabase<T>(bool ok, DateTime date) where T: IDateOk
Now you should be able to access OK and Date in the implementation.

Specifying a format inside of a class

I'm currently writing some software for a jumping-competition.
I've made a class to put my riders in and in this class theres also a variable to store the timing of the rider. I'm using a timespan for this as I also need to use milliseconds.
This is not a problem so far.
However, when I link my list with riders to a datagridview, the value of the time is being represented as 00:00:00 while I would need it to be 00:00.000
Is there a way that I can specify the outputstring either in my class or in my datagridview?
I know I could fill the datagridview manually and bypass the issue that way, but that doesn't really make sense.
So how can I tackle this problem?
Cheers,
Kenneth
public class RidersClass
{
public string firstnameRider { get; set; }
public string lastnameRider { get; set; }
public string nameHorse { get; set; }
public string Stable { get; set; }
public TimeSpan timeRound { get; set; }
public int penalty { get; set; }
}
Riders = new List<RidersClass>();
private void showList()
{
var source = new BindingSource();
source.DataSource = Riders;
grdRiders.DataSource = source;
}
One way to do it would be to create a wrapper class around TimeSpan like this
public class TimeSpanWrapper
{
public TimeSpan Time{get;set;}
public override string ToString()
{
return string.Format("{0}:{1}.{2}",Time.Hour,Time.Minute,Time.Second);
}
}
Then replace the TimeSpan object in your class with the TimeSpanWrapper, when the binding will occur for this class the ToString() method will be called and return the string in the format you like.

Lots of constructor parameters - Is there a better way?

public class HourlyForecastData
{
public DateTime DateTime { get; private set; }
public decimal TemperatureCelcius { get; private set; }
public decimal DewPoint { get; private set; }
public string Condition { get; private set; }
public int ConditionCode { get; private set; }
public int WindSpeed { get; private set; }
public string WindDirection { get; private set; }
public decimal WindDegrees { get; private set; }
public int UltravioletIndex { get; private set; }
public decimal Humidity { get; private set; }
public decimal WindChill { get; private set; }
public int HeatIndex { get; private set; }
public decimal FeelsLike { get; private set; }
public decimal Snow { get; private set; }
public HourlyForecastData(DateTime dateTime, decimal temperatureCelcius, ...)
{
DateTime = dateTime;
TemperatureCelcius = temperatureCelcius;
//...set all the other properties via constructor
}
}
I am trying to learn better software design and OOP. I'm creating a library that can access a weather service that replies with XML. There are a lot of different fields provided by the service, so I've created properties for each of the XML fields. However, it feels a bit messy to have that number of properties set via the constructor. I could omit the constructor and have public setters but I'm trying to make an immutable class.
I've looked around at different design patterns for this and there seems to be some "Builder" and "Factory" patterns. However, I'm struggling to understand how I would apply that to my code. Or should I be using something completely different to fill the properties in these objects?
In this case composition might be a good fit. Especially since there are some parameters that belongs to specific categories.
For instance:
public int WindSpeed;
public string WindDirection;
public decimal WindDegrees;
Create a new object for them and then access the different values as:
weatherData.Wind.Speed;
and pass the new wind object to the constructor:
var wind = new Wind(xmlData.WindSpeed, xmlData.WindDirection, xmldata.WindDegrees);
var weatherReport = new WeatherReport(wind, /* .... */);
I would also introduce a few enums. Because as of now, the users of the weatherReport would for instance have to know which values the string WindDirection can have. If you convert the string to an enum instead it's a lot easier to use the different values.
A final note is that I typically only use constructors if the are some values that really have to be specified for the class to have a valid state. For instance, in your case the minimum valid state would be a date and the temperature? Then just put those in the constructor.
Re Is there a better OOP approach?
A large number of properties on a class can often indicate a need for splitting the class up (the Single Responsibility Principle of SOLID).
e.g. It would appear that HourlyForecastData models Wind (speed and direction), Precipitation (Snow, Dew and Rain), and Temperature (Min, Max ...) These concerns can be split into separate classes, and then the HourlyForecastData would be a composition of the three.
Re : Builder Pattern
The Builder Pattern can be useful to ease the burden during construction of large (often immutable) classes or graphs, but would obviously require additional (mutable) Builder class(es) to build up the target class representation (i.e. HourlyForecastData) and eventually create it (viz, by constructing it immutably by passing it all parameters to the constructor). So it isn't less effort, if that is what you required by 'better', but this can certainly can be easier to read e.g.:
HourlyForecastData todaysForecast = new HourlyForecastDataBuilder()
.WithBaseline(ObjectMother.WinterSnow) // Provide an archetype
.WithPrecipitation(snow: 5, rain:1) // Dew defaults to 0
.Build();
Baseline archetypes / object mothers would be useful if the weather patterns in an area were frequently stable and just required small adjustments. IMO builder pattern is most useful in Testing. I can't see an obvious fit in an Xml Serialization usage.
See also Named and Optional parameters
Re: Immutability
A private setter technically still allows mutability, although restricted within the class itself. C#6 and later supports getter-only auto properties which is the simplest form for implementing immutable properties
public class HourlyForecastData
{
public DateTime DateTime { get; }
...
public HourlyForecastData(DateTime dateTime, ...)
{
// Get only auto properties can only be set at construction time
DateTime = dateTime;
...
Unrelated, but Scala offers an even more concise syntax than C# for defining immutable public properties on a class, by declaring them once in the (primary) constructor:
class HourlyForecastData(val temperature: Int, val station: String, ...) {
}
Without the need for any further property or backing fields, whilst expressing and enforcing immutability. However, the burden still remains on the caller to provide all the parameters (whether directly, or via Builder, etc).
Re : Xml
If you are offering an API, I would suggest using WebAPI. Instead of building Xml serialization concerns into your DTO classes, I would suggest instead on relying on Content Negotiation. This will allow the caller to determine whether the data should be returned in Xml or JSON format.
* Note however that Xml Deserialization technologies often make use of reflection to populate DTO properties, which MAY require that the serializable properties have setters (even if private).
One way is to use a struct and pass it in instead. It also makes using the class easier as you only need to declare the struct state variable, change whatever differs from the "default" then pass it in.
public struct HourlyForecastDataState
{
public DateTime DateTime;
public decimal TemperatureCelcius;
public decimal DewPoint;
public string Condition;
public int ConditionCode;
public int WindSpeed;
public string WindDirection;
public decimal WindDegrees;
public int UltravioletIndex;
public decimal Humidity;
public decimal WindChill;
public int HeatIndex;
public decimal FeelsLike;
public decimal Snow;
}
public class HourlyForecastData
{
public DateTime DateTime { get; private set; }
public decimal TemperatureCelcius { get; private set; }
public decimal DewPoint { get; private set; }
public string Condition { get; private set; }
public int ConditionCode { get; private set; }
public int WindSpeed { get; private set; }
public string WindDirection { get; private set; }
public decimal WindDegrees { get; private set; }
public int UltravioletIndex { get; private set; }
public decimal Humidity { get; private set; }
public decimal WindChill { get; private set; }
public int HeatIndex { get; private set; }
public decimal FeelsLike { get; private set; }
public decimal Snow { get; private set; }
public HourlyForecastData(HourlyForecastDataState state)
{
DateTime = state.dateTime;
TemperatureCelcius = state.temperatureCelcius;
//...etc
}
}
//Usage:
HourlyForecastDataState HFDstate = new HourlyForecastDataState();
HFDstate.temperatureCelcius = 100 //omg, it's hot!
HourlyForecastData HFD = new HourlyForecastData(HFDstate);

Categories