Reputation: 9389
I decided to use Dapper.net because it seems to be doing only what I want : mapping, I don't need anything fancy , I'm just bored to handle the mapping between my datareader and my object.
My problem :
Let's say I have these class :
class Foo{
int ID;
string Name;
}
class Bar : Foo{
string FavoriteMoovie;
}
And these tables :
Foo
- ID
- Name
Bar
- FooID
- FavoriteMoovie
So I'd like to know how I can select my Foo and Bars in the same query ?
My only idea so far is
I can't use the overload of the method "Query" because there are just here for mapping relationships.
Upvotes: 3
Views: 4426
Reputation: 706
in the case when one table per hierarchy TPH, it is easy to get all concrete childs Class, especially if the BaseClass is abstract
abstract class BaseValue
{
public BaseValue()
: this(0, 0, string.Empty)
{
}
public BaseValue(int id, double value, string dimension)
{
Id = id;
TypeName = GetType().Name;
Dimension = dimension;
_value = value;
}
protected double _value;
public double RawValue
{
get { return _value; }
}
public int Id { get; protected set; }
public string TypeName { get; protected set; }
public string Dimension { get; set; }
}
abstract class BaseValue<T> : BaseValue
where T : struct
{
public BaseValue()
: this(0, default(T), string.Empty)
{ }
public BaseValue(int id, T value, string dimension)
: base(id, 0, dimension)
{
Value = value;
}
public T Value
{
get
{
if (typeof(T) == typeof(float))
return (dynamic)(float)_value;
else if (typeof(T) == typeof(bool))
return (dynamic)(bool)(_value > 0 ? true : false);
else if (typeof(T) == typeof(int))
return (dynamic)(int)_value;
else if (typeof(T) == typeof(TimeSpan))
return (dynamic)TimeSpan.FromSeconds(_value);
else if (typeof(T) == typeof(DateTime))
return (dynamic)new DateTime((long)_value);
else
return (dynamic)_value;
}
set
{
if (typeof(T) == typeof(float))
_value = (float)(object)value;
else if (typeof(T) == typeof(bool))
_value = (bool)(object)value ? 1 : 0;
else if (typeof(T) == typeof(int))
_value = (int)(object)value;
else if (typeof(T) == typeof(TimeSpan))
_value = ((TimeSpan)(object)value).TotalSeconds;
else if (typeof(T) == typeof(DateTime))
_value = ((DateTime)(object)value).Ticks;
else
_value = (double)(object)value;
}
}
}
class IntValue : BaseValue<int>
{
public IntValue()
: this(0, 0, string.Empty)
{ }
public IntValue(int id, int value, string dimension)
: base(id, value, dimension)
{ }
}
class BoolValue : BaseValue<bool>
{
public BoolValue()
: this(0, false, string.Empty)
{ }
public BoolValue(int id, bool value, string dimension)
: base(id, value, dimension)
{ }
}
class FloatValue : BaseValue<float>
{
public FloatValue()
: this(0, 0, string.Empty)
{ }
public FloatValue(int id, float value, string dimension)
: base(id, value, dimension)
{ }
}
class TimeSpanValue : BaseValue<TimeSpan>
{
public TimeSpanValue()
: this(0, TimeSpan.MinValue, string.Empty)
{ }
public TimeSpanValue(int id, TimeSpan value, string dimension)
: base(id, value, dimension)
{ }
}
class DateTimeValue : BaseValue<DateTime>
{
public DateTimeValue()
: this(0, DateTime.Now, string.Empty)
{ }
public DateTimeValue(int id, DateTime value, string dimension)
: base(id, value, dimension)
{ }
}
and Repository select from TPH table:
class Repository
{
public IEnumerable<BaseValue> GetAll()
{
IEnumerable<BaseValue> values = null;
using (SqlConnection cn = new SqlConnection(""))
{
cn.Open();
const string query = "SELECT Id, TypeName, RawValue, Dimension FROM Values";
values = cn.Query<BaseValue, object, BaseValue>(query,
(value, ignore) =>
{
BaseValue child = null;
if (value.TypeName == "IntValue")
child = new IntValue(value.Id, (int)value.RawValue, value.Dimension);
else if (value.TypeName == "BoolValue")
child = new BoolValue(value.Id, value.RawValue > 0, value.Dimension);
else if (value.TypeName == "FloatValue")
child = new FloatValue(value.Id, (float)value.RawValue, value.Dimension);
else if (value.TypeName == "TimeSpanValue")
child = new TimeSpanValue(value.Id, TimeSpan.FromSeconds(value.RawValue), value.Dimension);
else if (value.TypeName == "DateTimeValue")
child = new DateTimeValue(value.Id, new DateTime((long)value.RawValue), value.Dimension);
return child;
});
cn.Close();
}
return values;
}
}
Upvotes: 1
Reputation: 131112
Very hacky, but this probably works.
db.Query<Bar, object, Foo>("select * from Foo left join Bar on FooID = ID",
(bar,ignore) =>
bar.FavoriteMoovie == null ? bar : new Foo{ID = bar.ID, Name = bar.Name});
Disadvantage is that it creates a couple of intermediate objects that it could do without.
Other options are to simply select Bar
objects and then use the same trick to filter out the Foos or select a dynamic and then convert to the correct class.
Personally I would not query twice just to handle this, unless you are allowing for NULL
FavoriteMoovie, in which case you have no choice but to either complicate the query or select twice.
Upvotes: 2