I'm currently working on a EF Fluent project (yes, I do like writing it like that) that is taking a model first approach with Table-Per-Type architecture on EF 4.3.
As I've found out over the past couple of months, Table-Per-Type and inheritance just doesn't play nice -> more information . I'm using a single base class with seven derived classes and just returning items across the seven derived classes isn't particular fast. In terms of execution timings, to retreive a list of five records EF is taking a between 5 to 7 seconds, subsequent executions are around the 2.5 to 4 second mark. Safe to say this is just unacceptable so I'm looking at alternative methods...
What I can do is hit the database multiple times, ie attempt to retreive each type of object individual and collate into a single collection; however, the code is unwieldly at best, ie
IList<MyBaseClass> items = new List<MyBaseClass>();
dbContext.Database.SqlQuery<MyFirstDerivedClass>("SELECT * FROM MyBaseClass INNER JOIN MyFirstDerivedClass ON...").ToList().ForEach(x => items.Add(x));
... repeat for each derived class...
return items;
But it works! The first hit on the database takes 2 seconds and subsequent queries a mere 200 milliseconds.
My problem is that this is not very elegant, maintainable, etc, etc. I have been toying with casting the dbContext into an ObjectContext and running with something like this with a stored procedure ('spGetMyDerivedItems') returning all of the derived resultsets ordered in one db hit...
IList<MyBaseClass> items = new List<MyBaseClass>();
ObjectContext oContext = ((IObjectContextAdapter)dbContext).ObjectContext;
using (var connection = oContext.Connection as EntityConnection)
{
EntityCommand command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "spGetMyDerivedItems";
connection.Open();
using (EntityDataReader reader = command.ExecuteReader())
{
oContext.Translate<MyFirstDerivedClass>(reader).ToList().ForEach( x => items.Add(x));
reader.NextResult();
...repeat for each derived type...
}
}
return items;
However, this doesn't work with a InvalidOperationException complaining that the CommandText is not valid and that I must provide a 'ContainerName'. My guessing here is that if I was using an EDMX file, I could set this set item (and using the DefaultContainerName doesn't work). But I'm taking a fluent approach and I feel I've hit a dead end.
So...
What approaches are available to resolving the performance problems of EF and table-per-type? Is it possible to execute a stored procedure through the ObjectContext with Fluent / Model First approach? Can I execute a standard SQLClient.SqlDataReader and translate into an ObjectContext?
Thanks in advance...
OK - it appears that the ObjectContext can translate from System.Data.SqlClient.SqlDataReader meaning I don't need to derive (directly) from the dbContext. Here's the example code...
IList<MyBaseClass> items = new List<MyBaseClass>();
ObjectContext oContext = ((IObjectContextAdapter)dbContext).ObjectContext;
using (var sqlConn = new SqlConnection(dbContext.Database.Connection.ConnectionString))
{
SqlCommand sqlComm = new SqlCommand(){
Connection = sqlConn,
CommandText = "spGetMyDerivedItems",
CommandType = CommandType.StoredProcedure
};
sqlConn.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
oContext.Translate<MyFirstDerivedClass>(reader).ToList().ForEach( x => items.Add(x));
reader.NextResult();
...repeat for each derived type...
}
}
return items;
Obviously the best answer is that EF would pick this up but I'm happy with the above for the moment. Moving to EF5 sounds like a good move - but with various timescales its better the devil you know :)
Thanks for the help.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.