I'm working with an existing EF data model that includes subclassed objects. That works fine when working with individual objects, but is quite slow when loading a large number of objects for analysis.
I started exploring Dapper as an alternative for populating POCO objects used for read-only analysis.
The trouble is, I can't see any means to correctly handle an object hierarchy.
If I have
class MyBase
{
}
class MyDerived1 : MyBase
{
}
class MyDerived2 : MyBase
{
}
Dapper correctly populates a list of MyBase
var mine = conn.Query<MyBase>("SELECT * from MyTable");
The Multimap capability doesn't seem to solve the problem (or am I missing something?).
Is there a way to solve this, short of making one round-trip to the database for each subclass?
public class MyBase
{
public String BaseProp { get; set; }
}
public class MyDerived1 : MyBase
{
public String Derived1Prop { get; set; }
}
public class MyDerived2 : MyBase
{
public String Derived2Prop { get; set; }
}
Multimapping or a dynamic mapping should do the trick.
MM:
String query = "SELECT * FROM Table";
var res = conn.Query<MyBase, MyDerived1, MyDerived2, Tuple<MyBase, MyDerived1, MyDerived2>>(query, (b, d1, d2) => Tuple.Create(b, d1, d2), splitOn: "Derived1Id,Derived2Id");
The dynamic mapping is also very cool and probably more flexible in your case (Thanks #Sam!)
var res = conn.Query<dynamic>(query).Select(x => new Tuple<MyBase, MyDerived1, MyDerived2>(new MyBase() { BaseProp = x.BaseProp },
new MyDerived1() { Derived1Prop = x.Derived1Prop },
new MyDerived2() { Derived2Prop = x.Derived2Prop }));
Related
I am calling a stored procedure from Entity Framework and trying to get result of stored procedure in a model-view class but I am getting error while casting list of Result class I got from entity framework -
Below code I tried, but I am getting error while trying to cast, I tried other way also like ConvertAll<> but didn't work -
public List<DepartmentModelView> GetDepartmentData()
{
using (Model1Container obj = new Model1Container())
{
return obj.usp_getDepartment().ToList<usp_getDepartment_Result>().Cast<DepartmentModelView>.ToList();
}
}
This is the auto generated result class in Model.tt
namespace MvcApplication4.Models
{
using System;
public partial class usp_getDepartment_Result
{
public Nullable<int> Depid { get; set; }
public string DepName { get; set; }
}
}
But I want it to be returned in DepartmentModelView class-
public class DepartmentModelView
{
public Nullable<int> Depid { get; set; }
public string DepName { get; set; }
}
Please suggest how could I do this ?
If the rest of your Code works, you can use the Linq-Select-Projection:
public List<DepartmentModelView> GetDepartmentData()
{
using (Model1Container obj = new Model1Container())
{
return obj.usp_getDepartment().ToList<usp_getDepartment_Result>().Select(m=>new DepartmentModelView{Depid=m.Depid, DepName=m.DepName}).ToList();
}
}
You could implement implicit cast in another partial file for usp_getDepartment_Result:
namespace MvcApplication4.Models
{
public partial class usp_getDepartment_Result
{
static public implicit operator DepartmentModelView(usp_getDepartment_Result input)
{
return new DepartmentModelView
{
Depid = input.Depid,
DepName = input.DepName
};
}
}
}
Then your existing code ought to work.
Use AutoMapper (from Nuget). You can create a map from one class to another and you can do all kinds of manipulation during the mapping operation for cases where it isn't a straightforward copy of properties like this one.
And for simple cases like this one, Automapper will autowire up the conversion when it finds properties with the same names and types.
What Utility or Pattern can be used to solve this Issue? I don't know what can be used to assist with this. Can we use some type of pattern?
If you have the following abstract class:
abstract class Foo
{
function void Something()
{
// Get the media type
}
}
And the following classes that derive from that class:
class Foo1 : Foo
{
public string MyId {get;set}
public string MyFile {get;set}
public TxtFile MyTextFile {get;set}
function void myFooFunction()
{
// Save File to Txt
}
}
class Foo2 : Foo
{
public string MyId {get;set}
public string MyFile {get;set}
public XMLFile MyXMLFile {get;set}
function MyOtherFunction()
{
// Save to XML
}
}
Then in Linq (or Similar) within the repository you do something like this:
var a = (from e in db.myTable
where e.myFileType == "XML"
Select e);
Then we have to map this to the correct object. Like this:
Foo newFoo = FooFactory.CreateFooFor(a.myFileType.ToString())
newFoo.MyId = a.id;
newFoo.MyFile = a.myfile;
newFoo.MyXMLFile = a.xml;
The Factory certainly helps, but how do you do this for multiple "FileTypes" like txt for example? The Fields wouldn't match up!
Do I have to write more code that does the same thing??
I feel like there has to be something that can do this.
First, if myFooFunction and MyOtherFunction are both used to save, you can use the strategy pattern and just define and abstract Save() method to implement in derived classes. You might also look at the Template Method pattern.
Although this isn't exactly a pattern, you might also want to apply the "Pull Up Field" refactoring here and put the MyId and MyFile properties in the parent class.
For creation...
The Builder pattern is similar to the factory, but allows for more complex object creation. I don't know how well it fits this simplified example, but it might fit what you are actually trying to do in your real code. Probably not. I just mention it first because it is the closest to factory in my mind.
There are also the Mapper Pattern and the Data Mapper Pattern. You might encapsulate the mapping in an object and have the factory return a mapper:
FooMapper mapper = FooMapperFactory.CreateFooMapperFor(a.myFileType);
Foo newFoo = mapper.CreateFoo(a);
I believe you could solve your problem using generics. I took the liberty of changing around some code. Would this work?
public abstract class Foo
{
public abstract void Save();
public void Something()
{
// Get the media type
}
}
public class FooText : Foo
{
public string MyId { get; set; }
public string MyFile { get; set; }
public string MyTextFile { get; set; }
public override void Save()
{
// Save File to Txt
}
}
public class FooXml : Foo
{
public string MyId { get; set; }
public string MyFile { get; set; }
public string MyXMLFile { get; set; }
public override void Save()
{
// Save to XML
}
}
public class FooFactory<T> where T : Foo, new()
{
public static T CreateFoo()
{
return new T();
}
}
If you consider using reflection on the data that's returned from the database, or perhaps the Adapter pattern you can set up a dynamic way to map fields to each other. Using reflection (the following is pseudo logic as reflection is kind of messy code to provide):
Get a list of PropertyInfo objects for all public properties from the target type
Get a list of PropertyInfo objects for all public properties from the database type
Compare their names/types to create the mapping
Assign values from the database type, using reflection, to the target type
Something like this will do the trick:
public void AssignAndMapTypes<DatabaseType, TargetType>(DatabaseType db, ref TargetType target)
{
var dbType = db.GetType();
var dbTypeProperties = dbType.GetProperties(System.Reflection.BindingFlags.Public);
var targetType = target.GetType();
var targetTypeProperties = targetType.GetProperties(System.Reflection.BindingFlags.Public);
foreach (var prop in targetTypeProperties)
{
var matchingProp = dbTypeProperties.Where(e => { return (string.Compare(e.Name, prop.Name, true) == 0) && (e.PropertyType == prop.PropertyType) }).FirstOrDefault();
if(matchingProp != null)
{
prop.SetValue(target, matchingProp.GetValue(db, null), null);
}
}
}
I have a large collection of automatically generated objects. Although they are all of different, non-related classes, all of the objects share some basic properties (name, id, etc.). I do not control the generation of these objects, so unfortunately I cannot take the ideal approach of implementing an interface. I would like to create a method in which I pass an arbitrary one of these objects and do something using these common properties.
The general idea would be something like:
someObj a = new someObj();
a.name = "sara";
diffObj b = new diffObj();
b.name = "joe";
string phrase = string.Format("I am with {0} and {1}",
getName(a), getName(b));
private string getName(object anyObjWithName)
{
return anyObjWithName.name;
}
though naturally this does not work.
I thought a generic method might hold the answer, but the only way I can see to call it with the current type is using genericMethod.Invoke , which still carries the same issue of not being able to resolve the properties of the passed object in the method. This is unlike Calling generic method with a type argument known only at execution time or How to call generic method with a given Type object? where only the type, or properties of the type, are used in the method, as opposed to properties of the object.
I am aware that this would be (very) prone to error, but I can guarantee that all objects encountered will have the common properties being manipulated.
I can guarantee that all objects encountered will have the common properties being manipulated
If that's the case, you can use dynamic:
private string getName(dynamic anyObjWithName)
{
return anyObjWithName.name;
}
Be aware that using any object that does not have a name property will not fail until run-time.
If you want to add a little bit of safety you can catch the RuntimeBinderException that gets thrown if the property does not exist:
private string getName(dynamic anyObjWithName)
{
try {
return anyObjWithName.name;
}
catch(RuntimeBinderException) {
return "{unknown}";
}
}
If you're unhappy with the performance using dynamic as mentioned by D Stanley, you could always try FastMember.
All you need to know to start using it is pretty much shown in the first 2 code examples.
You are creating a Rube Goldberg device there. You should just have all your data objects classes implement a single interface, then you can work on that. Much simpler and less error prone than fiddling with reflection.
The very fact that a lot of objects have common properties but don't share the same ancestry, on in the very least a common interface, shows that something is wrong with your design. Do rethink it.
Multiple ways to accomplish this, simplest probably is to create Interface and declare common methods there, have your object implement it, then change "getName" method take interface object
private string getName(IMyInterface anyObjWithName)
{
return anyObjWithName.name;
}
The correct way to do this is with an interface, if you own the types that you're working with
public interface IEntity
{
int ID { get; set; }
string Name { get; set; }
}
public class TypeOne : IEntity
{
public int ID { get; set; }
public string Name { get; set }
public string BespokePropertyOne { get; set;}
}
public class TypeTwo : IEntity
{
public int ID { get; set; }
public string Name { get; set; }
public float BespokePropertyTwo { get; set; }
}
static void Main(string[] args)
{
List<IEntity> entities = new List<IEntity>();
entities.Add(new TypeOne() { ID = 1, Name = "Bob", BespokePropertyOne = "blablabla" });
entities.Add(new TypeTwo() { ID = 2, Name = "Alice", BespokePropertyTwo = 5.4f });
foreach (IEntity entity in entities)
{
Console.WriteLine("ID: {0} Name: {1}", entity.ID, entity.Name);
}
}
This answer was written before the edit to the question stating that interfaces weren't possible in this case. Perhaps it can help someone else reading this question.
Interface:
interface Iname
{
string Name { get; set; }
}
Use interface:
class A : Iname
{
public string Name { get; set; }
}
class B : Iname
{
public string Name { get; set; }
}
The method:
string GetName(Iname o)
{
return o.Name;
}
Use:
A a = new A { Name = "First" };
B b = new B { Name = "Last" };
Text = GetName(a) + " " + GetName(b);
I have 10 tables which are presenting to LINQ as different types, but share exactly the same properties. When I try to run a union on them, the compiler tells me that:
"Argument 2: cannot convert from 'System.Collections.IEnumerable' to 'System.Collections.Generic.IEnumerable<LINQPad.User.TelJun2011>'"
The code looks like this
var jul = (from n in TelJul2011s select n);
var jun = (from p in TelJun2011s select p);
jun.Union(jul).Dump();
I've done my research and understand that unions cannot be performed across different types, I also understand that unions can be performed on anonymous types if they share the same properties. This option will not work for me, as I need all the properties from all the tables and don't want to have to type out the same anonymous type 10 times - once for each variable. I want the compiler to infer that they are all the same type based on the fact that all properties are identical.
I've already tried casting to an IEnumberable, Iqueryable, Datatable etc. using both the AsQueryable() type functions, and the "as" keyword. None of that seems to do the trick for me.
I'm wondering if there is some way of doing this by casting dynamically to a parent type. I can't edit the initial declarations of the classes, so can't implement a common interface on them to cast to. But is there some way I can downcast the types into a common interface when they are used, without writing a conversion from each type to a parent interface?
Thanks for any advice!
The result of the Union will be an IEnumerable<Xxx> but in this case you have to specify what Xxx is. If the types TelJun2011 and TelJul2011 are not structs (value-types), you can utilize the covariance of IEnumerable<out T> like this:
jun.Union<object>(jul)
This works because TelJun2011 and TelJul2011 are both object, and then by covariance IEnumerable<TelJun2011> and IEnumerable<TelJul2011> are both IEnumerable<object>.
Of course object does not possess all the properties common to TelJun2011 and TelJul2011. It would be better if these two types had a more useful common base class or implemened a common interface, because then you could say e.g.:
jun.Union<ITelMonth>(jul)
where ITelMonth were some type containing the common properties you want.
The "problem" is that C#'s static typesystem won't allow what you're trying to achieve. You will have to cast the objects to a base type before union-ing them. That means if both have just System.Object in common, you would have to cast it either to object or (for .net 4.0) to dynamic.
The latter will force a dynamic typechecking:
class A
{
public int Integer { get; set; }
}
class B
{
public int Integer { get; set; }
}
class Program
{
public static void main(string[] args)
{
var a = new[] { new A { Integer = 5 }, new A { Integer = 6 }, new A { Integer = 7 } };
var b = new[] { new B { Integer = 1 }, new B { Integer = 2 }, new B { Integer = 3 } };
var u = a.Cast<dynamic>().Union(b).ToArray();
var i1 = u[0].Integer;
var i2 = u[1].Integer;
var i3 = u[2].Integer;
var i4 = u[3].Integer;
var i5 = u[4].Integer;
var i6 = u[5].Integer;
}
}
In my opinion this is not an ideal solution, but this might help you.
If you're using EntityFramework (or any other framework, I guess), the classes auto-generated are marked as partial, such as the following:
/Project/Data/TelJun2011.cs
namespace Project.Data
{
using System;
using System.Collections.Generic;
public partial class TelJun2011
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
/Project/Data/TelJul2011.cs
namespace Project.Data
{
using System;
using System.Collections.Generic;
public partial class TelJul2011
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
What partial means is that you can create another file for the same class. The generated classes don't implement an interface, but you can easily make then implement your custom interface like this:
/Project/Data/ITelMonth.cs
namespace Project.Data
{
public interface ITelMonth
{
int Id { get; set; }
string Name { get; set; }
string Description { get; set; }
}
}
/Project/Data/Partial/TelJun2011.cs
namespace Project.Data
{
public partial class TelJun2011 : ITelMonth { }
}
/Project/Data/Partial/TelJul2011.cs
namespace Project.Data
{
public partial class TelJul2011 : ITelMonth { }
}
And having correctly defined the interfaces, then we can simply do this:
var jul = (from n in TelJul2011s select (ITelMonth)n);
var jun = (from p in TelJun2011s select (ITelMonth)p);
var bimester = jun.Union(jul);
And you can even access the common properties like such:
foreach (var e in bimester)
{
e.Id.Dump();
}
If I have an object with nothing but private properties such as
public class Foo
{
private int Id { get; set; }
private string Bar { get; set; }
private string Baz { get; set; }
}
and store it in Raven, it will store those properties and everything works like magic. If I want to do some sort of read-only query off of the collection, how would I go about doing so using an index? (I'm actually open to any solution, even if it doesn't use indices.)
Obviously, something like this will not work because of the private access (and dynamic cannot be used in an expression tree):
public class Foo_LineItems : AbstractIndexCreationTask<Foo, FooLineItem>
{
public Foo_LineItems ()
{
Map = foos => foos.Where (x => x.Baz == null)
.Select (x => new { x.Id, x.Bar });
}
}
I'm sure I have overlooked something, but have been searching the web and cannot find anything that answers this specific question. The obvious answer is to segregate the reads and writes, using CQRS, and not actually persist the raw domain object. (This is just an experiment with Raven and CQS.)
We have untyped API for doing this:
public class Foo_LineItems : AbstractIndexCreationTask
{
public override IndexDefinition CreateIndexDefinition()
{
return new IndexDefinition
{
Map = #"
from foo in docs.Foos
where foo.Baz == null
select new { foo.Id, foo.Bar }
"
};
}
}