Using reflection to address a Linqed property - c#

I'm trying to writing a generic method that will load a record of a specific type, with a specific ID. Here's one way that works:
public abstract class LinqedTable<T> where T : LinqableTable {
public static T Get(long ID) {
DataContext context = LinqUtils.GetDataContext<T>();
var q = from obj in context.GetTable<T>()
where obj.ID == ID
select obj;
return q.Single<T>();
}
}
public abstract class LinqableTable {
public abstract long ID { get; set; }
}
You can ignore the call to LinqUtils.GetDataContext<T>(); that's a utility function I've got to deal with the fact that I have multiple data contexts in my program. The point is that now I can declare any of my classes as subclasses of LinqableTable, and I can easily instantiate a record of that table just by calling LinqedTable<MyType>.Get(ID).
This has some limitations, however. Firstly, it forces all of my tables to have an I
identity field of type long, named ID. Secondly, because I'm using an abstract method, I am forced to go to the O/R designer and change the inheritance property of every ID field in my system to "override".
I want more flexibility than that. So naturally, I tried reflection, and came out with the following:
public abstract class LinqedTable<T> where T : LinqableTable {
public static T Get(long ID) {
DataContext context = LinqUtils.GetDataContext<T>();
var q = from obj in context.GetTable<T>()
where obj.IDValue == ID
select obj;
return q.Single<T>();
}
}
public abstract class LinqableTable {
internal long IDValue {
get { return (long)IDProperty.GetValue(this, null); }
set { IDProperty.SetValue(this, value, null); }
}
internal PropertyInfo IDProperty {
get { return this.GetType().GetProperty(IDPropertyName); }
}
internal protected virtual string IDPropertyName {
get { return "ID"; }
}
}
Theoretically, this allows me to override the ID column name, the cast to long should be OK with any integral data type, and I don't need to go defining all my ID columns as overrides.
BUT
Linq doesn't like this. On the call to q.Single<T>(); I get a runtime error:
The member 'EISS.Utils.LinqableTable.IDValue' has no supported translation to SQL.
OK, today I learned that Linq does some kind of magic on the back end; it doesn't instantiate obj and just read the IDValue property. So must be there's some attribute that needs to be set on the IDValue property that lets Linq do its thing.
But what?

Linq to SQL tries to translate your linq-query into SQL, but it does not know how to translate your property to a column name in the DB.
A good explanation can be found here on SO:
simple linq to sql has no supported translation to SQL
But how to solve it, is another matter. I have with succes used the apporoach from this thread:
http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/df9dba6e-4615-478d-9d8a-9fd80c941ea2/
Or you can use dynamic query as mentioned here by scott guthrie:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Having read these posts: Generic Data Access using LINQ to SQL and C#,
LINQ-to-SQL: Generic Primary Key function and
Calling a generic method with Type
My colleague and I came up with the following digest:
We added the following method to our datacontext (in a partial class).
public T GetInstanceByPrimaryKey<T>(object primaryKeyValue) where T : class
{
var table = this.GetTable<T>();
var mapping = this.Mapping.GetTable(typeof(T));
var pkfield = mapping.RowType.DataMembers.SingleOrDefault(d => d.IsPrimaryKey);
if (pkfield == null)
throw new Exception(String.Format("Table {0} does not contain a Primary Key field", mapping.TableName));
var param = Expression.Parameter(typeof(T), "e");
var predicate =
Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Property(param, pkfield.Name), Expression.Constant(primaryKeyValue)), param);
return table.SingleOrDefault(predicate);
}
Then, where we need to instanciate from the type name and primary key value:
string name = "LinqObjectName";
int primaryKey = 123;
var dc = new YourDataContext();
Type dcType = dc.GetType();
Type type = dcType.Assembly.GetType(String.Format("{0}.{1}", dcType.Namespace, name));
MethodInfo methodInfoOfMethodToExcute = dc.GetType().GetMethod("GetInstanceByPrimaryKey");
MethodInfo methodInfoOfTypeToGet = methodInfoOfMethodToExcute.MakeGenericMethod(name);
var instance = methodInfoOfTypeToGet.Invoke(dc, new object[] { primaryKey });
return instance;
Hope this helps!

