Is there a way of Implementing a Select Condition in LINQ DataContext - c#

I am working in a MVC3 project, and i am using LINQ to SQL. I have a database schema that uses a field to indicate if the record is active or deleted (field is boolean named "Active").
Now suppose there are two table linked such as State, and City, where City references State.
Let's say i have a method that returns a list of states:
public ActionResult ListStates()
{
return View(_repository.ListStates());
}
Now, i have implemented the repository method to return all states, and i could implement it in the following way:
public class Repository
{
public IQueryable<State> ListStates()
{
return dataContext.States.Where(p => p.Active == true)
}
}
In the view i could be sure i'm using only active states. But to be sure i'm using only active cities i would need to filter it in view, which makes the view uglier, or implement a custom view model. Both cases are valid, but they require a lot of work.
I have seen there are methods in data context where we can implement certain operations before an object gets inserted/updated into database, as this examle:
public partial class DatabaseDataContext
{
partial void InsertState(State instance)
{
instance.Active = true;
this.ExecuteDynamicInsert(instance);
}
}
The above method gets executed whenever an insert of the State object is happening.
My question is, is there a way to implement a condition only in one place for an object, for example to return only active records whenever a select is performed?

If I understood correctly, you're trying to eliminate the need of specifying .Where(p => p.Active == true) on methods of your repositories and you want to define it only once.
I'm not sure whether you can achieve this without creating a data context wrapper, because for each query you have to combine two logical expressions, the expression that comes from repository and p => p.Active == true.
The most simplest solution would be as follows:
/// <summary>
/// A generic class that provides CRUD operations againts a certain database
/// </summary>
/// <typeparam name="Context">The Database context</typeparam>
/// <typeparam name="T">The table object</typeparam>
public class DataContextWrapper<Context> where Context : DataContext, new()
{
Context DataContext;
/// <summary>
/// The name of the connection string variable in web.config
/// </summary>
string ConnectionString
{
get
{
return "Connection String";
}
}
/// <summary>
/// Class constructor that instantiates a new DataContext object and associates the connection string
/// </summary>
public DataContextWrapper()
{
DataContext = new Context();
DataContext.Connection.ConnectionString = ConnectionString;
}
protected IEnumerable<T> GetItems<T>([Optional] Expression<Func<T, bool>> query) where T : class, new()
{
//get the entity type
Type entity = typeof(T);
//get all properties
PropertyInfo[] properties = entity.GetProperties();
Expression<Func<T, bool>> isRowActive = null;
//we are interested in entities that have Active property ==> to distinguish active rows
PropertyInfo property = entity.GetProperties().Where(prop => prop.Name == "Active").SingleOrDefault();
//if the entity has the property
if (property != null)
{
//Create a ParameterExpression from
//if the query is specified then we need to use a single ParameterExpression for the whole final expression
ParameterExpression para = (query == null) ? Expression.Parameter(entity, property.Name) : query.Parameters[0];
var len = Expression.PropertyOrField(para, property.Name);
var body = Expression.Equal(len, Expression.Constant(true));
isRowActive = Expression.Lambda<Func<T, bool>>(body, para);
}
if (query != null)
{
//combine two expressions
var combined = Expression.AndAlso(isRowActive.Body, query.Body);
var lambda = Expression.Lambda<Func<T, bool>>(combined, query.Parameters[0]);
return DataContext.GetTable<T>().Where(lambda);
}
else if (isRowActive != null)
{
return DataContext.GetTable<T>().Where(isRowActive);
}
else
{
return DataContext.GetTable<T>();
}
}
}
And then you can create your repositories like this:
/// <summary>
/// States Repository
/// </summary>
public class StatesRepository : DataContextWrapper<DEMODataContext>
{
/// <summary>
/// Get all active states
/// </summary>
/// <returns>All active states</returns>
public IEnumerable<State> GetStates()
{
return base.GetItems<State>();
}
/// <summary>
/// Get all active states
/// </summary>
/// <param name="pattern">State pattern</param>
/// <returns>All active states tha contain the given pattern</returns>
public IEnumerable<State> GetStates(string pattern)
{
return base.GetItems<State>(s=>s.Description.Contains(pattern));
}
}
The usage:
StatesRepository repo = new StatesRepository();
var activeStates = repo.GetStates();
and
var filtered = repo.GetStates("Al");
Hope this helps ;)

You are looking for the dynamic linq library:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
I've used this before to insert a Where IsActive = true into all select statements before.

Related

How to write Repository method for .ThenInclude in EF Core 2

