Return the content of an EF model's DbSet based on type - entity-framework

I have an entity framework context with tables EntityTypeA, EntityTypeB ... EntityTypeZ. I would like to create a method which returns an IEnumerable of IEntityModel, or in other words the content of the tables listed above.
I currently have a switch which, based on the type provided as argument, returns the content of the corresponding table.
Please consider the following code that I'm trying to factorize:
IEnumerable<IEntityModel> GetAllEntitiesByType(Type entityType)
{
NorthwindEntities en = new NorthwindEntities();
switch (entityType.Name)
{
case "EntitiesTypeA":
return en.EntitiesTypeA;
// all types in between
case "EntitiesTypeZ":
return en.EntitiesTypeZ;
default:
throw new ArgumentException("Unknown model type: " + entityType);
}
}
I would be surprised if there were no other more concise way to achieve the same result (by using reflection for instance) but I can't seem to find a useful example.
Any ideas please?

You can use the non generic DbContext.Set method to get the corresponding DbSet and then cast it to IEnumerable<IEntityModel> (important - do not use Cast method but regular C# cast operator):
IEnumerable<IEntityModel> GetAllEntitiesByType(Type entityType)
{
NorthwindEntities en = new NorthwindEntities();
return (IEnumerable<IEntityModel>)en.Set(entityType);
}

Consider using generic repository pattern. Here you can find an example.
Then implement the GetAllEntitiesByType function in your repository like this:
IEnumerable<T> GetAllEntitiesByType()
{
return entities.Set<T>();
}

Related

Can you use Lambda expressions against ObjectSets in Entity Framework?

I am using EF5, although I am sure it is a more general EF Question.
I cannot get the following to work. I keep getting casting error:
Unable to cast object of type 'System.Data.Objects.ObjectQuery`1[StdOrgUser]' to type 'System.Data.Objects.ObjectSet`1[StdOrgUser]'.
For the code:
public ObjectSet<StdOrgUser> StdOrgUser
{
get
{
if ((_StdOrgUser == null))
{
_StdOrgUser = base.CreateObjectSet<StdOrgUser>("StdOrgUser");
_StdOrgUser = (ObjectSet<StdOrgUser>) _StdOrgUser.Where(r => r.IsActive == false);
}
return _StdOrgUser;
}
}
It compiles fine. Intellisense enables me to choose LINQ operators etc. It is when I run it, that I get the above runtime error.
Where am I going wrong?
Many thanks for any help.
The ObjectSet class implements (amongst other things) IQueryable and IEnumerable, both of these interfaces have an extension method Where, see here and here. Neither IQueryable nor IEnumerable (which are the respective return types of the extension methods) can be cast back to ObjectSet.
The following line of code cannot be evaluated until run time:
_StdOrgUser = (ObjectSet<StdOrgUser>) _StdOrgUser.Where(r => r.IsActive == false);
but if you remove the cast the code will not compile:
_StdOrgUser = _StdOrgUser.Where(r => r.IsActive == false);
UPDATE
For querying you could change the return type of StdOrgUsers from ObjectSet to IQueryable but you lose all the other methods such as Add, Attach etc. You can't apply a standard filter using this technique. You could have an extension method called ActiveUsers()
public static IQueryable<StdOrgUser> ActiveUsers(this ObjectSet<StdOrgUser> users)
{
return users.Where(r => r.IsActive == false);
}
what you need to do is remember to use it in each query (not very pretty but it does clearly show intent)
var results = myContext
.StdOrgUser
.ActiveUsers()
.Where(//some filter);

Casting issue while returning value in method in EF4.0

I'm trying to load employees using Entity Framework.
The method is supposed to return employee list.
It' s giving this error:
Cannot implicit convert....<Class names and methods>.... An Explicit conversion exists.
I think the problem is related to casting.
Please check below code.
public List<Employee> LoadEmployees()
{
try
{
EMployeeDB1Entities EE = new EMployeeDB1Entities();
var Employees = EE.Employees.Where(p => p.Name.StartsWith("T"));
return Employees;
}
catch
{
return null;
}
}
var Employees = EE.Employees.Where(p => p.Name.StartsWith("T")).ToList();
Update your code to:
return Employees.ToList();
Also do note that this is the ToList() method that actually triggers the database query.
EE.Employees.Where(....) doesn't query the database. The DB is queried when the result of the Where() is enumerated, which is what .ToList() does.
Thanks it works...one more issue, suppose if I want to bind above list
to grid then how can I bind ?
Assuming you're using WPF or Silverlight:
To bind the result of your query on a datagrid, you could expose a public property of type ObservableCollection.
This collection accepts an IEnumerable<T> object as constructor.
You can write:
var myCollection = new ObservableCollection<Employee>(this.LoadEmployees());
Then bind the ItemSource property of your datagrid to your collection.
If you have more problems using bindings, I recommend you to ask another question, because the subject is quite different.

how can pass T dynamicaly in Ilist<T>?

i have a question.i have a method (Filter),i want to pass T dynamic.but it dosen`t accept.how can i do it?
public List<T> Filter<T>(string TypeOfCompare)
{
List<T> ReturnList2 = new List<T>();
return ReturnList2;
}
IList MakeListOfType(Type listType)
{
Type listType1 = typeof(List<>);
Type specificListType = listType.MakeGenericType(listType1);
return (IList)Activator.CreateInstance(specificListType);
}
Filter < ConstructGenericList(h) > ("s");
IList MakeListOfType(Type listType)
{
Type listType1 = typeof(List<>);
Type specificListType = listType.MakeGenericType(listType1);
return (IList)Activator.CreateInstance(specificListType);
}
It should be the other way round, you should call MakeGenericType on the generic type definition, not on the generic type argument. So the code becomes this:
IList MakeListOfType(Type elementType)
{
Type listType = typeof(List<>);
Type specificListType = listType.MakeGenericType(elementType);
return (IList)Activator.CreateInstance(specificListType);
}
(note that I changed the variables names to make the code clearer)
Generic parameters must have a type able to be determined at compile time (without resorting to something like functional type inference that some other languages have). So, you can't just stick a function between the angle brackets to get the type you want.
Edit:
Now that I know what you're trying to do, I would suggest a different approach entirely.
You mention that you are using Entity Framework, and you are trying to use one method to get a list of different types of objects. Those objects -- like Student and Teacher -- must have something in common, though, else you would not be trying to use the same method to retrieve a list of them. For example, you may just be wanting to display a name and have an ID to use as a key.
In that case, I would suggest defining an interface that has the properties common to Student, Teacher, etc. that you actually need, then returning a list of that interface type. Within the method, you would essentially be using a variant of the factory pattern.
So, you could define an interface like:
public interface INamedPerson
{
int ID { get; }
string FirstName { get; }
string LastName { get; }
}
Make your entities implement this interface. Auto-generated entities are (typically) partial classes, so in your own, new code files (not in the auto-generated code files themselves), you would do something like:
public partial class Student : INamedPerson
{
public int ID
{
get
{
return StudentId;
}
}
}
and
public partial class Teacher : INamedPerson
{
public int ID
{
get
{
return TeacherId;
}
}
}
Now, you may not even need to add the ID property if you already have it. However, if the identity property in each class is different, this adapter can be one way to implement the interface you need.
Then, for the method itself, an example would be:
public List<INamedPerson> MakeListOfType(Type type)
{
if (type == typeof(Student))
{
// Get your list of students. I'll just use a made-up
// method that returns List<Student>.
return GetStudentList().Select<Student, INamedPerson>(s => (INamedPerson)s)
.ToList<INamedPerson>();
}
if (type == typeof(Teacher))
{
return GetTeacherList().Select<Teacher, INamedPerson>(t => (INamedPerson)t)
.ToList<INamedPerson>();
}
throw new ArgumentException("Invalid type.");
}
Now, there are certainly ways to refine this pattern. If you have a lot of related classes, you may want to use some sort of dependency injection framework. Also, you may notice that there is a lot of duplication of code. You could instead pass a function (like GetStudentList or GetTeacherList) by doing something like
public List<INamedPerson> GetListFromFunction<T>(Func<IEnumerable<T>> theFunction) where T : INamedPerson
{
return theFunction().Select<T, INamedPerson>(t => (INamedPerson)t).ToList<INamedPerson>();
}
Of course, using this function requires, once again, the type passed in to be known at compile time. However, at some point, you're going to have to decide on a type, so maybe that is the appropriate time. Further, you can make your life a little simpler by leaving off the generic type at method call time; as long as you are passing in a function that takes no arguments and returns an IEnumerable of objects of the same type that implement INamedPerson, the compiler can figure out what to use for the generic type T.

Add index with entity framework code first (CTP5)

Is there a way to get EF CTP5 to create an index when it creates a schema?
Update: See here for how EF 6.1 handles this (as pointed out by juFo below).
You can take advantage of the new CTP5’s ExecuteSqlCommand method on Database class which allows raw SQL commands to be executed against the database.
The best place to invoke SqlCommand method for this purpose is inside a Seed method that has been overridden in a custom Initializer class. For example:
protected override void Seed(EntityMappingContext context)
{
context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ...");
}
As some mentioned in the comments to Mortezas answer there is a CreateIndex/DropIndex method if you use migrations.
But if you are in "debug"/development mode and is changing the schema all the time and are recreating the database every time you can use the example mentioned in Morteza answer.
To make it a little easier, I have written a very simple extension method to make it strongly typed, as inspiration that I want to share with anyone who reads this question and maybe would like this approach aswell. Just change it to fit your needs and way of naming indexes.
You use it like this: context.Database.CreateUniqueIndex<User>(x => x.Name);
.
public static void CreateUniqueIndex<TModel>(this Database database, Expression<Func<TModel, object>> expression)
{
if (database == null)
throw new ArgumentNullException("database");
// Assumes singular table name matching the name of the Model type
var tableName = typeof(TModel).Name;
var columnName = GetLambdaExpressionName(expression.Body);
var indexName = string.Format("IX_{0}_{1}", tableName, columnName);
var createIndexSql = string.Format("CREATE UNIQUE INDEX {0} ON {1} ({2})", indexName, tableName, columnName);
database.ExecuteSqlCommand(createIndexSql);
}
public static string GetLambdaExpressionName(Expression expression)
{
MemberExpression memberExp = expression as MemberExpression;
if (memberExp == null)
{
// Check if it is an UnaryExpression and unwrap it
var unaryExp = expression as UnaryExpression;
if (unaryExp != null)
memberExp = unaryExp.Operand as MemberExpression;
}
if (memberExp == null)
throw new ArgumentException("Cannot get name from expression", "expression");
return memberExp.Member.Name;
}
Update: From version 6.1 and onwards there is an [Index] attribute available.
For more info, see http://msdn.microsoft.com/en-US/data/jj591583#Index
This feature should be available in the near-future via data annotations and the Fluent API. Microsoft have added it into their public backlog:
http://entityframework.codeplex.com/workitem/list/basic?keywords=DevDiv [Id=87553]
Until then, you'll need to use a seed method on a custom Initializer class to execute the SQL to create the unique index, and if you're using code-first migrations, create a new migration for adding the unique index, and use the CreateIndex and DropIndex methods in your Up and Down methods for the migration to create and drop the index.
Check my answer here Entity Framework Code First Fluent Api: Adding Indexes to columns this allows you to define multi column indexes by using attributes on properties.

Entity Framework using Generic Predicates

I use DTO's to map between my Business and Entity Framework layer via the Repository Pattern.
A Standard call would look like
public IClassDTO Fetch(Guid id)
{
var query = from s in _db.Base.OfType<Class>()
where s.ID == id
select s;
return query.First();
}
Now I wish to pass in filtering criteria from the business layer so I tried
public IEnumerable<IClassDTO> FetchAll(ISpecification<IClassDTO> whereclause)
{
var query = _db.Base.OfType<Class>()
.AsExpandable()
.Where(whereclause.EvalPredicate);
return query.ToList().Cast<IClassDTO>();
}
The Call from the business layer would be something like
Specification<IClassDTO> school =
new Specification<IClassDTO>(s => s.School.ID == _schoolGuid);
IEnumerable<IClassDTO> testclasses = _db.FetchAll(school);
The problem I am having is that the .Where clause on the EF query cannot be inferred from the usage. If I use concrete types in the Expression then it works find but I do not want to expose my business layer to EF directly.
Try making FetchAll into a generic on a class instead, like this:-
public IEnumerable<T> FetchAll<T> (Expression<Func<T,bool>> wherePredicate)
where T:IClassDTO //not actually needed
{
var query = _db.Base.OfType<T>()
.AsExpandable()
.Where(wherePredicate);
return query;
}
pass in school.Evalpredicate instead. FetchAll doesn't appear to need to know about the whole specification, it just needs the predicate, right? If you need to cast it to IClassDTO, do that after you have the results in a List.