Since LINQ statements referred to a LINQ-to-SQL IQueryable are translated to SQL queries, you will have to use the AsEnumerable extension (which will in turn cause a read of all the items in the database) and do reflection-related stuff on that IEnumerable.
EDIT
As required here's a clarificationAs specified in a comment, what I meant was something like:
(from obj in context.GetTable<T>() select obj).AsEnumerable().Where(x => x.IDValue == ID)
Unlike a query executed on an IQueryable, which can be perfectly translated to SQL such as
context.GetTable().Where(x => x.Text == "Hello")
which gets converted to something similar to
SELECT * FROM TABLE_MAPPED_TO_TYPE_T WHERE Text = 'Hello'
a query executed against an IEnumerable - in your case - will be executed by fetching all the entries of your table and then applying code-wise the specified filter.

Related

How to use Anonymous Type query in c# and ef core [duplicate]

I have the following generic method that I need to be able to perform a LINQ Where query in:
public static List<T> GetItems<T>(Guid parentId = new Guid()) where T : new()
{
var db = new SQLiteConnection(_dbPath);
List<T> result;
if (parentId != Guid.Empty)
{
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
}
else
{
result = db.Table<T>().ToList();
}
db.Close();
return result;
}
The compiler doesn't like the following line
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
error: cannot resolve 'ParentId'
Is it possible to use generics in this way in a LINQ query? Note that object of type T will always have a ParentId property.
You should concretize T parameter with some interface which will include required values. Also, you should add this interface to all types that contains this field or base type for its classes.
public interface IHierarchy
{
public Guid ParentId { get; }
}
public static List<T> GetItems<T>(Guid parentId = new Guid())
where T : IHierarchy, new()
{
var db = new SQLiteConnection(_dbPath);
List<T> result;
if (parentId != Guid.Empty)
{
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
}
else
{
result = db.Table<T>().ToList();
}
db.Close();
return result;
}
If you have 2 types of entities and the first contains required values and the second does not, then you can have two overloads for this scenario.
You used a generic type and the compiler don't know which entity are you going to use.
Just use reflection feature of .NET language.
result = db.Table<T>().Where(i => i.GetType().GetProperty("ParentId").GetValue(src, null).Equals(parentId)).ToList();
The problem is that in your code you assume that every T has a GUID property ParentId, while in fact you only required that every T has a default constructor. You need to require that every T has a ParentId.
You could do this by requiring that every T implements some interface. Like other answers suggest, however this is quite a nuisance, because for every class that you want to use this function for you'll need to implement this interface.
The function Enumerable.Where seems to be able to do the same job, without requiring any interface from the input items. So let's use the same method:
As input we tell which property to use (in your case ParentId) and with which value to compare (in your case parentId).
The only requirement we have is that we must be able to compare ParentId with parentId: it should be IEquatable
public List<T> GetItems<T, TKey>(Func<T, TKey> keySelector, Tkey value)
TKey : IEquatable<TKey>,
{
...
result = db.Table<T>()
.Where(t => keySelector(t).Equals(value))
.ToList();
}
Usage:
Guid value = ...
var items = GetItems<MyClass, Guid>(item => item.ParentId, value);
This function will also work with other classes and other properties:
int studentId = ...
var students = GetItems<Student, int>(student => student.Id, studentId);
var otherStudents = GetItems<Student, string>(student => student.Name, "John");
Two side remarks:
- you use new Guid() to define some default Guid. It is faster to use Guid.Empty
- You will not create new items of type T. They are already in your dbContext.Table. Therefore you don't need new().
- However, if your Table requires that T is a class then you should require that. See your Table definition:
where T : class

How can I get the type of the results of a LINQ query before executing it?