I'm trying to write a repository method for Entity Framework Core 2.0 that can handle returning child collections of properties using .ThenInclude, but I'm having trouble with the second expression. Here is a working method for .Include, which will return child properties (you supply a list of lambdas) of your entity.
public T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query.Where(predicate).FirstOrDefault();
}
Now here is my attempt at writing a method that will take a Tuple of two Expressions and feed those into a .Include(a => a.someChild).ThenInclude(b => b.aChildOfSomeChild) chain. This isn't a perfect solution because it only handles one child of a child, but it's a start.
public T GetSingle(Expression<Func<T, bool>> predicate, params Tuple<Expression<Func<T, object>>, Expression<Func<T, object>>>[] includeProperties)
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty.Item1).ThenInclude(includeProperty.Item2);
}
return query.Where(predicate).FirstOrDefault();
}
Intellisense returns an error saying "The type cannot be inferred from the usage, try specifying the type explicitly". I have a feeling it's because the expression in Item2 needs to be classified as somehow related to Item1, because it needs to know about the child relationship it has.
Any ideas or better techniques for writing a method like this?
I found this repository method online and it does exactly what I wanted. Yared's answer was good, but not all the way there.
/// <summary>
/// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method default no-tracking query.
/// </summary>
/// <param name="selector">The selector for projection.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="orderBy">A function to order elements.</param>
/// <param name="include">A function to include navigation properties</param>
/// <param name="disableTracking"><c>True</c> to disable changing tracking; otherwise, <c>false</c>. Default to <c>true</c>.</param>
/// <returns>An <see cref="IPagedList{TEntity}"/> that contains elements that satisfy the condition specified by <paramref name="predicate"/>.</returns>
/// <remarks>This method default no-tracking query.</remarks>
public TResult GetFirstOrDefault<TResult>(Expression<Func<TEntity, TResult>> selector,
Expression<Func<TEntity, bool>> predicate = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null,
bool disableTracking = true)
{
IQueryable<TEntity> query = _dbSet;
if (disableTracking)
{
query = query.AsNoTracking();
}
if (include != null)
{
query = include(query);
}
if (predicate != null)
{
query = query.Where(predicate);
}
if (orderBy != null)
{
return orderBy(query).Select(selector).FirstOrDefault();
}
else
{
return query.Select(selector).FirstOrDefault();
}
}
Usage:
var affiliate = await affiliateRepository.GetFirstOrDefaultAsync(
predicate: b => b.Id == id,
include: source => source
.Include(a => a.Branches)
.ThenInclude(a => a.Emails)
.Include(a => a.Branches)
.ThenInclude(a => a.Phones));
I had the same issue since EF Core doesn't support lazy loading but i tried to get workaround in the following way:
First create an attribute class to mark our desired navigation properties from other properties of a given class.
[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public class NavigationPropertyAttribute : Attribute
{
public NavigationPropertyAttribute()
{
}
}
Extension methods to filter out navigation properties and apply Include/ThenInclude using string based Eager loading.
public static class DbContextHelper
{
public static Func<IQueryable<T>, IQueryable<T>> GetNavigations<T>() where T : BaseEntity
{
var type = typeof(T);
var navigationProperties = new List<string>();
//get navigation properties
GetNavigationProperties(type, type, string.Empty, navigationProperties);
Func<IQueryable<T>, IQueryable<T>> includes = ( query => {
return navigationProperties.Aggregate(query, (current, inc) => current.Include(inc));
});
return includes;
}
private static void GetNavigationProperties(Type baseType, Type type, string parentPropertyName, IList<string> accumulator)
{
//get navigation properties
var properties = type.GetProperties();
var navigationPropertyInfoList = properties.Where(prop => prop.IsDefined(typeof(NavigationPropertyAttribute)));
foreach (PropertyInfo prop in navigationPropertyInfoList)
{
var propertyType = prop.PropertyType;
var elementType = propertyType.GetTypeInfo().IsGenericType ? propertyType.GetGenericArguments()[0] : propertyType;
//Prepare navigation property in {parentPropertyName}.{propertyName} format and push into accumulator
var properyName = string.Format("{0}{1}{2}", parentPropertyName, string.IsNullOrEmpty(parentPropertyName) ? string.Empty : ".", prop.Name);
accumulator.Add(properyName);
//Skip recursion of propert has JsonIgnore attribute or current property type is the same as baseType
var isJsonIgnored = prop.IsDefined(typeof(JsonIgnoreAttribute));
if(!isJsonIgnored && elementType != baseType){
GetNavigationProperties(baseType, elementType, properyName, accumulator);
}
}
}
}
Sample POCO classes implementing NavigationPropertyAttribute
public class A : BaseEntity{
public string Prop{ get; set; }
}
public class B : BaseEntity{
[NavigationProperty]
public virtual A A{ get; set; }
}
public class C : BaseEntity{
[NavigationProperty]
public virtual B B{ get; set; }
}
Usage in Repository
public async Task<T> GetAsync(Expression<Func<T, bool>> predicate)
{
Func<IQueryable<T>, IQueryable<T>> includes = DbContextHelper.GetNavigations<T>();
IQueryable<T> query = _context.Set<T>();
if (includes != null)
{
query = includes(query);
}
var entity = await query.FirstOrDefaultAsync(predicate);
return entity;
}
Json result for sample class C would be:
{
"B" : {
"A" : {
"Prop" : "SOME_VALUE"
}
}
}
Back in EF6 we could write something like this:
query.Include(t => t.Navigation1, t => t.Navigation2.Select(x => x.Child1));
And it was perfect and simple. We could expose it in an repository without dragging references from the EF assembly to other projects.
This was removed from EF Core, but since EF6 is open-source, the method that transforms the lambda expressions in paths can easily be extracted to use in EF Core so you can get the exact same behavior.
Here's the complete extension method.
/// <summary>
/// Provides extension methods to the <see cref="Expression" /> class.
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// Converts the property accessor lambda expression to a textual representation of it's path. <br />
/// The textual representation consists of the properties that the expression access flattened and separated by a dot character (".").
/// </summary>
/// <param name="expression">The property selector expression.</param>
/// <returns>The extracted textual representation of the expression's path.</returns>
public static string AsPath(this LambdaExpression expression)
{
if (expression == null)
return null;
TryParsePath(expression.Body, out var path);
return path;
}
/// <summary>
/// Recursively parses an expression tree representing a property accessor to extract a textual representation of it's path. <br />
/// The textual representation consists of the properties accessed by the expression tree flattened and separated by a dot character (".").
/// </summary>
/// <param name="expression">The expression tree to parse.</param>
/// <param name="path">The extracted textual representation of the expression's path.</param>
/// <returns>True if the parse operation succeeds; otherwise, false.</returns>
private static bool TryParsePath(Expression expression, out string path)
{
var noConvertExp = RemoveConvertOperations(expression);
path = null;
switch (noConvertExp)
{
case MemberExpression memberExpression:
{
var currentPart = memberExpression.Member.Name;
if (!TryParsePath(memberExpression.Expression, out var parentPart))
return false;
path = string.IsNullOrEmpty(parentPart) ? currentPart : string.Concat(parentPart, ".", currentPart);
break;
}
case MethodCallExpression callExpression:
switch (callExpression.Method.Name)
{
case nameof(Queryable.Select) when callExpression.Arguments.Count == 2:
{
if (!TryParsePath(callExpression.Arguments[0], out var parentPart))
return false;
if (string.IsNullOrEmpty(parentPart))
return false;
if (!(callExpression.Arguments[1] is LambdaExpression subExpression))
return false;
if (!TryParsePath(subExpression.Body, out var currentPart))
return false;
if (string.IsNullOrEmpty(parentPart))
return false;
path = string.Concat(parentPart, ".", currentPart);
return true;
}
case nameof(Queryable.Where):
throw new NotSupportedException("Filtering an Include expression is not supported");
case nameof(Queryable.OrderBy):
case nameof(Queryable.OrderByDescending):
throw new NotSupportedException("Ordering an Include expression is not supported");
default:
return false;
}
}
return true;
}
/// <summary>
/// Removes all casts or conversion operations from the nodes of the provided <see cref="Expression" />.
/// Used to prevent type boxing when manipulating expression trees.
/// </summary>
/// <param name="expression">The expression to remove the conversion operations.</param>
/// <returns>The expression without conversion or cast operations.</returns>
private static Expression RemoveConvertOperations(Expression expression)
{
while (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.ConvertChecked)
expression = ((UnaryExpression)expression).Operand;
return expression;
}
}
Then you can use it like this (put it in an QueryableExtensions class or something like that):
/// <summary>
/// Specifies related entities to include in the query result.
/// </summary>
/// <typeparam name="T">The type of entity being queried.</typeparam>
/// <param name="source">The source <see cref="IQueryable{T}" /> on which to call Include.</param>
/// <param name="paths">The lambda expressions representing the paths to include.</param>
/// <returns>A new <see cref="IQueryable{T}" /> with the defined query path.</returns>
internal static IQueryable<T> Include<T>(this IQueryable<T> source, params Expression<Func<T, object>>[] paths)
{
if (paths != null)
source = paths.Aggregate(source, (current, include) => current.Include(include.AsPath()));
return source;
}
And then in your repository you call it normally like you would do in EF6:
query.Include(t => t.Navigation1, t => t.Navigation2.Select(x => x.Child1));
References:
How to pass lambda 'include' with multiple levels in Entity Framework Core?
https://github.com/aspnet/EntityFramework6
When I need .ThenInclude I add my dbcontext class as dependency injection and write my query directly from dbcontext reference. I don't know if it is good or bad practice.

