We are using Dapper as an ORM to a legacy Informix database, and within this database boolean fields are actually stored as a Char, with 'F' meaning False and 'T' meaning True.
Within our POCO, we would like to expose a single boolean property and instruct Dapper to map to/from the relevant char value when reading from and writing to the database.
For Example:
Let's say we have a field within a table called "Active". The value in the database for the Active column will be either "T" of "F"
Our POCO may look something like this:
public class MyTable
{
public bool Active { get; set; }
}
Is it possible to create a custom mapping within Dapper that for this column would set the Active property in the POCO to true if the underlying value is "T", and false if "F"?
One way I know I could work around this is to have two properties, one a string that Dapper can map to directly and another a boolean used by the consumers of the POCO. i.e:
public class MyTable
{
public string Active { get; set; }
public bool MyActive
{
get { return Active == "T"; }
set { Active = (value == "T"); }
}
}
The disadvantage of this approach is having to maintain two properties so it would be a great if there is a way to extend dapper to get it to do this for me (particularly as there are a lot of fields like this within the table our database).
I've looked at implementing a custom type map but although this would work for a custom complex type, I'm not sure how it would work in this instance when I want to map from one basic type to a another basic type.
I doubt that dapper supports it, have a look at this related question's answer. As you can see the Active-property does not even have to be public, make it private to avoid confusion. However, i would name your bool property IsActive.
public class MyTable
{
private string Active { get; set; }
public bool IsActive
{
get { return Active == "T"; }
set { Active = value ? "T" : "F"; }
}
}
Related
I had this question but there was no C# answer, only Java ones (DyanmoDb is storing value 1 instead of boolean value true) so posting this.
There is no way I know of that allows you to use the Object Persistence model for DynamoDB and ensure that boolean primitives stay "true"/"false" when put in a DynamoDB table. By default, they get turned into "1" and "0".
How can we ensure that a boolean field doesn't get turned into a 1/0 when put in DynamoDB?
#Dhruv's original converter saves as a string value rather than native bool. You can modify your property converter slightly to use the DynamoDBBool type and still use the document model as follows:
public class DynamoDBNativeBooleanConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value) => new DynamoDBBool(bool.TryParse(value?.ToString(), out var val) && val);
public object FromEntry(DynamoDBEntry entry) => entry.AsDynamoDBBool()?.Value;
}
This could be extended more to support for reading from string/number/etc in the FromEntry to handle legacy data scenarios if desired.
The one way we can do this is to use IPropertyConverter.
First, we need to create a class that extends the IPropertyConverter, and put in our desired logic. We need to describe the to and from logic.
public class DynamoDBNativeBooleanConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value) => (bool) value ? "true" : "false";
public object FromEntry(DynamoDBEntry entry)
{
var val = bool.Parse(entry.AsPrimitive().Value.ToString());
return val;
}
}
Then, we can use this class when we use our boolean attribute:
...
[JsonProperty("can_flip")]
[DynamoDBProperty("can_flip", typeof(DynamoDBNativeBooleanConverter))]
public bool CanFlip { get; set; }
...
Using this, the data in DynamoDB tables will show up as "true" or "false", and when you consume it, it will be a boolean.
Consider the following code:
public interface IIdentifiable<T>
{
T Id { get; set; }
}
public interface IViewModel
{
}
public class MyViewModel1 : IViewModel, IIdentifiable<int>
{
public string MyProperty { get; set; }
public int Id { get; set; }
}
public class MyViewModel2 : IViewModel, IIdentifiable<string>
{
public string MyProperty { get; set; }
public string Id { get; set; }
}
I also have class that operates with ViewModels:
public class Loader<T> where T: IViewModel
{
public void LoadData()
{
/*some important stuff here*/
if (typeof(IIdentifiable<??>).IsAssignableFrom(typeof(T)))
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<??>) ds).Id != ((IIdentifiable<??>) d).Id)).ToList();
} // ^---- and there the second ----^
/*some important stuff here too*/
}
}
Now, as you can see, viewmodels that I have might implement the IIdentifiable<> interface. I want to check that, and if it's true,
I want to make sure my data list does not contains any entry that are already present in my _dataSourse list.
So I have 2 questions:
I don't know what IIdentifiable<> has in its generic parentheses, it might be int, string or even GUID.
I tried typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) which is the correct syntax, yet it always returns false.
Is there a way to check whether T is IIdentifiable<> without knowing the exact generic type?
If there is an answer for the first question, I would also like to know how can I compare the Id fields without knowing their type.
I found this answer quite useful, yet it doesn't cover my
specific case.
I know that I probably can solve that problem if I make my Loader<T> class a generic for two types Loader<T,K>, where K would be the
type in IIdentifiable<>, yet I would like to know if there are other solutions.
P.S. In addition to my first question: I'm also curious why one can write something like this typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) if it returns false when the generic type of IIdentifiable<> is not specified?
Edit: I guess, in hindsight, I understand why I can't write the code this bluntly - because there's might be the collection ICollection<IViewModel> where the entries implement different types of IIdentifiable<> (or don't implement it at all), and the check like that would fail awkwardly. Yet maybe there is a way to do something like that with some restrictions, but without creating second generic parameter to my Loader?
Try add two methods to your Loader<T>:
public bool CanCast<TId>()
{
var identifiableT = typeof(IIdentifiable<>).MakeGenericType(typeof(TId));
return identifiableT.IsAssignableFrom(typeof(T));
}
public IEnumerable<IIdentifiable<TId>> Filter<TId>(IEnumerable<T> data)
{
return data.Where(d => _dataSource.All(
ds => !((IIdentifiable<TId>) ds).Id.Equals(((IIdentifiable<TId>) d).Id)));
}
Then in LoadData
if (CanCast<int>())
data = Filter<int>(data);
else if (CanCast<Guid>())
data = Filter<Guid>(data);
// and so om
Well, I would suggest you to always use a string for identification. You can convert int and guid to a string. And if you want to ensure proper type is used then you can prefix the string with type information.
However, I do think that the performance of you algorithm would be very poor as you wouls essentially loop 2 containers so it would be O(n * m).
Thus it would be best to either do appropriate SQL query if both sources are from the database or use a dictionary if you do it in code. Alternatively if data is properly sorted, you could find duplicates more efficiently.
By the way generics are quite limited in C#. Sometime using ˋFunc<>ˋ could help but even then you have to provide extra information to the algorithm.
We should address your question in two steps (because there really are two problems to solve here).
First, make following change to your interface IIdentifiable<T>
public interface IIdentifiable<T>
where T : IEquatable<T>
{
T Id { get; set; }
}
This will ensure that you can compare Id properties correctly.
Secondly, in your LoadData() method, change the if statement to
if (T is IIdentifiable<T>)
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<T) ds).Id != ((IIdentifiable<T) d).Id)).ToList();
}
How to let an Attribute in one property know the existence of another property?
Lets say i have this class, and like this, many others:
public class MyClass
{
[CheckDirty] //a custom attribute (that it is empty for now)
public int A { get; set; }
public int B { get; set; }
public string Description { get; set; }
public string Info { get; set; }
}
Somewhere in our program, if we want to see if an object changed values on any CheckDirty property, for example lets say it is diferent from DB, MyPropertyUtils.GetPropertiesIfDirty() does this, giving us an array of changed propertys, on any property with that attribute:
PropertyInfo[] MyPropertyUtils.GetPropertiesIfDirty(SomeBaseObject ObjectFromDB, SomeBaseObject NewValues);
Perfect.
So, lets say A changed and in this case Info holds some information we need(in another class might be any other property). If we want 'A' we just do property.GetValue(NewValues, null);
But we dont want 'A's value, we want 'A' or CheckDirty to tell us where to read some data we want. How can i tell my attribute CheckDirty where to get the values from?
I was thinking in giving an expression to CheckDirty but an Attribute's argument "must be a constant expression, typeof expression or array creation expression of an attribute parameter type"(thats what VS says).
So I decided, "ok, lets give it a string with the property's name", and so my try failed:
(this is all the code we need to work on, the rest was just to give some kind of context example)
public class CheckDirty : Attribute
{
public String targetPropertyName;
public CheckDirty(String targetPropertyName)
{
this.targetPropertyName = targetPropertyName;
}
}
public class MyClass
{
//Code fails on this line
[CheckDirty(BoundPropertyNames.Info)]
public int Id { get; set; }
public string Info { get; set; }
public static class BoundPropertyNames
{
public static readonly string Info = ((MemberExpression)
((Expression<Func<MyClass, string>>)
(m => m.Info)
).Body
).Member.Name;
}
}
This is the error i get:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
We do NOT want to pass the name of the proprety as a String saing [CheckDirty("Info")] because that way if anyone in the future changes the class, and in concrete the property's name, no error would get thrown in compile time by it, only occuring the error in run time, when an "edit" to that field would occur. Or maybe it would just not do anything because it could not find the property.
Any idea how to not use the strongly typed string as a property name?
You may use something like this, first declare an interface that will be implemented by every class that need dirty checking:
interface IDirtyCheckPropertiesProvider {
string GetPropertyName(string dirtyProperty);
}
then implement it like that
class DataEntity : IDirtyCheckPropertiesProvider {
[CheckDirty]
public int Id { get; set; }
public string Info { get; set; }
string GetPropertyName(string dirtyProperty) {
if (GetPropertyNameFromExpression(x => Id) == dirtyProperty)
return GetPropertyNameFromExpression(x => Info);
return null;
}
}
In class that will be responsible for handling dirty checks you must use this interface to get target property names.
There is a bit too much boilerplate that may be removed further by using Reflection API.
On the other hand using string for property names looks like more simple solution. If you use tool like Resharper - using string is a viable option - Resharper will automatically refactor string when you change property name.
Also for a long time string'ed property names were used in implementation of WPF INotifyPropertyChanged.
As comments suggested nameof is the best option in VS2015.
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.
Consider following class
public class AccountGroup : Entity<int>
{
public AccountGroup()
{
Accounts = new HashSet<Account>();
Groups = new HashSet<AccountGroup>();
}
// option 1 - read only properties
public bool IsRoot { get { return Parent == null; } }
public bool IsLeaf { get { return !Groups.Any(); } }
public Account MainAccount { get { return Accounts.FirstOrDefault(a=>a.Type == AccountType.MainAccount); } }
// option 2 - parameter-less methods
//public bool IsRoot() { return Parent == null; }
//public bool IsLeaf() { return !Groups.Any(); }
//public Account GetMainAccount() { return Accounts.FirstOrDefault(a => a.Type == AccountType.MainAccount); }
public string Name { get; set; }
public string Description { get; set; }
public virtual ISet<Account> Accounts { get; private set; }
public virtual ISet<AccountGroup> Groups { get; private set; }
public virtual AccountGroup Parent { get; set; }
}
If I want to "enrich" the class above, which option approach should I use.
Option 1
Should I use read only parameters knowing that EF does not like them (trying to use IsRoot in Where clause throws ex, with The specified type member 'IsRoot' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Option 2
Or should I go with parameter-less methods (not sure what would be disadvantages)
In general (not considering EF), which approach is preferred considering above when functionality is equivalent (i.e. I get the same functionality if I invoke .IsRoot or .IsRoot())
IsRoot feels more like a property to me. It represents current state of the object, doesn't actually do anything when invoked other than report that state, and generally getters/setters in .NET are properties.
There are other things to consider, a JSON/XML serializer will not serialize IsRoot() but will for IsRoot as a property. Generally speaking a lot of things in .NET hinge off of properties, so often they are the better choice.
EF wouldn't like IsRoot() either, it just doesn't know how to translate IsRoot into SQL, whether it's a property or method.
In general (as you say, not taking limitations of EF into account), the approach for domain models in this particular context would probably be a read-only property.
Consider that the property is simply checking state, not modifying it in any way. A read-only property conveys, outside of the object, that it's just returning a piece of information. On the other hand, a method could be potentially destructive in that it might modify information.
This would be particularly true if the method returned void of course, which isn't the case here, so this could be considered a borderline issue (and not even a question in languages which don't have "properties" but just use accessor methods, which under the hood is what a "property" does).
My vote is for a property when checking state and a method when commanding the object to modify state.
Have you already tried decorating IsRoot with [NotMapped]? The NotMapped attribute should prevent Entity Framework from complaining about properties that it's unable to persist and allow you to express that as a property.