When EntityFramework executes a LINQ query, if query returns somethings as dynamic class, I can't get real type of result.
I have an abstract class:
abstract class Person
{
public string Name { get; set; }
//and about 1000 other properties
}
And 2 derived classes:
class RealPerson : Person
{
public void Print()
{
Console.WriteLine("Type=RealPerson, Name=" + Name);
}
}
class LegalPerson : Person
{
public void Print()
{
Console.WriteLine("Type=LegalPerson, Name=" + Name);
}
}
My LINQ TO SQL query:
var lst =
EFContext.Persons.Select(item=> new { DynamicClass_Name = item.Name }).ToList();
Now for every item in lst, I need to know type of its class to cast this item as that type, but item.GetType() returns a dynamic type.
For example assume that one of items of lst is RealPerson (called dynamicTypeItem), so if I know type of it is RealPerson I will cast this dynamicTypeItem to RealPerson using this code:
var value = dynamicTypeItem.GetType().GetProperty("DynamicClass_Name").GetValue(dynamicTypeItem);
var result = (RealPerson)Activator.CreateInstance(typeof(RealPerson));
result.GetType().GetProperty("Name").SetValue(result, value);
But I don't know type of this dynamicTypeItem (It has a dynamic type);
How to realize type of every item of lst?
It is very important that the above query selects only and only 1 property (Name property) of entities, so I can't use this code:
var lst =
EFContext.Persons.ToList().Select(item=> new { DynamicClass_Name = item.Name, Type=item.GetType() });
So I need knowing type of every item of lst before converting this item to dynamic type.
EDIT1
more explanation: result can't be Person because Person is abstract. result is RealPerson or LegalPerson, And when I select only one of properties of RealPerson or LegalPerson during convertion strongly type to anonymous type the type of original entity is missed.
You want to elicit the type from the value of one property of a database table? There is no way to select the type from that, since the type information is not fetched from database.
If you explain what it is you really need we might still be able to help you, but this constraint:
It is very important that the above query selects only and only 1 property (Name property) of entities
makes what you are trying to achieve impossible. You must select something more from the database.
How I could imaging doing it, although I would have a look at database design first if that is at all possible:
public partial class Person {
public Person() {
_dotnetType = this.GetType().Fullname;
_dotnetAssembly = this.GetType().Assembly.Fullname;
}
private string _dotnetType;
private string _dotnetAssembly;
public string DotNetType { get { return _dotnetType; } set { _dotnetType = value } }
public string DotNetAssembly { get { return _dotnetAssembl; } set { _dotnetAssembly = value } }
}
// Example usage
var peeps = from person in Entities.Persons
select new { Name = person.Name, Type = DotNetType, Assembly = DotNetAssembly };
var loadedPeople = peeps.ToList() // enumerate it
.Select( p => {
var instance = Activator.CreateInstance(p.Assembly, p.Type);
var property = p.GetType().GetProperties().First(prop => prop.Name == "Name");
property.SetValue(instance, p.Name, null);
});
I haven't tried this code, but it should work, just ensure that the parameterless constructor in Person gets called. The key point is that the database will "lose" the type information, so its better to store it as strings. Do remember that you need to add the columns to the database as well and map them!
This looks like an XY problem. Your question is, how do I instanciate objects from a table using Entity Frame (AND NOT Linq To SQL), where I have a discriminator?
The answer is simple.
YOU DON'T!
Use Single Table inheritance for your Entity Framework model and your LinqToEntities queries would be pretty simple.
Once you have that, there should be absolutely NO REASON WHAT SO EVER FOR YOUR PROJECTION.
You should be think about objects and not tables with an ORM.
So you could do the following to get all LegalPersons with name 'Alice'
var legallyAlices = EFContext.Persons.OfType<LegalPerson>()
.Where(x => x.Name == 'Alice');
OR
var legallyAlices = from legalPerson in EFContext.Persons.OfType<LegalPerson>()
where legalPerson.Name == 'Alice'
select legalPerson;

Entity framework - get entity by name

