I have an abstract class:
public abstract class Entity<T> where T : Tweet
{
protected string _name;
public abstract string Name { get; set; }
public abstract List<Tweet> tweets { get; set; }
}
Which is sub-classed by several different classes (their names are Person, Place and Organisation). I store lots of instances of the Entity class in a List<T> instance.
I have a separate method that is used to combine different List<Entity<Tweet>> instances into one another, joining them on Entity.Name and merging their containing List<Tweet>:
private static List<Entity<Tweet>> joinLists(List<Entity<Tweet>> list1, List<Entity<Tweet>> list2)
{
List<Entity<Tweet>> joined;
joined = list1.Union(list2)
.GroupBy(o => o.Name)
.Select(o => new Entity<Tweet> // this is wrong as class is abstract but at this point I don't know what concrete class o is?
{
Name = o.Key,
tweets =
o.SelectMany(x => x.tweets).ToList()
}).ToList();
return joined;
}
Unfortunately as Entity is an abstract class, I cannot create an instance of it, so how can I dynamically determine the actual concrete class of the o instance in the LINQ expression. I have a separate method that does this based on a string representation of an object's class name, but I would like to know how this would be achieved with LINQ (method below is my implementation for use elsewhere in my application):
private static Entity<Tweet> createEntity(string className, Tweet tweet, string value)
{
Entity<Tweet> entity = null;
Type t = Type.GetType("FinalUniProject.NERModels." + className);
entity = (Entity<Tweet>)Activator.CreateInstance(t);
entity.Name = value;
// Allow for inverted index by adding tweet to NamedEntist List<TweetModel>
if (entity.tweets == null) entity.tweets = new List<Tweet>();
entity.tweets.Add(tweet);
return entity;
}
Line of code below do not give any compile error for sure. Haven't checked all aspects. U sure this wont work ?
joined = list1.Union(list2)
.GroupBy(o => o.Name)
.Select(o =>
{
Entity<Tweet> entity = null;
string className = o.First().GetType().Name;
Type t = Type.GetType("FinalUniProject.NERModels." + className);
entity = (Entity<Tweet>)Activator.CreateInstance(t);
entity.Name = o.Key;
// Allow for inverted index by adding tweet to NamedEntist List<TweetModel>
entity.tweets = o.ToList().SelectMany(x => x.tweets).ToList();
return entity;
}).ToList();
Related
I have a problem in fetching the record from a generic list. I have created a common function from where i want to get the records from any type of class. Below is sample code:-
public void Test<T>(List<T> rEntity) where T : class
{
object id = 1;
var result = rEntity.Where(x => x.id == id);
}
Please suggest. Thanks in advance.
With method like that a usual question for compiler is 'what is T' ?
If it's just a class it could be anything even a StringBuilder as Jon has mentioned and there is no guarantee that it has a property 'Id'. So it won't even compile the way it is right now.
To make it work we have two options :
A) Change the method and let compiler know what type to expect
B) Use reflection and use run-time operations (better avoid this when possible but may come handy when working with 3rd party libraries).
A - Interface solution :
public interface IMyInterface
{
int Id {get; set;}
}
public void Test<T>(List<T> rEntity) where T : IMyInterface
{
object id = 1;
var result = rEntity.Where(x => x.id == id);
}
B - Reflection solution:
public void Test<T>(List<T> rEntity)
{
var idProp = typeof(T).GetProperty("Id");
if(idProp != null)
{
object id = 1;
var result = rEntity.Where(x => idProp.GetValue(x).Equals(id));
}
}
You most define a basic class that have id property and your T most be inherit from that basic class.
public class BaseClass{
public object ID;
}
and you can change your function like this:
public void Test<T>(List<T> rEntity) where T : BaseClass
{
object id = 1;
var result = rEntity.Where(x => x.id == id);
}
I have implemented an interface for some of my entity classes:
public partial class Order : IReportable
{
public string TableName { get { return "Order"; } }
}
public partial class Client: IReportable
{
public string TableName { get { return "Client"; } }
}
public interface IReportable
{
string TableName { get; }
}
Then I added this to the DbContext:
public virtual DbSet<IReportable> IReportable { get; set; }
When I try to query all the tables that implement this interface (as shown here):
var result = from reportabletable in db.IReportable
where reportabletable.TableName == table_name
select reportabletable
I get the following exception:
The type 'Report.DataAccess.IReportable' was not mapped. Check that
the type has not been explicitly excluded by using the Ignore method
or NotMappedAttribute data annotation. Verify that the type was
defined as a class, is not primitive or generic, and does not inherit
from EntityObject.
I would go for something like this:
Create this extension method
public static class DbContextExtensions
{
public static IEnumerable<T> SetOf<T>(this DbContext dbContext) where T : class
{
return dbContext.GetType().Assembly.GetTypes()
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface)
.SelectMany(t => Enumerable.Cast<T>(dbContext.Set(t)));
}
}
And use it like this:
using (var db = new dbEntities())
{
var result = from reportabletable in db.SetOf<IReportable>()
where reportabletable.TableName == table_name
select reportabletable
}
EF doesn't like mapping interfaces directly to tables. You can get around this by making using a generic Repository, as outlined Here!
Then use repository method and supply the Type of the table(s) you want to query. Something like: myRepo.GetAll<myClient.GetType()>();
Get the classes that inherit that interface and run the query for all of them:
var types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes().Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)));
foreach (var mytype in types)
{ // aggregate query results }
Hope this helps! There is probably a more graceful solution
First of all MarcGravell comment is on the money. Its up to you to know which table to query.
Personally I go through list of poco types that implement an interface or have an custom attribute. But if you are keen to go via the DBContext only, here are some extensions that give you access to the "names". You will still need to access that part of the context afterwards one at a time.
Again you can do that via generics, but you can just go directly as you suggest.
You will need to iterate of a list of types.
eg:
ReportRespository : BaseRespository where t : IReport
Check the assembly for Certain types and attributes
eg
/// <summary>
/// POCOs that have XYZ Attribute of Type and NOT abstract and not complex
/// </summary>
/// <returns></returns>
public static List<Type> GetBosDirDBPocoList() {
var result = new List<Type>();
// so get all the Class from teh assembly that public non abstract and not complex
foreach (var t in Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.BaseType != null
&& t.IsClass
&& t.IsPublic
&& !t.IsAbstract
&& !t.IsComplexType()
&& t.GetMyAttribute() != null)) {
result.Add(t);
}
}
return result;
}
public static GetMyAttribute(this Type T) {
var myAttr= T.GetCustomAttributes(true)
.Where(attribute => attribute.GetType()
.Name == "XYZAttr").Cast<BosDir>().FirstOrDefault();
return myAttr;
}
Extensions
public static class DalExtensions {
// DbSet Names is the plural property name in the context
public static List<string> GetModelNames(this DbContext context) {
var propList = context.GetType().GetProperties();
return GetDbSetNames(propList);
}
// DbSet Names is the plural property name in the context
public static List<string> GetDbSetTypeNames<T>() where T : DbContext {
var propList = typeof (T).GetProperties();
return GetDbSetNames(propList);
}
// DBSet Types is the Generic Types POCO name used for a DBSet
public static List<string> GetModelTypes(this DbContext context) {
var propList = context.GetType().GetProperties();
return GetDbSetTypes(propList);
}
// DBSet Types POCO types as IEnumerable List
public static IEnumerable<Type> GetDbSetPropertyList<T>() where T : DbContext {
return typeof (T).GetProperties().Where(p => p.PropertyType.GetTypeInfo()
.Name.StartsWith("DbSet"))
.Select(propertyInfo => propertyInfo.PropertyType.GetGenericArguments()[0]).ToList();
}
// DBSet Types is the Generic Types POCO name used for a DBSet
public static List<string> GetDbSetTypes<T>() where T : DbContext {
var propList = typeof (T).GetProperties();
return GetDbSetTypes(propList);
}
private static List<string> GetDbSetTypes(IEnumerable<PropertyInfo> propList) {
var modelTypeNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet"))
.Select(p => p.PropertyType.GenericTypeArguments[0].Name)
.ToList();
return modelTypeNames;
}
private static List<string> GetDbSetNames(IEnumerable<PropertyInfo> propList) {
var modelNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet"))
.Select(p => p.Name)
.ToList();
return modelNames;
}
}
}
Accepted solution does not work in EF Core.
Here is my first working draft
public IEnumerable<T> SetOf<T>() where T : class
{
var firstType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
.FirstOrDefault(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
if (firstType == null) return new List<T>();
var dbSetMethodInfo = typeof(DbContext).GetMethod("Set");
var dbSet = dbSetMethodInfo.MakeGenericMethod(firstType);
IQueryable<T> queryable = ((IQueryable)dbSet.Invoke(this, null)).Cast<T>();
return queryable.ToList().Cast<T>();
}
Then you could use like this
_dbContext.SetOf<ISomeInterface>();
More info here Expose method DbContext.Set(Type entityType)
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;
I have the following query:
// Type T is constrained to a class that contains "ID" property
// propertiesToQuery is a list constructed based on type T
var set = AppContext.Set<T>();
var result = set.SelectMany(x => propertiesToQuery.Select(p => new { x.ID, Value = x.GetType().GetProperty(p.Name).GetValue(x) })
.Where(p => p.Value != null)
.Select(p => new SearchIndexItem
{
Key = p.Value.ToString(),
Url = Url.Action("Edit", type.Name, new { p.ID }),
Type = type
}));
Now because linq to entities does not allow to use PropertyInfo in queries, I need to run a ToList() on the set in order to execute the query on the db first and then perform the desired SelectMany().
This queries more than it needs to from the database which will be a problem when there's a lot of data (queried columns are of type string, others can be blobs and these are the ones I don't want to pull the data from)
So the question is how can I limit the columns queried from the db based on a list constructed at runtime?
I was trying to create an expression tree, and pass it to the Select() method on the set, but the problem was with creating the anonymous type, which can be different depenging on type T.
Your observation here:
the problem was with creating the anonymous type, which can be different depenging on type T
is accurate; it is hugely problematic to construct the result columns at runtime. The only simply way to do that is to make it look like you are populating a projection of a type that has all the members, for example the equivalent of:
// where our list is "Foo", "Bar":
x => new SomeType {
Foo = x.Foo,
Bar = x.Bar
// but other SomeType properties exist, but are't mapped
}
The obvious contender would be the entity type, so you are partially mapping a set of Customer rows to Customer objects - but most ORMs won't let you do that: if the projection is an entity type they want the entire type (i.e. x => x). You might be able to create a second version of the entity type that is a regular POCO/DTO but isn't part of the entity model, i.e.
Customer x => new CustomerDto {
Foo = x.Foo,
Bar = x.Bar
}
which you can do as part of Expression.MemberInit at runtime. Example:
class Foo
{
public string A { get; set; }
public int B { get; set; }
public DateTime C { get; set; }
}
class FooDto
{
public string A { get; set; }
public int B { get; set; }
public DateTime C { get; set; }
}
class Program
{
static void Main(string[] args)
{
var data = new[] { new Foo { A = "a", B = 1, C = DateTime.Now}}
.AsQueryable();
var mapped = PartialMap<Foo, FooDto>(data, "A", "C").ToList();
}
static IQueryable<TTo> PartialMap<TFrom, TTo>(
IQueryable<TFrom> source, params string[] members)
{
var p = Expression.Parameter(typeof(TFrom));
var body = Expression.MemberInit(Expression.New(typeof(TTo)),
from member in members
select (MemberBinding)Expression.Bind(
typeof(TTo).GetMember(member).Single(),
Expression.PropertyOrField(p, member))
);
return source.Select(Expression.Lambda<Func<TFrom, TTo>>(body, p));
}
}
in the output, A and C have values, but B does not.
I am endeavoring to write a test method to determine if a class has a superset of properties of a different class. This is for purposes of mapping from domain objects to view model objects and as such there is no relationship between the two classes.
As an example if I had the domain class Foo and the view model class FooMap I would want to test that Foo had the properties that FooMap expected it to.
public class Foo
{
public string Bar { get;set; }
public string Baz { get;set; }
public string NoOneCaresProp { get; set; }
public string GetBarBaz() { return Bar + Baz; }
}
public class FooMap
{
public string Bar { get; set; }
public string GetBarBaz { get; set; }
public string NotAFooProp { get; set; }
}
Given the properties of FooMap for the purposes of this test I want to ensure that class Foo has the Bar property and the GetBarBaz method. Additional methods or properties for either class should be ignored. I've written the following static method to perform such a test but am not happy with my implementation:
public static void ExpectedPropertiesExist<TSource, TDestination, R>(params
Expression<Func<TDestination, R>>[] exclude)
{
var excludedProperties = exclude.Select(e => (e.Body as
MemberExpression).Member.Name);
var mappedProperties = typeof(TDestination).GetProperties()
.Select(p => p.Name)
.Except(excludedProperties);
var sourceType = typeof(TSource);
var baseTypeNames = sourceType.GetProperties().Select(b => b.Name).ToList();
baseTypeNames.AddRange(sourceType.GetMethods().Select(b => b.Name));
Assert.IsTrue(new HashSet<string>(baseTypeNames)
.IsSupersetOf(mappedProperties));
}
The code to call the above is not nearly as succinct as I would like it to be:
// what my call to the function looks like now
TestExtensionFun.ExpectedPropertiesExist<Foo, FooMap,
object>(fm => fm.NotAFooProp);
// I'd prefer it to look like this
TestExtensionFun.ExpectedPropertiesExist<Foo, FooMap>(fm => fm.NotAFooProp);
Nor am I sure that the method is as proficient as it could be. What is the best mechanism to write a generic test method to ensure that a class has a subset of properties of a separate class?
Since you don't really care what the expressions return (you are passing in object as the type for R), you could just remove the generic type parameter R from the ExpectedPropertiesExist method:
public static void ExpectedPropertiesExist<TSource, TDestination>(params
Expression<Func<TDestination, object>>[] exclude)
{
var excludedProperties = exclude.Select(e => (e.Body as
MemberExpression).Member.Name);
var mappedProperties = typeof(TDestination).GetProperties()
.Select(p => p.Name)
.Except(excludedProperties);
var sourceType = typeof(TSource);
var baseTypeNames = sourceType.GetProperties().Select(b => b.Name).ToList();
baseTypeNames.AddRange(sourceType.GetMethods().Select(b => b.Name));
Assert.IsTrue(new HashSet<string>(baseTypeNames)
.IsSupersetOf(mappedProperties));
}
This way, you can call the method with your desired syntax (only two generic type parameters).