Finding all properties that are the same generic class - c#

If you're unfamiliar with the Entity Framework, it generates a class that looks like
public partial class contextontext : DbContext
{
public virtual DbSet<foo> foo { get; set; }
public virtual DbSet<bar> bar { get; set; }
//Etc, there could be lots of these DbSet properties
}
I'm trying to build a list of types that there are DbSet<T> collections for, but I'm not sure how to check for a generic type. I got it to work using PropertyType.ToString().StartsWith("System.Data.Entity.DbSet`1") but that seems like a messy and unnecessarily complicated way to do it. This is the full LINQ I use to get the properties.
foreach (var property in context.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.PropertyType.ToString().StartsWith("System.Data.Entity.DbSet`1")))
{
Type type = property.PropertyType.GenericTypeArguments[0];
//other stuff...
}
I poked around in the property object, but didn't find any leads. There's a Type in there, but that's always the type specific implementation of the generic DbSet (as it should be). How would I check to see if it's the generic collection, regardless of what type it is?

I think you want simply:
var propertyType = property.PropertyType;
if (propertyType.IsGenericType
&& propertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
{
// ...
}
I see now your Where far to the right in your code. That would be:
.Where(p => p.PropertyType.IsGenericType
&& p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
The method GetGenericTypeDefinition goes from the concrete constructed ("closed") generic type (e.g. DbSet<foo>), to the definition of the type (here DbSet<TEntity>).

Related

Linq query for Where condition on Collection of variant object's property

I'm accessing an Interop model that has the following structure
Projects is a collection containing multiple Project objects
The Project object has a State property and a Properties collection
The Properties collection contains Variant/Object/Property objects
The Property always has a Name property
I want to use Linq to:
Find all Projects Find the first Property object (1 or more projects may have a Property.Name == "InitiatorName". I just want the first Property Object that has Property.Name == "IntiatorName". That is I don't care which Project the Property Object belongs to.
Where Project.State = state_initiated
and the Project.Properties that have Project.Name = "InitiatorName"
Here is the Linq that I'm trying (which C# doesn't like)... I think I have the first couple of line correct, but I'm unsure how to deal with the variant Property objects.
Is there something I can do in Linq, or do I have to enumerate all of the property objects?
var result = dept.Projects
.Cast<Project>()
.Where(project => project.State == pState.state_initiated)
.SelectMany(project => project.Properties())
.Where(property => property.Name == "InitiatorName");
This is the Interop signature of the Properties Interface:
public interface _Properties : IEnumerable
{
[DispId(1)]
Application Application { get; }
[DispId(40)]
int Count { get; }
[DispId(2)]
object Parent { get; }
[DispId(-4)]
[TypeLibFunc(1)]
IEnumerator GetEnumerator();
[DispId(0)]
Property Item(object index);
}
And the Property signature looks like this:
public interface Property
{
[DispId(41)]
Properties Collection { get; }
[DispId(40)]
string Name { get; }
[DispId(1)]
Properties Parent { get; }
[DispId(0)]
object Value { get; set; }
}
You need to do something like this:
var result = dept.Projects
.Cast<Project>()
.Where(project => project.State == pState.state_initiated)
.SelectMany(project => project.Properties().OfType<Property>())
.FirstOrDefault(property => property.Name == "InitiatorName");
This code is assuming that Properties is a method of Project.
If it is a property of Project, then you need to use .Properties.OfType<Property>() instead of .Properties().OfType<Property>().
You might want to use Cast instead of TypeOf if you are sure that Properties only contains objects of type Property which is probably the case.
By accessing SelectMany of Properties you will not get Projects as required, but properties.
Try this query:
var result = dept.Projects
.Cast<Project>()
.Where(
project =>
project.State == pState.state_initiated &&
project.Properties().Any(property => property.Name == "InitiatorName"));
"Properties()" may not deliver null. So if there is scenario where it could happen please handle the situation by null checking.

Using reflection to cast an IList<Interface> to List<T>

I am working on a WCF service and I have run into a bit of a snag mapping my entities to my DTO. Consider the following
namespace Foo.Entities
{
public class Order : IOrder
{
public string Name { get;set; }
public string Address { get;set; }
public IList<ILocation> Locations { get;set; }
}
}
namespace Foo.DTO
{
[DataContract]
public class Order
{
[DataMember]
public string Name { get;set; }
[DataMember]
public string Address { get;set; }
[DataMember]
public List<Location> Locations { get;set; }
}
}
This is all very straightforward: DTO.Order is what I am returning from my endpoint and Entities.Order is what I am using internally (I am using DI / IOC) for business logic, data operations, etc. Since my business layer returns types from the Entities namespace, but the endpoint returns types from the DTO namespace I wrote a small mapping method that will take one type and map it to another type like so:
public TTarget MapObject<TSource, TTarget>(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
foreach (var prop in source.GetType().GetProperties())
{
var targetProp = target.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
if(targetProp == null || !targetProp.CanWrite) continue;
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
??
}
else{ targetProp.SetValue(target, prop.GetValue(source)); }
}
return target;
}
I then call this method like so:
factory.MapObject(Entities.DealerOrder, new GTO.DealerOrder())
where Entities.DealerOrder represents an instantiated object that contains data.
Everything works fine until I get to the property of type IList and I am at a loss at how to convert the IList to List. I know what needs to happen but all of the documentation I have read thus far hasn't pointed me in the right direction.
The pseudo is
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
var lst = new List<type of targetProp>()
foreach(var val in prop.GetValue())
{
var item = new Location() (I have to figure out this initialization based on the List type of targetProp. In this case it would be List<Location>)
var retval = MapObject(val, item);
lst.Add(retval);
}
targetProp.SetValue(target, lst);
}
I am not sure if what I want to do is even possible. I know that Generics and Reflection don't mix well so if there is a solution it might be overly complex for what I am really trying to accomplish. If worse comes to worse I can put a static method on each of my DTO's that will accept the source type as a parameter and return an instance of the DTO, but I want to avoid having to manually map the fields from the Entity to the DTO if at all possible.
Any help is greatly appreciated.
You can use targetProp.GetGenericArguments()[0]; to get the type of item you want to map your collection content to.
You can use Activator.CreateInstance to create List<T> with T known at runtime at not at compile time.
You can use Activator.CreateInstance to create instance of the type you want to map to.
You can't rely on type inference when calling MapObject anymore. You need to create proper generic method via reflection here too, and call it.
You can't simply call Add on the list, because you don't know what kind of list it is. You can cast it to ICollection and call Add on it instead.
Can't you just use something like AutoMapper? Those are problems people already solved, why don't you use their work?

