Suppose you need to store some values in a table formed by several columns (such as a relational database): for example, int for the first column, string for the second one, DateTime for the third one, etc..
If one or more column are like a primary key, then we could use an IDictionary, whose Key would be the set of fields that acts as a primary key. The remaining fields represent the Value. In this case I could create one or two classes/structures. For example, if the primary key is simply an existing type, we will only have to create a class/struct like the following:
public class MyValue
{
public int Field1;
public double Field2;
public string Field3;
}
The dictionary could be a Dictionary<int, MyValue>, while the table could be the following.
public class MyTable
{
private Dictionary<int, MyValue> _table;
...
}
Obviously, according to the application domain there may be ranges and/or rules of validity for the above fields: for example, Field1 may have to be positive, and so on...
As a first alternative I could design the MyValue class so that it throws some exceptions in order to identify the "violation of rules". But perhaps this approach might be excessive, especially if the class MyValue is used only internally to MyTable: in this case I would write code like the following and handle validity error within MyTable class: that is, MyTable class checks the data fields before inserting them into the dictionary, so MyValue would be a "stupid" class...
namespace MyNamespace
{
class MyValue
{
// only public fields
}
public class MyTable
{
private Dictionary<int, MyValue> _table;
...
public void Add(int key, int field1, double field2, string field3)
{
// some code to check validity range for fields
...
}
}
}
Is this solution correct? Or should I avoid this approach? Should I always define a class/struct in a complete manner (exceptions handling, Equals, GetHashCode methods?
What you've done looks overly complicated, brittle and will ultimately lead to maintainability nightmares.
I'd say you have two options.
Option one: use a DataTable. It doesn't have to be backed by an actual database and you can define it's layout (including column definitions) at runtime.
Option two: Define a class that implements your "record" logic. Define a Collection to hold that class. Use LINQ to "query" the collection for whatever you need.
The primary difference between the two options is that a DataTable is very limited in the type of rules you can employ. Option 2, OTOH, allows you to build precisely what you want.
I would let the values check their consistency themselves. If you implement the fields as properties, the setter can do checks and throw an exception is the value is out of range for instance.
I also would suggest a somewhat more flexible approach. Define an interface that your table records must implement
public interface IRecord<PK>
{
PK ID { get; }
}
Records must have an ID, which will be used as primary key. We use a generic primary key type PK.
Now you can define a value class like this
public class MyValue : IRecord<int>
{
private int _field1;
public int Field1
{
get { return _field1; }
set
{
if (value < 0 || value > 1000) {
throw new ArgumentException("Value of 'Field1' must be between 0 and 1000");
}
_field1 = value;
}
}
public double Field2;
#region IRecord<int> Members
public int ID { get { return Field1; } }
#endregion
}
As you can see, it implements IRecord<int> and returns Field1 as ID. Field1 checks the values passed to it. If the primary key is made up of several fields you can use a type like Tuple (.NET 4.0) as primary key type. Like IRecord<Tuple<int,double>>.
Now you can define a generic table
public class Table<T, PK>
where T : IRecord<PK>
{
private Dictionary<PK, T> _table = new Dictionary<PK, T>();
public void Add(T item)
{
_table.Add(item.ID, item);
}
}
You can define specific tables like this
public class MyTable : Table<MyValue, int>
{
}
UPDATE:
Alternatively, you could let records implement an explicit error handling
public interface IRecord<PK> {
PK ID { get; }
bool IsValid { get; }
string[] Errors { get; }
}
Related
I have a dictionary class which is used to store data, and which tracks hundreds of variables during the course of a session.
I have been tasked with building a common framework, which I can reference this base set of functionality, but allow the calling components to use different key and value within the dictionary.
Currently, this dictionary uses a 4-part tuple as the key, and a 2-part value.
The two components I'm tying into has a different key and value layout.
Component 1 - key is a 5-part tuple, and value is a 3-part.
Component 2 - Key is a 3-part tuple (string, int, string) and the same 2-part value.
This class handles data transfer to other components, so to avoid duplication of effort, want to keep as much of the common functionality in the Common dll, and external components would use the Survey class which the different key/value. Not certain I'm explaining it well enough.
I have included the current code below.
Seems to me, if the main Survey is created with object, object, and subclass the external components with the correct key/value pair.
public sealed class Survey
{
#region Private Objects
private Survey()
{
}
private Dictionary<SurveyKey, SurveyValue> survey = new Dictionary<SurveyKey, SurveyValue>();
private int maxLines = 50000;
private bool AllowLogging { get => (survey.Count > maxLines); }
#endregion
private void WriteData(SurveyKey key, SurveyValue value)
{
if (AllowLogging)
{
if (!survey.ContainsKey(key))
survey.Add(key, value);
else
survey[key] = value;
}
}
}
#region SurveyValue Class
public sealed class SurveyValue
{
public SurveyValue(int? value = null, string detail = null)
{
Detail = detail;
Value = value;
}
// Uses an either/or value; Value or Detail
public string Detail { get; private set; }
public int? Value { get; private set; }
}
#endregion
#region SurveyKey Class
public sealed class SurveyKey : Tuple<string, string, string, string>
{
public SurveyKey(string Signal, string SignalType, string Name, string OverallType) : base(Signal, SignalType, Name, OverallType) { }
public string Signal { get => Item1; }
public string SignalType { get => Item2; }
public string Name { get => Item3; }
public string OverallType { get => Item4; }
}
Make your common class generic of type K,V and use the where keyword to restrict the dictionary K and V to KBaseClass and VBaseClass. Component1 can expose KBaseClass and VBaseClass derived types and inherit from common or reuse common.
Turns out, I was over thinking this problem. All I need to do is create my base dictionary as Survey, and use this in my external components.
For some reason I was thinkning I needed to create an interface to allow the plugging in of the base dictionary.
private Dictionary<TKey, TValue> survey = new Dictionary<TKey, TValue>();
How can I read from my database an int attribute that in my system is an Enumeration type attribute in the Repository Pattern, C #.
I made a class:
public class Status : Enumeration
{
public static readonly Status Active = new Status(0, "Active");
public static readonly Status Inactive = new Status(1, "Inactive");
public static readonly Status Removed = new Status(2, "Removed");
public Status()
{
}
private Status(int value, string displayName)
: base(value, displayName)
{
}
}
So in the Bank class I put a Status attribute;
At the time of reading from the bank where my Bank class is and a table with an attribute Status type int, plus the attribute gets null.
I would introduce a static method to convert integers to "enum" in your class, for example
public class Status : Enumeration
{
//YOUR CODE
public static Status FromInteger(int value){
switch(value){
case 0:
return Active;
case 1:
return Inactive;
case 2:
return Removed;
default:
throw new ArgumentException();
}
}
}
I have not dealt with DapperRepository. But quick look at ClassMapper<T> reveals that you may leverage custom conversion using AutoMap method. However, I did not find neither documentation nor example.
Therefore, I can propose only a universal solution.
public class Bank {
//Standard fields that are mapped to a table in database
public Status StatusEnum {
get {
Status.FromInteger(StatusId); //StatusId is a property mapped to table's field
}
set {
//TODO Handle null value
StatusId = value.Value;
}
}
}
NOTE:
I assume that property StatusId is a field mapped to the table's field that contains status value.
This code has obvious problem - StatusId allows values that are out of enum range. You will have to do some additional validation to maintain data consistency.
I am in situation where I need to store a payment type enumeration value in the database for record keeping.
The problem is that I would like to add the ability for end user define their own value types.
I understand that I can use a negative range in my enumeration for my own values since user defined types will have an id greater than 0 but would that be a correct approach?
Or maybe I should have a second column like CustomPaymentType and referenced to PaymentType table for a data consistency?
Don't use an enumeration.
Enumerations are only useful for things that are constant by their nature, like days of the week.
Instead use a reference table in the data base like CustomPaymentType (Id,PaymentTypeName)
then you can use a class that looks like:
public class CustomPaymentType
{
public string paymentTypeName { get; private set; }
public int Id { get; private set; }
// if you need "Constant payment types usable in code, just add something like:
public static CustomPaymentType CashPayment
{
get { return new CustomPaymentType() { Id = 7, paymentTypeName= "CashPayment" } }
}
public static CustomPaymentType CreditPayment
{
get { return new CustomPaymentType() { Id = 7,paymentTypeName= "CreditPayment" } }
}
}
This approach is pretty good, because you have both the ease of coding about well known specific instances that you may need while coding, and its also very extendable.
What is a good way to denote "type" in database?
I have a base class Action which is inherited by numerous child classes. Action has members like Id, Name etc all which corresponds to equivalent columns in a table in the database called action. So action table looks like this:
id | name | type
The type column denotes what action it is. In my code they correspond to the child classes deriving from parent Action. Now how do I save the type of class to the type field in database?
The type column in db could be of any data type.
Options:
Save action.GetType().ToString() as string in db. And get the action type from db back by converting the string representation of the type to its original type using reflection. But this will be problematic if class names change in future.
Create an enum to denote each child class and decorate it by a TypeAttribute, something like:
public abstract class Action
{
public enum Kind
{
[Type(typeof(ControlAction))]
ControlAction = 1,
[Type(typeof(UpdateAction))]
UpdateAction = 2,
etc
}
public abstract Kind ActionType { get; }
}
public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } }
public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } }
//etc
This looks good, except that for each class from here onwards I have to create an enum. And it feels like a little too much work to be done.
Build a separate static hash table of <int, Type> that ties a class to a int value. May be a little bit unreadable.
Is there a better solution to this?
I would go from the 3rd solution with a hash-table, as it does seem to be the cleaner design-wise. And I would delegate its management to the database!
After all, isn't this what relational databases excel at the most, creating relations between two entities (in your case, action and type)? Other advantage is you end up with a normalized schema (sure, so far, there is only one column to the type table, namely its name, but normalizing allows you to easily add additional attributes to the types should you need them in the future, which is why it is cleaner as a design).
The schema would be something like this:
Action table
action_id(PK) | name | type_id (int, FK to Type table)
Type table
type_id(PK) | type_name
Now you are safe if the name of a class changes in the future (concern from your first proposition with string type). Indeed, all you would do is change the type_name value in the corresponding Type table row and all your Action rows would still be linked to this row by the type_id, which never changes once created (no problem here, as it does not hold any "business meaning").
And you have your hash-table from 3 (the Type table) in a readable format as it is the RDMBS's responsibility to manage the keys of the hash-table (the type_id PK).
Note that you won't have to tie your class to an int value corresponding to the type_id column, but rather fetch from the Type table the type_id by looking it up against the Class type (type_name).
I ended up using option 2, but with less clutter of attributes. Something like this:
public abstract class Action
{
public enum Kind
{
ControlAction = 1,
UpdateAction = 2,
etc
}
public abstract Kind ActionType { get; }
}
public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } }
public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } }
The biggest advantage for this is that (even if it meant more typing), it enforces a numeric value to be associated with a class type.
Now class to int is just:
var value = (int)instance.ActionType;
Very fast.
But to convert int to class instance (or class type), I will have to create an instance of each sub action types, and compare its ActionType property to match the input int value. This is going to be slow. But I can cache somethings and make it faster. Something like:
static readonly Dictionary<Action.Kind, Type> actionTypes =
GetDefaultInstanceOfAllActions().ToDictionary(x => x.ActionType, x => x.GetType());
public static Action ToAction(this Action.Kind value)
{
return (Action)Activator.CreateInstance(actionTypes[value]);
}
The GetDefaultInstanceOfAllActions does some reflection (once) to get all types of actions (I use something like this answer for that). I can even make the make the instantiation faster by going the expression route.
The benefits:
Less hassle when creating a new class (no attributes).
Enforces an int to be tied to a class type.
Moderately fast with adequate caching.
I would go with your first option and use reflection. It seems more likely that you will want to add new action types rather than change existing class names and therefore the ease of serializing the type using reflection is more useful.
You could then just have a utility class for serializing actions and restoring them from their type string.
I'm looking for an efficient in-memory type that mimics a table of mixed-type data (rows/columns). By efficient I mean fast operations for the below scenarios. Memory is a secondary concern.
Primary scenarios are:
add rows of data
read whole columns
iterate over rows
Out of scope:
sorting/ordering
searching
persistence to database
random access of cells (i.e. table(row=3,col=4) )
I'm assuming I can do better than the ADO types (DataTable, etc.) because they solve for a broader set of scenarios? I could be wrong.
DataTable has a lot of features and has bulk. Like AcceptChanges.
To handle the mixed data types created an abstract class
public abstract class Field : INotifyPropertyChanged
It includes
public abstract String DispValue { get; }
Then for the various data types
class FieldBooleanSV : Field
class FieldStringSV : Field
class FieldInt32SV : Field
public class FieldInt16SV : DocField
{
Int16 fieldValue;
Int16 FieldValue { get { return fieldValue; }
set
{
if (value != fieldValue)
{
fieldValue = value;
NotifyPropertyChanged("DispValue");
NotifyPropertyChanged("FieldValue");
}
}
}
}
public override String DispValue
{
get
{ return fieldValue.ToString()); }
}
}
SV is single value and there is a MV
So a FieldRow is a class with property
List<Field> Fields ....
And total collection is (rows and columns) is
ObservableCollection<FieldRow>
It is fragile as you need to sure that each FieldRow has the same collection of Fields.
It is a lot of work but I needed control of Field.
If you are going down this path then go GridView over DataGrid (for the same reasons - power but overhead).
The problem with
List<IEnumerable<T>>
Is that T is a variable but it is singular. All columns are the same T.