Getting property name and distinct values of a type T from a List<T> with reflection

I have a class Product with a set of properties:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string Categories { get; set; }
}
From a component, I obtain a List<Product> and, for several reasons, I need to use Reflection to get the properties of Product and then get the Distinct values and their Count() for each property.
Is it possible to achieve my goal through reflection? If not is there any other way to do it? Thanks!
UPDATE
The problem is that I do not know in advance which properties I have to use and which properties are in the Product class. That's why I think reflection is the best option.
I can achieve the same result by using a Switch - Case construct where the switch compare the Property Name extarcted from the class and each Case corresponds to a specific Property Name. But the flexibility of this solution is not enough for my problem
So it sounds like you're asking for something slightly different than the rest of us previously thought. You're not looking for the number of distinct values, or you're looking for the number of duplicates of each distinct value, which is essentially a group-by with a count of each group.
private static Dictionary<string, Dictionary<object, int>>
getDistinctValues<T>(List<T> list)
{
var properties = typeof(T).GetProperties();
var result = properties
//The key of the first dictionary is the property name
.ToDictionary(prop => prop.Name,
//the value is another dictionary
prop => list.GroupBy(item => prop.GetValue(item, null))
//The key of the inner dictionary is the unique property value
//the value if the inner dictionary is the count of that group.
.ToDictionary(group => group.Key, group => group.Count()));
return result;
}
At one point I had broken this up into two methods, but I condensed it down a bit to the point where I don't think it's needed. If you have trouble wrapping your head around all of the levels of nesting of this query feel free to ask for further clarifications.
private static int DistinctCount<T>(IEnumerable<T> items, string property)
{
var propertyInfo = typeof(T).GetProperty(property);
return items.Select(x => propertyInfo.GetValue(x, null)).Distinct().Count();
}
Usage:
List<Product> prods = GetProductsFromSomeplace();
int distinctCountById = DistinctCount(prods, "Id");
int distinctCountByName = DistinctCount(prods, "Name");
int distinctCountByCategories = DistinctCount(prods, "Categories");
If you want to allow for a custom IEqualityComparer for the properties, you can have an overload:
private static int DistinctCount<TItems, TProperty>(IEnumerable<TItems> items,
string property,
IEqualityComparer<TProperty> propertyComparer)
{
var propertyInfo = typeof(TItems).GetProperty(property);
return items.Select(x => (TProperty)propertyInfo.GetValue(x, null))
.Distinct(propertyComparer).Count();
}
And use like so:
List<Product> prods = GetProductsFromSomeplace();
int distinctCountById = DistinctCount(prods, "Id", new MyCustomIdComparer());
Where MyCustomIdComparer implements IEqualityComparer<TProperty> (in this case IEC<int>)
I present a solution below - but ideally you should look at breaking creating an abstraction for this problem that allows an object returning an IEnumerable<T> to provide a list of 'filterable' properties of the T, along with the values that are to be used. That way whatever is returning the data from the data source can do this with full knowledge. It pushes more of the work back to your data source/service/whatever, but it makes your UI much simpler.
Since you don't know the properties - then you can do this (I'm assuming assuming an IEnumerable because I'm assuming a generic solution is out - since you say you need reflection). If you do have a typed expression (i.e. you actually have a List<Product>) then a generic solution would be better as it would remove the need to get the first item:
public Dictionary<string, IEnumerable<object>>
GetAllPropertyDistincts(IEnumerable unknownValues)
{
//need the first item for the type:
var first = unknownValues.Cast<object>().First(); //obviously must NOT be empty :)
var allDistinct = first.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(p => new
{
PropName = p.Name,
Distinct = unknownValues.Cast<object>().Select(
o => property.GetValue(o, null)
).Distinct()
}).ToDictionary(v => v.PropName, v => v.Distinct);
}
Now you have a dictionary, keyed by the property name of every distinct value for each property of every object in your untyped enumerable (well - assuming they're all of the same type or base). Note - there might be some issues with properties of certain types and the default IEqualityComparer that the Distinct extension method uses - because it's a generic method and at the moment it'll be using EqualityComparer<object>.Default - which won't necessarily work for some types.
To turn this into a generic solution you can just change the first four lines to:
public Dictionary<string, IEnumerable<object>>
GetAllPropertyDistincts<T>(IEnumerable<T> unknownValues)
{
var allDistinct = typeof(T)
With the .GetProperties(BindingFlags.Public | BindingFlags.Instance) line following, and then change the inner call unknownValues.Cast<object>().Select( to just unknownValues.Select(.
If the list is not typed with Product but indeed with an open generic parameter T and this parameter has no restriction (where T : Product) then casting can help
int count = list
.Cast<Product>()
.Select(p => p.Id)
.Distinct()
.Count();
Okay, so I got slightly carried out with my answer, but here it is... a fully fledged distinct value counter. This doesn't completely answer your question, but should be a good start towards counting a property on a given object. Using this, in conjunction to looping through all of the properties on an object, should do the trick :p
/// <summary>
/// A distinct value counter, using reflection
/// </summary>
public class DistinctValueCounter<TListItem>
{
/// <summary>
/// Gets or sets the associated list items
/// </summary>
private IEnumerable<TListItem> ListItems { get; set; }
/// <summary>
/// Constructs a new distinct value counter
/// </summary>
/// <param name="listItems">The list items to check</param>
public DistinctValueCounter(IEnumerable<TListItem> listItems)
{
this.ListItems = listItems;
}
/// <summary>
/// Gets the distinct values, and their counts
/// </summary>
/// <typeparam name="TProperty">The type of the property expected</typeparam>
/// <param name="propertyName">The property name</param>
/// <returns>A dictionary containing the distinct counts, and their count</returns>
public Dictionary<TProperty, int> GetDistinctCounts<TProperty>(string propertyName)
{
var result = new Dictionary<TProperty, int>();
// check if there are any list items
if (this.ListItems.Count() == 0)
{
return result;
}
// get the property info, and check it exists
var propertyInfo = this.GetPropertyInfo<TProperty>(this.ListItems.FirstOrDefault(), propertyName);
if (propertyInfo == null)
{
return result;
}
// get the values for the property, from the list of items
return ListItems.Select(item => (TProperty)propertyInfo.GetValue(item, null))
.GroupBy(value => value)
.ToDictionary(value => value.Key, value => value.Count());
}
/// <summary>
/// Gets the property information, for a list item, by its property name
/// </summary>
/// <typeparam name="TProperty">The expected property type</typeparam>
/// <param name="listItem">The list item</param>
/// <param name="propertyName">The property name</param>
/// <returns>The property information</returns>
private PropertyInfo GetPropertyInfo<TProperty>(TListItem listItem, string propertyName)
{
// if the list item is null, return null
if (listItem == null)
{
return null;
}
// get the property information, and check it exits
var propertyInfo = listItem.GetType().GetProperty(propertyName);
if (propertyInfo == null)
{
return null;
}
// return the property info, if it is a match
return propertyInfo.PropertyType == typeof(TProperty) ? propertyInfo : null;
}
}
Usage:
var counter = new DistinctValueCounter<Person>(people);
var resultOne = counter.GetDistinctCounts<string>("Name");
If I understand the goal, you should be able to just use LINQ:
List<Product> products = /* whatever */
var distinctIds = products.Select(p=>p.Id).Distinct();
var idCount = distinctIds.Count();
...

Retrieve only base class from Entity Framework

If I have three classes in entity framework.
class Base {}
class Left : Base {}
class Right : Base {}
and I call DBContext.Bases.ToList();
This returns all instances of Base fully typed into their associated inherited types, as some people have noticed, the performance of EF on large inheritance structures is not great to say the least. My actual query in my project is 600 lines long, just for returning one entity and takes 2 seconds to generate.
They query runs much faster if you tell it which type to return, as it does not have to join across the whole structure. e.g.
DBContext.Bases.OfType<Left>.ToList();
or
DBContext.Bases.OfType<Right>.ToList();
However I now want to ONLY return the base class. Unfortunalty doing
DBContext.Bases.OfType<Base>.ToList();
does the same as
DBContext.Bases.ToList();
It gets the WHOLE inheritance structure... Is there any way (without making a new type in EF) of ONLY returning the class Base when looking through the Base collection?
Sorry I cant log into my actual account...
Maybe I didnt make myself clear, I want to bring back all the objects (including Base, Left and Right) but I only want the Base class to be returned, even if in the database they are actual Left and Right classes.
OFTYPE was a good suggestion but it filters out all my entities because none are the actual Base type. But I want to return only the Base type values in the Base type object.
Any ideas?
The GetType() is not understood by Entity Framework, but the keyword is does work. As such you can build an Expression and apply it to your query. The code here should work for EF5+ to add an extension method that you can call as: query.OfOnlyType<Base, SubTypeWithDescendants>(). (Or with the same two Type arguments if you need to, my hierarchy is more complicated than that though)
public static IQueryable<ReturnType> OfOnlyType<ReturnType, QueryType>
(this IQueryable<QueryType> query)
where ReturnType : QueryType {
// Look just for immediate subclasses as that will be enough to remove
// any generations below
var subTypes = typeof(ReturnType).Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(ReturnType)));
if (subTypes.Count() == 0) { return query.OfType<ReturnType>(); }
// Start with a parameter of the type of the query
var parameter = Expression.Parameter(typeof(ReturnType));
// Build up an expression excluding all the sub-types
Expression removeAllSubTypes = null;
foreach (var subType in subTypes) {
// For each sub-type, add a clause to make sure that the parameter is
// not of this type
var removeThisSubType = Expression.Not(Expression
.TypeIs(parameter, subType));
// Merge with the previous expressions
if (removeAllSubTypes == null) {
removeAllSubTypes = removeThisSubType;
} else {
removeAllSubTypes = Expression
.AndAlso(removeAllSubTypes, removeThisSubType);
}
}
// Convert to a lambda (actually pass the parameter in)
var removeAllSubTypesLambda = Expression
.Lambda(removeAllSubTypes, parameter);
// Filter the query
return query
.OfType<ReturnType>()
.Where(removeAllSubTypesLambda as Expression<Func<ReturnType, bool>>);
}
I've only tested it on EF6.1 with a code-first model. It borrows heavily from Alex James' tip 35.
To answer the question that none of the above answers seem to take care of (that is, we are only filtering returned columns to only be the base type columns, but not filtering out the rows that have derived type information), there is a fairly straightforward way of doing this with anonymous types. See here for another stackoverflow question dealing with the specifics.
The idea is to do something like this:
db.BaseTypes.Select(o => new { Prop1 = o.Prop1, Prop2 = o.Prop2, ....})
.AsEnumerable()
.Select(a => new BaseType() { Prop1 = a.Prop1, Prop2 = a.Prop2, ...});
The Linq-to-Entities will return a list of anonymous objects, while the .AsEnumerable() returns you back to Linq-to-Objects and allows you to call new BaseType() with an object initializer list.
This has an unfortunate downside of being specific to the types. Somebody here at the office wants a generic one written, so I'll return soon and edit this answer with a fully generic version of this.
EDIT (tested, but not in production EntityFramework):
Thanks to this answer for the SelectDynamic code.
public static class QueryableExtensions {
/// <summary>
/// Constructs a query that only selects the columns that are actually in the type <typeparamref name="T"/> as public properties.
///
/// Useful for inherited types when you only want the base type information.
/// </summary>
/// <remarks>
/// This function materializes the query. You'll want to call the where clauses BEFORE this call (since it is an optimization).
/// </remarks>
/// <typeparam name="T">Entity type.</typeparam>
/// <param name="query">Source query.</param>
/// <returns>An IEnumerable of items of type <typeparamref name="T"/>.</returns>
public static IEnumerable<T> FilterColumnsByType<T>(this IQueryable<T> query) where T : new() {
Type type = typeof(T);
List<string> selectedProps = type.GetProperties().Select(p => p.Name).ToList();
Tuple<IQueryable, Type> anonObjectTypePair = query.SelectDynamicAndType(selectedProps);
IQueryable anonObjects = anonObjectTypePair.Item1;
Type anonType = anonObjectTypePair.Item2;
return anonObjects.Cast<object>().AsEnumerable().Select(ob => {
var ret = new T();
selectedProps.ForEach(p =>
type.GetProperty(p).SetValue(ret, anonType.GetField(p).GetValue(ob)));
return ret;
});
}
/// <summary>
/// Constructs a query that selects only the <paramref name="propNames"/> given and returns an <see cref="IQueryable"/> of dynamic objects with only the selected fields.
///
/// Also returns the type information of the dynamic objects.
/// </summary>
/// <param name="source">Source query.</param>
/// <param name="propNames">The list of properties names to select.</param>
/// <returns>A query of anonymous types defined by the supplied <paramref name="propNames"/> and the actual <see cref="Type"/> used to construct anonymous type.</returns>
public static Tuple<IQueryable, Type> SelectDynamicAndType(this IQueryable source, IEnumerable<string> propNames) {
Dictionary<string, PropertyInfo> sourceProperties = propNames.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 Tuple.Create(source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[] { source.ElementType, dynamicType },
Expression.Constant(source), selector)), dynamicType);
}
/// <summary>
/// Constructs a query that selects only the <paramref name="propNames"/> given and returns an <see cref="IQueryable{dynamic}"/> of dynamic objects with only the selected fields.
/// </summary>
/// <param name="source">Source query.</param>
/// <param name="propNames">The list of properties names to select.</param>
/// <returns>A query of anonymous types defined by the supplied <paramref name="propNames"/>.</returns>
public static IQueryable<dynamic> SelectDynamic(this IQueryable source, IEnumerable<string> propNames) {
return source.SelectDynamicAndType(propNames).Item1.Cast<dynamic>();
}
static class LinqRuntimeTypeBuilder {
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) {
string key = string.Empty;
foreach (var field in fields.OrderBy(kvp => kvp.Key).ThenBy(kvp => kvp.Value.Name))
key += field.Key + ";" + field.Value.Name + ";";
return key;
}
private 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);
Console.WriteLine(ex);
} finally {
Monitor.Exit(builtTypes);
}
return null;
}
public static Type GetDynamicType(IEnumerable<PropertyInfo> fields) {
return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
}
}
Assuming you are able to use LINQ, could you use something along the lines of the following quick and dirty example?:
var result = from item in DBContext.Bases.ToList()
where (!item.GetType().IsSubclassOf(typeof(Base)))
select item;
Not sure about the performance differences, but i could imagine that this would be faster than loading all rows (when a lot of rows are in DB):
List<int> ids = DBContext.Rights.Select(x => x.Id).ToList();
ids.AddRange(DBContext.Lefts.Select(x => x.Id).ToList());
var bases = DBContext.Bases.Where(x => !ids.Contains(x.Id)).ToList();
You can use DbSet.SqlQuery:
DBContext.Bases.SqlQuery("select * from BaseTable").AsNoTracking().ToList();
Be aware that not using .AsNoTracking() will get you into hot water sooner or later (if there are derived types already loaded into the context you will get unique key violations/exceptions immediatelly).
I currently use the following LINQ extension, assuming sub-classes are located in the same assembly.
public static class MyLinqExtensions
{
public static IQueryable<T> OfTypeOnly<T>(this IQueryable<T> query)
{
Type type = typeof (T);
IEnumerable<Type> derivedTypes = Assembly
.GetAssembly(type)
.GetTypes()
.Where(t => t.IsSubclassOf(type));
return query.ExceptTypes(derivedTypes.ToArray());
}
public static IQueryable<T> ExceptTypes<T>(this IQueryable<T> query, params Type[] excludedTypes)
{
if (excludedTypes == null)
return query;
return excludedTypes.Aggregate(query,
(current, excludedType) => current.Where(entity => entity.GetType() != excludedType));
}
}
Usage:
var bases = DBContext.Bases.OfTypeOnly<Base>();

