简体   繁体   中英

Entity Framework Fluent, Table-Per-Type performance alternatives

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM