Reputation: 101
how I can do mapping in serviceStack.ormlite or Dapper dependent on column type?
For example I have next classes:
//table A
abstract Class A
{
public ulong? id {get; set}
public string Name {get; set}
public string DeviceType {get; set}
abstract public void method()
}
//no table
Class B : A
{
public override void method()
{
//dependent on B implementation
}
}
//no table
Class C : A
{
public override void method()
{
//dependent on C implementation
}
}
From ORM I need something lite that:
List<A> items = orm.Must_Return_list_With_B_and_C_Instances_From_A_Table();
How I see this logic:
function Must_Return_list_With_B_and_C_Instances_From_A_Table()
{
var items = new List<A>();
foreach(var row in rows)
{
if (row.DeviceType == "B")
{
items.Add(new B(row)); // mean mapping there
}
else if (row.DeviceType == "A")
{
items.Add(new C(row)); // mean mapping there
}
}
}
Then I can:
-use next:
foreach(var item in items)
{
item.method(); // calls the right method of class B or C
}
-if I need add new deviceType I implement only class D : A and edit the mapper, and dont touch global program logic.
This is generally implemented in the context of ORM and С# idea?
If you understand what I want, please indicate the direction of how to make similar. Many thanks.
Upvotes: 1
Views: 384
Reputation: 28992
You're expecting a bit much of Dapper I feel. It's not Dapper's job to do this. But instead of writing your own factories, why don't you introduce a DI container. With TinyIoC for example, you would register B and C as named implementations of interface A. When another DeviceType comes along, you just register a new implementation and you're in business.
public interface A
{
POCO poco { get; set; }
void MyMethod();
}
public class B : A
{
public void MyMethod()
{
throw new NotImplementedException();
}
public POCO poco { get; set; }
}
public class C : A
{
public void MyMethod()
{
throw new NotImplementedException();
}
public POCO poco { get; set; }
}
public class POCO
{
public ulong? id { get; set; }
public string Name { get; set; }
public string DeviceType { get; set; }
}
public class Program
{
public static void main()
{
var ctr = TinyIoCContainer.Current;
ctr.Register<A, B>("B");
ctr.Register<A, C>("C");
List<A> devices = new List<A>();
using (var db = new SqlConnection(Config.DefaultConnectionString))
{
db.Open();
List<POCO> queryResults = db.Query<POCO>("SELECT * FROM Devices").ToList();
foreach (var queryResult in queryResults)
{
// the magic step where we create the right type of A based on the value in column Name...
var newDevice = ctr.Resolve<A>(queryResult.Name);
newDevice.poco = queryResult;
devices.Add(newDevice);
}
}
}
}
Upvotes: 1
Reputation: 11667
I wouldn't make B
or C
derive from A
. Instead, I would make them own a member instance. You could still have B
and C
implement some interface:
interface IProcessA
{
void Method();
}
class B : IProcessA
{
readonly A _a;
public B(A a)
{
_a = a;
}
public void Method()
{
// do something with _a
}
}
class C : IProcessA
{
readonly A _a;
public C(A a)
{
_a = a;
}
public void Method()
{
// do something different with _a
}
}
Then you can use Linq to return instances of either B
or C
as IProcessA
:
List<IProcessA> items = dbResult.Select(a => a.DeviceType == "B" ? new B(a) : new C(a))
.ToList();
If you're going to add new types D
or E
, you would want to move the work done in the Select
to a method or factory that you could add to later.
Upvotes: 2