How can I change the schema of a type that implements a particular interface in an Entity Framework 6 Custom Convention?

I created an interface ILookupValue that I want all lookup values to inherit from.
public interface ILookupValue
{
public bool Enabled { get; set; }
}
How can I determine if the current entitySet implements the interface so that I can set the schema for that entitySet to something other than the default?
I've tried the following, but it doesn't work:
public void Apply(EntitySet entitySet, DbModel model)
{
ILookupValue lookupCheck = entitySet.GetType() as ILookupValue;
if (lookupCheck != null) { entitySet.Schema = "lu"; }
}
Update: I've tried the following also, but get an object reference not set error.
if (typeof(ILookupValue).IsAssignableFrom(Type.GetType(entitySet.ElementType.Name))) { entitySet.Schema = "lu"; }
Since EF doesn't actually use your types, you need to get them from the assembly. My biggest problem was that this convention was part of a library, so I didn't know ahead of time the assembly name and I couldn't find how to get it from the EF EntityType model. Therefore, I just created a static method that searches all loaded assemblies for the type name and returns it. I got the idea from this stackoverflow answer.
public static class TypeUtils
{
public static Type FindType(string name)
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic)
.SelectMany(a => a.GetTypes())
.FirstOrDefault(t => t.Name.Equals(name));
}
}
Then I updated my convention to find the type based on the EntitySet.ElementType.Name and then check to see if it implements the interface.
public void Apply(EntitySet entitySet, DbModel model)
{
Type type = TypeUtils.FindType(entitySet.ElementType.Name);
if (type != null)
{
if (typeof(ILookupValue).IsAssignableFrom(type)) { //make changes here; }
}
}

Dynamic cast to generic type

Just a quickie before the weekend rolls in...
I have a Method with the following signature, that I need to invoke:
public interface IObjectProvider<T>
{
T Get(Predicate<T> condition);
}
This will provide me with a T from whatever kind of source, that meets the predicate criteria.
Now, this has to be called from a context where all I have is the following:
//the actual predicate that's going to be evaluated
var predicate = predicateProperty.GetValue(invocation.InvocationTarget, null);
//The type that should go into the call as type param
Type relationTargetType = relationDefinition.RelatedType;
As you might guess, the compiler won't let me use the predicate variable as parameter. What I need to do is convert this object into a Predicate, but Generic type params must be compile-time-constant, so this won't work.
I've started messing around with this, but no success so far:
Type genericPredicateType = typeof(Predicate<>);
Type specificPredicateType= genericPredicateType.MakeGenericType(relationTargetType);
Convert.ChangeType(predicate, specificPredicateType)
How on earth can I mash this up?
EDIT: I thought this was a rather use-case-agnostic question, but obviously I was wrong. So, since there is such a fuss as to what I do, what I have and why and whatnot, here's a lot more background info. I am trying to resolve relations between objects in a Proxy (Castle Dynamic Proxy). The following Snippet should explain the kind of relation I want to depict:
public class Order
{
public virtual int Id { get; set; } // OR-Mapped
public virtual DateTime OrderDate { get; set; } // OR-Mapped
[RelatedObject(typeof(Address), "DeliveryAddressPredicate")]
public virtual Address DeliveryAddress { get; set; }
public Predicate<Address> DeliveryAddressPredicate
{
get { return new Predicate<Address>(a => OrderDate >= a.ValidFrom && OrderDate <= a.ValidTo); }
}
}
public class Address
{
public virtual DateTime ValidFrom { get; set; } // OR-Mapped
public virtual DateTime ValidTo { get; set; } // OR-Mapped
//Not OR-Mapped
[RelatedList(typeof(Order), "OrdersPredicate")]
public virtual IList<Order> Orders { get; set; }
public Predicate<Order> OrdersPredicate
{
get { return new Predicate<Order>(o => o.OrderDate >= ValidFrom && o.OrderDate <= ValidTo); }
}
To sum it up, this is supposed to become a Fuzzy OR-Mapping, meant to extend NHibernate in a project or two.
How did I mean to get this to work? The address is proxied, and when a call to a property with one of my CustomAttributes is made, i use DynamicProxy's IInterceptor interface to resolve the relation. The main problem is that this resolving has to happen in the IInterceptor.Intercept() Method which has only one Param (see here), and I have no generic type param available. So, in the end it all boils down to a simple .Net question again: I have a Type stored in a variable and a Method that has to be called with a parameter generic of the aforesaid type...
Sorry for any mistakes made (like calling var a Type - man that was a rough one), it's been quite a day ;-)
You have some IObjectProvider<T>. If T is a type know at compile-time, you can just use a cast. For example, if T was Foo:
IObjectProvider<Foo> provider = …;
var predicate = (Predicate<Foo>)predicateProperty.GetValue(
invocation.InvocationTarget, null);
Foo item = provider.Get(predicate);
EDIT: It seems you don't know T at compile time. This means you have two options:
Use dynamic:
object provider = …
object predicate = predicateProperty.GetValue(
invocation.InvocationTarget, null);
object item = ((dynamic)provider).Get((dynamic)predicate);
Use reflection:
object provider = …;
object predicate = predicateProperty.GetValue(
invocation.InvocationTarget, null);
var getMethod = provider.GetType().GetMethod("Get");
object item = getMethod.Invoke(provider, new[] { predicate });
This question shows a lot of confusion about types, var etc.
This is a meaningless sentence
It is of type var and GetValue turned it into an object.
I think you are saying
I have some code that needs a Predicate<T>
You have some code (that you don't show us) that returns an Object. And want somehow to coerce that return value into a Predicate<T>. If the returned object is a Predicate<T> then simply go (Predicate<T>)retobj - and you are done. If it's not a type that can be cast to Predicate<T> then no amount of jiggling will make it into a Predicate<T>.
I do this way
public T CastToType<T>(object objType, T type) where T : class
{
var cast = objType as T;
if(cast == null)
throw new InvalidCastException();
return cast;
}
And like this
var test = CastToType(objType, new ArrayList());
test will be have ArrayList type

LinqToSql and abstract base classes

I have some linq entities that inherit something like this:
public abstract class EntityBase { public int Identifier { get; } }
public interface IDeviceEntity { int DeviceId { get; set; } }
public abstract class DeviceEntityBase : EntityBase, IDeviceEntity
{
public abstract int DeviceId { get; set; }
}
public partial class ActualLinqGeneratedEntity : DeviceEntityBase
{
}
In a generic method I am querying DeviceEnityBase derived entities with:
return unitOfWork.GetRepository<TEntity>().FindOne(x => x.DeviceId == evt.DeviceId);
where TEntity has a contraint that is it a DeviceEntityBase. This query is always failing with an InvalidOperationException with the message "Class member DeviceEntityBase.DeviceId is unmapped". Even if I add some mapping info in the abstract base class with
[Column(Storage = "_DeviceId", DbType = "Int", Name = "DeviceId", IsDbGenerated = false, UpdateCheck = UpdateCheck.Never)]
Wow, looks like for once I may be able to one-up #MarcGravell!
I had the same problem, then I discovered this answer, which solved the problem for me!
In your case, you would say:
return unitOfWork.GetRepository<TEntity>().Select(x => x).FindOne(x => x.DeviceId == evt.DeviceId);
and Bob's your uncle!
LINQ-to-SQL has some support for inheritance via a discriminator (here, here), but you can only query on classes that are defined in the LINQ model - i.e. data classes themselves, and (more perhaps importantly for this example) the query itself must be phrased in terms of data classes: although TEntity is a data class, it knows that the property here is declared on the entity base.
One option might be dynamic expressions; it the classes themselves declared the property (i.e. lose the base class, but keep the interface) - but this isn't trivial.
The Expression work would be something like below, noting that you might want to either pass in the string as an argument, or obtain the primary key via reflection (if it is attributed):
static Expression<Func<T, bool>> BuildWhere<T>(int deviceId) {
var id = Expression.Constant(deviceId, typeof(int));
var arg = Expression.Parameter(typeof(T), "x");
var prop = Expression.Property(arg, "DeviceId");
return Expression.Lambda<Func<T, bool>>(
Expression.Equal(prop, id), arg);
}
This kind of heirarchial mapping isnot possible with LinqToSql. The the mapping is setup it cannot map to properties in base classes. I went around on this for a couple of months when it first came out. The best solution is to use the entity framework. It gives you much more flexibility with creating your object model. It will allow you to do exactly what your trying to do here.
Here is some information on the entity framework: MSDN Article
Try .OfType<>() as posted here https://stackoverflow.com/a/17734469/3936440, it works for me having the exact same issue.

Categories

Resources