I have a class structure similar to this:
public abstract class Device
{
public int DeviceId { get; set; }
//Additional Properties
}
public class DeviceA : Device
{
//Specific Behaviour
}
public class DeviceB : Device
{
//Specific Behaviour
}
I need to retrieve a list of Devices, or a single Device which is instantiated as the appropriate derived type (based upon a Type value in the Device Record in the DB). That is, the collection of Device
objects should contain a number of objects with different Types, all of which are derived from Device
.
I have implemented this the following way, but something just doesn't feel right about it.
public static IEnumerable<Device> AllDevices()
{
using (var connection = CreateConnection())
{
connection.Open();
return connection.Query<dynamic>("SELECT * FROM Device").Select<dynamic, Device>(d =>
{
Device device = null;
if (d.DeviceTypeID == 1)
device = new DeviceA();
else if (d.DeviceTypeID == 2)
device = new DeviceB();
else throw new Exception("Unknown Device");
device.DeviceId = d.DeviceID;
return device;
});
}
}
Is this the correct way to achieve this using Dapper, or is there a better approach?
In the current build that is probably the only option (especially since the base-type is abstract). However, it wouldn't be unreasonable to think of ways of suggesting a discriminated inheritance system. It isn't something we've done so far simply because it hasn't come up - but it doesn't sound impossible. The biggest problem I can see (other than IL-wrangling, obviously) is simply how we express the relationship.
I've came up with this solution:
using (IDbConnection db = new MySqlConnection(ConfigurationManager.ConnectionStrings["yourConnection"].ConnectionString))
{
return db.Query<dynamic, DeviceA, DeviceB, Device>(@"
Select
Discriminator,
...
From Device", (d, da, db) =>
{
if (p.Discriminator == "DeviceA")
{
return new DeviceA();
}
else if (p.Discriminator == "DeviceB")
{
return new DeviceB();
}
return d;
});
Sounds tricky, but it does work!
Hope it can help you. }