I have the following code (example):
public dynamic GetData(string name)
{
using(var ctx = GetObjectContext())
{
switch (name)
{
case "entity1":
return ctx.entity1.ToList();
case "entity2":
return ctx.entity2.ToList();
......
default:
return null;
}
}
}
I want to avoid switch in this sample. How can I find needed entity class by name, call the ToList() method and return data? Can I do this using reflection?
You can do it using reflection, however you will also need to use generics because the type of list returned by the ToList() method is different for each entity type.
You can access a property getter through reflection like so:
var enumerable = typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null);
Whereas [ClassNameOfContext] is the name of the class that ctx is an instance of. This is not obvious from your code, but you know it :-)
The problem is that enumerable will be an object and has to be casted to IEnumerable<EntityType> where EntityType is the type of entity you are accessing. In other words, it depends on the name you are passing. If you use generics to determine the type, you will be able to properly cast the object and don't have to return a dynamic even.
public TEntity Get<TEntity>(string name)
{
...
and transform the line from above:
var enumerable = (IEnumerable<TEntity>)(typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null));
return enumerable.ToList();
here you go!
Addendum: You could, conceivably, get rid of the string parameter, too - having names of types or properties in strings should be avoided where possible because it is not type safe. The compiler does not recognize it, and IDE features such as refactorings don't account for it. The problem here is that the property names are usually the pluralized form of the entity type names. But you could use reflection to find the property whose type matches the TEntity. I leave this as an exercise :-)
You can use code like this
private IEnumerable<TEntity> GetList<TEntity>(string connectionString, Func<object, T> caster)
{
using (var ctx = new DbContext(connectionString))
{
var setMethod = ctx.GetType().GetMethod("Set").MakeGenericMethod(typeof(T));
var querable = ((DbSet<object>)setMethod
.Invoke(this, null))
.AsNoTracking()
.AsQueryable();
return querable
.Select(x => caster(x))
.ToList();
}
}
To call like this:
var branchList = GetList<Branch>("connectionStringName", x => (Branch)x);
You can remove .AsNoTracking() and remove .ToList(), then you will get pure IQueryable which you can query further.
I've created a method to include all related entities with some help of the great answer of #chiccodoro.
using the entity "Product" which has 7 navigation properties
public static IQueryable<T> IncludeAllEntities<T>(this DbSet<T> entity, DataContext context) where T : class
{
var querable = entity.AsQueryable();
var type = typeof(T);
var entityType= context.Model.FindEntityType(type);
var navs = entityType?.GetNavigations();
if (navs==null)
{
return null;
}
List<string> navNames = new List<string>();
foreach (var nav in navs)
{
navNames.Add(nav.Name);
}
try
{
var agg = navNames.Aggregate(querable, (acc, name) => acc.Include(name));
return agg;
}
catch (Exception ex)
{
throw;
}
}
here I am getting the type of the entity to get the navigation properties, then adding the name of each one to a list of string, then aggregating over the list to include each entity.
then we can use this extension method like this:
var record= await _context.Products.IncludeAllEntities(_context).FirstOrDefaultAsync(x => x.Id == key);

Entity Wrapper - Custom