Pass variable type to a method without enumerating

I want to be able to pass a variable type to a method, mainly so that I can pass an entity framework query to a method that will apply common includes of nested object.
This is what I want to do...
public Person GetPersonByID(int personID)
{
var query = from Perspn p in Context.Persons
where p.PersonID = personID
select p;
ObjectQuery<Person> personQuery = ApplyCommonIncludes<Person>(query);
return personQuery.FirstOrDefault();
}
public ObjectQuery<T> ApplyCommonIncludes<T>(SomeType query)
{
return ((ObjectQuery<T>)query)
.Include("Orders")
.Include("LoginHistory");
}
Seems to be you actually want SomeType to be ObjectQuery<T>, right?
public ObjectQuery<T> ApplyCommonIncludes<T>(ObjectQuery<T> query)
{
return query
.Include("Orders")
.Include("LoginHistory");
}
This is valid syntax. Is there any problem with this?
This ought to work and do delayed execution (I think this is what you mean by "without enumerating") until FirstOrDefault() is called.
I ended up creating a different approach. My repository now has a list of string used for Includes. To retain type safety for creating includes, I created the following class:
/// <summary>
/// Builds Includes
/// </summary>
public class IncludeBuilder
{
/// <summary>
/// List of parts for the Include
/// </summary>
private List<string> Parts;
/// <summary>
/// Creates a new IncludeBuilder
/// </summary>
private IncludeBuilder()
{
this.Parts = new List<string>();
}
/// <summary>
/// Creates a new IncludeBuilder
/// </summary>
public static IncludeBuilder Create()
{
return new IncludeBuilder();
}
/// <summary>
/// Adds a property name to the builder
/// </summary>
public IncludeBuilder AddPart<TEntity, TProp>(Expression<Func<TEntity, TProp>> expression)
{
string propName = ExpressionHelper.GetPropertyNameFromExpression(expression);
this.Parts.Add(propName);
return this;
}
/// <summary>
/// Gets a value of the include parts separated by
/// a decimal
/// </summary>
public override string ToString()
{
return string.Join(".", this.Parts.ToArray());
}
This allows me to do this...
myPersonRepository.AppendInclude(
IncludeBuilder.Create()
.AddPart((Person p) => p.Orders)
.AddPart((Order o) => o.Items));
The above statement passes expressions to the IncludeBuilder class which then translates the above into "Orders.Items".
I then created helper methods in my RepositoryBase that given an ObjectQuery, will apply the includes, execute the query, and return the result. Not quite what I was looking for, but works well.

How do I create dynamic properties in C#?

I am looking for a way to create a class with a set of static properties. At run time, I want to be able to add other dynamic properties to this object from the database. I'd also like to add sorting and filtering capabilities to these objects.
How do I do this in C#?
You might use a dictionary, say
Dictionary<string,object> properties;
I think in most cases where something similar is done, it's done like this.
In any case, you would not gain anything from creating a "real" property with set and get accessors, since it would be created only at run-time and you would not be using it in your code...
Here is an example, showing a possible implementation of filtering and sorting (no error checking):
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1 {
class ObjectWithProperties {
Dictionary<string, object> properties = new Dictionary<string,object>();
public object this[string name] {
get {
if (properties.ContainsKey(name)){
return properties[name];
}
return null;
}
set {
properties[name] = value;
}
}
}
class Comparer<T> : IComparer<ObjectWithProperties> where T : IComparable {
string m_attributeName;
public Comparer(string attributeName){
m_attributeName = attributeName;
}
public int Compare(ObjectWithProperties x, ObjectWithProperties y) {
return ((T)x[m_attributeName]).CompareTo((T)y[m_attributeName]);
}
}
class Program {
static void Main(string[] args) {
// create some objects and fill a list
var obj1 = new ObjectWithProperties();
obj1["test"] = 100;
var obj2 = new ObjectWithProperties();
obj2["test"] = 200;
var obj3 = new ObjectWithProperties();
obj3["test"] = 150;
var objects = new List<ObjectWithProperties>(new ObjectWithProperties[]{ obj1, obj2, obj3 });
// filtering:
Console.WriteLine("Filtering:");
var filtered = from obj in objects
where (int)obj["test"] >= 150
select obj;
foreach (var obj in filtered){
Console.WriteLine(obj["test"]);
}
// sorting:
Console.WriteLine("Sorting:");
Comparer<int> c = new Comparer<int>("test");
objects.Sort(c);
foreach (var obj in objects) {
Console.WriteLine(obj["test"]);
}
}
}
}
If you need this for data-binding purposes, you can do this with a custom descriptor model... by implementing ICustomTypeDescriptor, TypeDescriptionProvider and/or TypeCoverter, you can create your own PropertyDescriptor instances at runtime. This is what controls like DataGridView, PropertyGrid etc use to display properties.
To bind to lists, you'd need ITypedList and IList; for basic sorting: IBindingList; for filtering and advanced sorting: IBindingListView; for full "new row" support (DataGridView): ICancelAddNew (phew!).
It is a lot of work though. DataTable (although I hate it) is cheap way of doing the same thing. If you don't need data-binding, just use a hashtable ;-p
Here's a simple example - but you can do a lot more...
Use ExpandoObject like the ViewBag in MVC 3.
Create a Hashtable called "Properties" and add your properties to it.
I'm not sure you really want to do what you say you want to do, but it's not for me to reason why!
You cannot add properties to a class after it has been JITed.
The closest you could get would be to dynamically create a subtype with Reflection.Emit and copy the existing fields over, but you'd have to update all references to the the object yourself.
You also wouldn't be able to access those properties at compile time.
Something like:
public class Dynamic
{
public Dynamic Add<T>(string key, T value)
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Dynamic.dll");
TypeBuilder typeBuilder = moduleBuilder.DefineType(Guid.NewGuid().ToString());
typeBuilder.SetParent(this.GetType());
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(key, PropertyAttributes.None, typeof(T), Type.EmptyTypes);
MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + key, MethodAttributes.Public, CallingConventions.HasThis, typeof(T), Type.EmptyTypes);
ILGenerator getter = getMethodBuilder.GetILGenerator();
getter.Emit(OpCodes.Ldarg_0);
getter.Emit(OpCodes.Ldstr, key);
getter.Emit(OpCodes.Callvirt, typeof(Dynamic).GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(typeof(T)));
getter.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethodBuilder);
Type type = typeBuilder.CreateType();
Dynamic child = (Dynamic)Activator.CreateInstance(type);
child.dictionary = this.dictionary;
dictionary.Add(key, value);
return child;
}
protected T Get<T>(string key)
{
return (T)dictionary[key];
}
private Dictionary<string, object> dictionary = new Dictionary<string,object>();
}
I don't have VS installed on this machine so let me know if there are any massive bugs (well... other than the massive performance problems, but I didn't write the specification!)
Now you can use it:
Dynamic d = new Dynamic();
d = d.Add("MyProperty", 42);
Console.WriteLine(d.GetType().GetProperty("MyProperty").GetValue(d, null));
You could also use it like a normal property in a language that supports late binding (for example, VB.NET)
I have done exactly this with an ICustomTypeDescriptor interface and a Dictionary.
Implementing ICustomTypeDescriptor for dynamic properties:
I have recently had a requirement to bind a grid view to a record object that could have any number of properties that can be added and removed at runtime. This was to allow a user to add a new column to a result set to enter an additional set of data.
This can be achieved by having each data 'row' as a dictionary with the key being the property name and the value being a string or a class that can store the value of the property for the specified row. Of course having a List of Dictionary objects will not be able to be bound to a grid. This is where the ICustomTypeDescriptor comes in.
By creating a wrapper class for the Dictionary and making it adhere to the ICustomTypeDescriptor interface the behaviour for returning properties for an object can be overridden.
Take a look at the implementation of the data 'row' class below:
/// <summary>
/// Class to manage test result row data functions
/// </summary>
public class TestResultRowWrapper : Dictionary<string, TestResultValue>, ICustomTypeDescriptor
{
//- METHODS -----------------------------------------------------------------------------------------------------------------
#region Methods
/// <summary>
/// Gets the Attributes for the object
/// </summary>
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return new AttributeCollection(null);
}
/// <summary>
/// Gets the Class name
/// </summary>
string ICustomTypeDescriptor.GetClassName()
{
return null;
}
/// <summary>
/// Gets the component Name
/// </summary>
string ICustomTypeDescriptor.GetComponentName()
{
return null;
}
/// <summary>
/// Gets the Type Converter
/// </summary>
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return null;
}
/// <summary>
/// Gets the Default Event
/// </summary>
/// <returns></returns>
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return null;
}
/// <summary>
/// Gets the Default Property
/// </summary>
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return null;
}
/// <summary>
/// Gets the Editor
/// </summary>
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return null;
}
/// <summary>
/// Gets the Events
/// </summary>
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return new EventDescriptorCollection(null);
}
/// <summary>
/// Gets the events
/// </summary>
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return new EventDescriptorCollection(null);
}
/// <summary>
/// Gets the properties
/// </summary>
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
List<propertydescriptor> properties = new List<propertydescriptor>();
//Add property descriptors for each entry in the dictionary
foreach (string key in this.Keys)
{
properties.Add(new TestResultPropertyDescriptor(key));
}
//Get properties also belonging to this class also
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this.GetType(), attributes);
foreach (PropertyDescriptor oPropertyDescriptor in pdc)
{
properties.Add(oPropertyDescriptor);
}
return new PropertyDescriptorCollection(properties.ToArray());
}
/// <summary>
/// gets the Properties
/// </summary>
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(null);
}
/// <summary>
/// Gets the property owner
/// </summary>
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion Methods
//---------------------------------------------------------------------------------------------------------------------------
}
Note: In the GetProperties method I Could Cache the PropertyDescriptors once read for performance but as I'm adding and removing columns at runtime I always want them rebuilt
You will also notice in the GetProperties method that the Property Descriptors added for the dictionary entries are of type TestResultPropertyDescriptor. This is a custom Property Descriptor class that manages how properties are set and retrieved. Take a look at the implementation below:
/// <summary>
/// Property Descriptor for Test Result Row Wrapper
/// </summary>
public class TestResultPropertyDescriptor : PropertyDescriptor
{
//- PROPERTIES --------------------------------------------------------------------------------------------------------------
#region Properties
/// <summary>
/// Component Type
/// </summary>
public override Type ComponentType
{
get { return typeof(Dictionary<string, TestResultValue>); }
}
/// <summary>
/// Gets whether its read only
/// </summary>
public override bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Gets the Property Type
/// </summary>
public override Type PropertyType
{
get { return typeof(string); }
}
#endregion Properties
//- CONSTRUCTOR -------------------------------------------------------------------------------------------------------------
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public TestResultPropertyDescriptor(string key)
: base(key, null)
{
}
#endregion Constructor
//- METHODS -----------------------------------------------------------------------------------------------------------------
#region Methods
/// <summary>
/// Can Reset Value
/// </summary>
public override bool CanResetValue(object component)
{
return true;
}
/// <summary>
/// Gets the Value
/// </summary>
public override object GetValue(object component)
{
return ((Dictionary<string, TestResultValue>)component)[base.Name].Value;
}
/// <summary>
/// Resets the Value
/// </summary>
public override void ResetValue(object component)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = string.Empty;
}
/// <summary>
/// Sets the value
/// </summary>
public override void SetValue(object component, object value)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = value.ToString();
}
/// <summary>
/// Gets whether the value should be serialized
/// </summary>
public override bool ShouldSerializeValue(object component)
{
return false;
}
#endregion Methods
//---------------------------------------------------------------------------------------------------------------------------
}
The main properties to look at on this class are GetValue and SetValue. Here you can see the component being casted as a dictionary and the value of the key inside it being Set or retrieved. Its important that the dictionary in this class is the same type in the Row wrapper class otherwise the cast will fail. When the descriptor is created the key (property name) is passed in and is used to query the dictionary to get the correct value.
Taken from my blog at:
ICustomTypeDescriptor Implementation for dynamic properties
You should look into DependencyObjects as used by WPF these follow a similar pattern whereby properties can be assigned at runtime. As mentioned above this ultimately points towards using a hash table.
One other useful thing to have a look at is CSLA.Net. The code is freely available and uses some of the principles\patterns it appears you are after.
Also if you are looking at sorting and filtering I'm guessing you're going to be using some kind of grid. A useful interface to implement is ICustomTypeDescriptor, this lets you effectively override what happens when your object gets reflected on so you can point the reflector to your object's own internal hash table.
As a replacement for some of orsogufo's code, because I recently went with a dictionary for this same problem myself, here is my [] operator:
public string this[string key]
{
get { return properties.ContainsKey(key) ? properties[key] : null; }
set
{
if (properties.ContainsKey(key))
{
properties[key] = value;
}
else
{
properties.Add(key, value);
}
}
}
With this implementation, the setter will add new key-value pairs when you use []= if they do not already exist in the dictionary.
Also, for me properties is an IDictionary and in constructors I initialize it to new SortedDictionary<string, string>().
I'm not sure what your reasons are, and even if you could pull it off somehow with Reflection Emit (I' not sure that you can), it doesn't sound like a good idea. What is probably a better idea is to have some kind of Dictionary and you can wrap access to the dictionary through methods in your class. That way you can store the data from the database in this dictionary, and then retrieve them using those methods.
Why not use an indexer with the property name as a string value passed to the indexer?
Couldn't you just have your class expose a Dictionary object? Instead of "attaching more properties to the object", you could simply insert your data (with some identifier) into the dictionary at run time.
If it is for binding, then you can reference indexers from XAML
Text="{Binding [FullName]}"
Here it is referencing the class indexer with the key "FullName"

Categories

Resources