【问题标题】:Entity Framework Fluent, Table-Per-Type performance alternativesEntity Framework Fluent,Table-Per-Type 性能替代方案
【发布时间】:2013-02-07 18:34:13
【问题描述】:

我目前正在开发一个 EF Fluent 项目(是的,我确实喜欢这样编写它),该项目在 EF 4.3 上采用模型优先方法,采用 Table-Per-Type 架构。

正如我在过去几个月中发现的那样,Table-Per-Type 和继承并不能很好地发挥作用 -> more information。我正在使用具有七个派生类的单个基类,并且仅在七个派生类中返回项目并不是特别快。在执行时间方面,EF 检索包含 5 条记录的列表需要 5 到 7 秒,随后的执行大约需要 2.5 到 4 秒。可以肯定地说这是不可接受的,所以我正在寻找替代方法......

我能做的是多次访问数据库,即尝试检索每种类型的对象个体并整理成一个集合;但是,该代码充其量是笨拙的,即

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;

但它有效!对数据库的第一次点击需要 2 秒,随后的查询只需 200 毫秒。

我的问题是这不是很优雅、可维护等等。我一直在玩弄将 dbContext 转换为 ObjectContext 并使用类似这样的存储过程('spGetMyDerivedItems')运行返回所有派生的结果集在一个 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;

但是,这不适用于抱怨 CommandText 无效并且我必须提供“ContainerName”的 InvalidOperationException。我在这里的猜测是,如果我使用的是 EDMX 文件,我可以设置这个设置项(并且使用 DefaultContainerName 不起作用)。但是我正在采取一种流利的方法,我觉得我已经走到了死胡同。

所以...

有哪些方法可以解决 EF 和 table-per-type 的性能问题? 是否可以使用 Fluent / Model First 方法通过 ObjectContext 执行存储过程? 我可以执行标准 SQLClient.SqlDataReader 并转换为 ObjectContext 吗?

提前谢谢...

【问题讨论】:

  • 这可能不是您正在寻找的答案,所以我在这里只留下评论和一些参考:根据声明,在 EF 5/.NET 4.5 TPT 性能已“显着提高”这里:data.uservoice.com/forums/… 另一方面,EF 团队仍然不鼓励在这里使用 TPT:msdn.microsoft.com/en-us/data/hh949853.aspx 我不知道以秒或毫秒为单位的改进意味着什么。
  • 通常 SQL 生成质量和性能(特别是由于在 EF 5/.NET 4.5 中默认使用已编译查询)已得到改进:blogs.msdn.com/b/adonet/archive/2012/02/14/… 和 outofmemory.co.uk/… 改进的 TPT 可能受益于两者.
  • 只是出于好奇,为什么不使用 table-per-inheritance?
  • 我认为 .NET 4.5 的改进主要基于查询基本类型或使用 OfType + 自动编译查询。如果要查询所有类型,EF 仍然必须生成具有大量连接的复杂查询,并且性能会很差。
  • Josh - 不幸的是,我正在挑选这个项目,而不是自己构建它。 Slauma - 很高兴听到有一些改进,我们当前的开发阶段将使用以下解决方案运行,但我肯定会升级!

标签: c# .net entity-framework entity-framework-4 fluent


【解决方案1】:

好的 - ObjectContext 似乎可以从 System.Data.SqlClient.SqlDataReader 转换,这意味着我不需要(直接)从 dbContext 派生。这是示例代码...

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;

显然,最好的答案是 EF 会接受这一点,但我目前对上述内容感到满意。迁移到 EF5 听起来是一个不错的举措 - 但在不同的时间尺度下,你知道的魔鬼会更好:)

感谢您的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    相关资源
    最近更新 更多