I would like find a workaround to accomplish a simple solution in order to automatize certain operation through EF.
What I need it's takeover during saving and retrieving process to modifying query result, but this class will be able to make that work for any type entities.
Example: I have a MyTestDb. So in my C# project I create a new entity model (MyTEstDbModel.edmx), with relative POCO class generation.
Well, a point of interest could be implementing a new custom class like following:
class Example
{
private ObjectContext _context;
private Example(ObjectContext obj) { _context = obj; }
public void Store(ObjectSet<???generic???> os)
{
// problem here: I dont't know the type contained in ObjectSet
// but if I Knew its type, I could make a work like this:
// -> foreach every instance in objectSet to check if exist some property
// via reflection, if i found them, then I set always the same values.
// Why this? Because all my db contains some common filed
// like (createdByUser, TimeToUpdate, and so on..), so it wold be boring
// setting all those fileds from any point of program.
}
public void Retrive(ObjectSet<???generic???> os)
{
// here problem too: all my queries will be filtered by one or more value
// fileds, but I cannot use lambaExpression cos I don't Know the type
// contained in objectSet<..>
}
//....
finally, by any point of program, the code should appear like following:
Example obj = new Example(myEntityContext); //-> global
var result = myEntityContext.ObjectSetTyped.Where(..lambaExpression..condition)
result.someProperty = "...";
obj.Store(result); // store method will fill all other boring filed automatically.
Can anyone give me some tips, help, suggestion about my issue?
Thanks in advance...
Update
Now, just only another problem. I'd to filter my ObjectSet through retrieve method like following:
public void Retrieve<TEntity>(IQueryable<TEntity> ooo) where TEntity : IC
{
ooo = ooo.Where(p => p.Filed == "MyDefaultValue");
}
But, from external method, not objectSet result is affect by my filter.
How so..?
MyEntities ent = new...
MyWrapper wrap = new MyWrapper();
wrap.Retrieve(ent.Users);
//problem here -> users objectSet is always the same..
Define interfaces which will allow you to do this. For example:
public interface IEntity
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
}
You need to "implement" this interface in your entities. You can for example either modify T4 template generating entities or implement it in partial class. Both properties must be already defined in the model so the implementation is only declarative:
public partial class MyEntity : IEntity // That's all
{ }
Now you can define Store like:
public void Store<TEntity>(TEntity entity) where TEntity : IEntity
{
...
}
Same can be done with query but you can for example define custom extension method:
public static IQueryable<TEntity> GetUserEntities(this IQueryable<TEntity> query, string user)
where TEntity : IEntity
{
return query.Where(e => e.CreatedBy == user);
}
You will simply define your query like:
var result = myEntityContext.MyEntities.GetUserEntities("someName");
Other approach is defining simply GetQuery on your custom context:
public IQueryable<T> GetQuery<T>() where T : IEntity
{
var query = GetObjectSetSomehow;
return query.ApplyGlobalConditions(); // Just another extension with your conditions
}
I'm not a big fan of the repository pattern but generally what you are trying to do is close to generic repository so check for example this post. It is just some example which can be further extended.
yeah, I just want a generic approach, likewise I realized with dataset and datatable.. but it seems impossible to achieve..
..ehmm..however, let me show yuo following code snippet, dynamic keyword looks like something to hopeful.... maybe I'm colse to solution..?
public ObjectSet<dynamic> Retrieve(string entity, string context)
{
Type myObjectContextType = Type.GetType(context);
ConstructorInfo cs = myObjectContextType .GetConstructor(new Type[] { });
dynamic myObjContext = cs.Invoke(new object[] { });
Type t = Type.GetType(entity);
ConstructorInfo xi = t.GetConstructor(new Type[] { });
dynamic UserEntity = xi.Invoke(new object[] { });
!problem here!
ObjectSet<?????> os = myObjContext.UserEntity.Where(...)
return ...
}
I'm very surprised..EF is a great instruments to develope more efficiently ways but too little "generalizalbe"

How to create LINQ Expression Tree to select an anonymous type

I would like to generate the following select statement dynamically using expression trees:
var v = from c in Countries
where c.City == "London"
select new {c.Name, c.Population};
I have worked out how to generate
var v = from c in Countries
where c.City == "London"
select new {c.Name};
but I cannot seem to find a constructor/overload that will let me specify multiple properties in my select lambda.
This can be done, as mentioned, with the help of Reflection Emit and a helper class I've included below. The code below is a work in progress, so take it for what it's worth... 'it works on my box'. The SelectDynamic method class should be tossed in a static extension method class.
As expected, you won't get any Intellisense since the type isn't created until runtime. Works good on late-bound data controls.
public static IQueryable SelectDynamic(this IQueryable source, IEnumerable<string> fieldNames)
{
Dictionary<string, PropertyInfo> sourceProperties = fieldNames.ToDictionary(name => name, name => source.ElementType.GetProperty(name));
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values);
ParameterExpression sourceItem = Expression.Parameter(source.ElementType, "t");
IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>();
Expression selector = Expression.Lambda(Expression.MemberInit(
Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);
return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[] { source.ElementType, dynamicType },
Expression.Constant(source), selector));
}
public static class LinqRuntimeTypeBuilder
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static AssemblyName assemblyName = new AssemblyName() { Name = "DynamicLinqTypes" };
private static ModuleBuilder moduleBuilder = null;
private static Dictionary<string, Type> builtTypes = new Dictionary<string, Type>();
static LinqRuntimeTypeBuilder()
{
moduleBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(assemblyName.Name);
}
private static string GetTypeKey(Dictionary<string, Type> fields)
{
//TODO: optimize the type caching -- if fields are simply reordered, that doesn't mean that they're actually different types, so this needs to be smarter
string key = string.Empty;
foreach (var field in fields)
key += field.Key + ";" + field.Value.Name + ";";
return key;
}
public static Type GetDynamicType(Dictionary<string, Type> fields)
{
if (null == fields)
throw new ArgumentNullException("fields");
if (0 == fields.Count)
throw new ArgumentOutOfRangeException("fields", "fields must have at least 1 field definition");
try
{
Monitor.Enter(builtTypes);
string className = GetTypeKey(fields);
if (builtTypes.ContainsKey(className))
return builtTypes[className];
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
foreach (var field in fields)
typeBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public);
builtTypes[className] = typeBuilder.CreateType();
return builtTypes[className];
}
catch (Exception ex)
{
log.Error(ex);
}
finally
{
Monitor.Exit(builtTypes);
}
return null;
}
private static string GetTypeKey(IEnumerable<PropertyInfo> fields)
{
return GetTypeKey(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
public static Type GetDynamicType(IEnumerable<PropertyInfo> fields)
{
return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
}
The accepted answer is very useful, but I needed something a little closer to a real anonymous type.
A real anonymous type has read-only properties, a constructor for filling in all of the values, an implementation of Equals/GetHashCode for comparing the values of each property, and an implementation ToString that includes the name/value of each property. (See https://msdn.microsoft.com/en-us/library/bb397696.aspx for a full description of anonymous types.)
Based on that definition of anonymous classes, I put a class that generates dynamic anonymous types on github at https://github.com/dotlattice/LatticeUtils/blob/master/LatticeUtils/AnonymousTypeUtils.cs. The project also contains some unit tests to make sure the fake anonymous types behave like real ones.
Here's a very basic example of how to use it:
AnonymousTypeUtils.CreateObject(new Dictionary<string, object>
{
{ "a", 1 },
{ "b", 2 }
});
Also, another note: I found that when using a dynamic anonymous type with Entity Framework, the constructor must be called with the "members" parameter set. For example:
Expression.New(
constructor: anonymousType.GetConstructors().Single(),
arguments: propertyExpressions,
members: anonymousType.GetProperties().Cast<MemberInfo>().ToArray()
);
If you used one of the versions of Expression.New that does not include the "members" parameter, Entity Framework would not recognize it as the constructor of an anonymous type. So I assume that means a real anonymous type's constructor expression would include that "members" information.
Maybe a bit late but may help to someone.
You Can generate dynamic select by call DynamicSelectGenerator in select from an entity.
public static Func<T, T> DynamicSelectGenerator<T>()
{
// get Properties of the T
var fields = typeof(T).GetProperties().Select(propertyInfo => propertyInfo.Name).ToArray();
// input parameter "o"
var xParameter = Expression.Parameter(typeof(T), "o");
// new statement "new Data()"
var xNew = Expression.New(typeof(T));
// create initializers
var bindings = fields.Select(o => o.Trim())
.Select(o =>
{
// property "Field1"
var mi = typeof(T).GetProperty(o);
// original value "o.Field1"
var xOriginal = Expression.Property(xParameter, mi);
// set value "Field1 = o.Field1"
return Expression.Bind(mi, xOriginal);
}
);
// initialization "new Data { Field1 = o.Field1, Field2 = o.Field2 }"
var xInit = Expression.MemberInit(xNew, bindings);
// expression "o => new Data { Field1 = o.Field1, Field2 = o.Field2 }"
var lambda = Expression.Lambda<Func<T, T>>(xInit, xParameter);
// compile to Func<Data, Data>
return lambda.Compile();
}
And use by this code:
var result = dbContextInstancs.EntityClass.Select(DynamicSelectGenerator<EntityClass>());
I don't believe that you will be able to achieve this. Although when you do select new { c.Name, c.Population } it seems like you're not creating a class you actually are. If you have a look at the compiled output in Reflector or the raw IL you will be able to see this.
You'll have a class which would look something like this:
[CompilerGenerated]
private class <>c__Class {
public string Name { get; set; }
public int Population { get; set; }
}
(Ok, I cleaned it up a touch, since a property is really just a get_Name() and set_Name(name) method set anyway)
What you're trying to do is proper dynamic class creation, something which wont be available until .NET 4.0 comes out (and even then I'm not really sure if it'll be able to achieve what you want).
You're best solution would be to define the different anonymous classes and then have some kind of logical check to determine which one to create, and to create it you can use the object System.Linq.Expressions.NewExpression.
But, it may be (in theory at least) possible to do it, if you're getting really hard-core about the underlying LINQ provider. If you are writing your own LINQ provider you can detect if the currently-parsed expression is a Select, then you determine the CompilerGenerated class, reflect for its constructor and create.
Defiantly not a simple task, but it would be how LINQ to SQL, LINQ to XML, etc all do it.
You could use the IQueryable-Extensions here, which is an implemantation of the solution described by "Ethan J. Brown":
https://github.com/thiscode/DynamicSelectExtensions
The Extension builds dynamically an anonymous type.
Then you can do this:
var YourDynamicListOfFields = new List<string>(
"field1",
"field2",
[...]
)
var query = query.SelectPartially(YourDynamicListOfFields);
You could use a parameter class instead of working with an anonymous type. In your example you can create a parameter class like this:
public struct ParamClass {
public string Name { get; set; };
public int Population { get; set; };
}
…and put it into your select like this:
var v = from c in Countries
where c.City == "London"
select new ParamClass {c.Name, c.Population};
What you get out is something of the type IQueryable<ParamClass>.
This compiles, I dunno if it works however...
myEnumerable.Select((p) => { return new { Name = p.Name, Description = p.Description }; });
Assuming p is what your transforming, and the select statement is returning an anon type, using the function declaration of lambda's.
Edit: I also don't know how you would generate this dynamically. But at least it shows you how to use the select lambda to return an anon type with multiple values
Edit2:
You would also have to bare in mind, that the c# compiler actually generates static classes of the anon type. So the anon type does actually have a type after compile time. So if your generating these queries at run time (which I assume you are) you may have to construct a type using the various reflection methods (I believe you can use them to make types on the fly) load the created types into execution context and use them in your generated output.
I think most of the things are already answered - as Slace said, you need some class that would be returned from the Select method. Once you have the class, you can use the System.Linq.Expressions.NewExpression method to create the expression.
If you really want to do this, you can generate class at runtime too. It's a bit more work, because it cannot be done using LINQ Expression trees, but it's possible. You can use System.Reflection.Emit namespace to do that - I just did a quick search and here is an article that explains this:
Introduction to Creating Dynamic Types with Reflection.Emit
You could use the Dynamic Expression API which allows you to dynamically build your select statement like this:
Select("new(<property1>,<property2>,...)");
You need the Dynamics.cs file from the LINQ and language samples for Visual Studio for this to work, both are linked at the bottom of this page. You can also see a working example showing this in action on at the same URL.

Categories

Resources