Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架(6)绩效优化建议_C#_.net_Performance_Entity Framework_Entity Framework 6 - Fatal编程技术网

C# 实体框架(6)绩效优化建议

C# 实体框架(6)绩效优化建议,c#,.net,performance,entity-framework,entity-framework-6,C#,.net,Performance,Entity Framework,Entity Framework 6,我的应用程序中有一个ADO.Net数据访问层,它使用基本ADO.Net和CRUD存储过程(每个操作一个,例如Select_myTable、Insert_myTable)。您可以想象,在一个大型系统(如我们的系统)中,DA层所需的DB对象数量相当大 我一直在研究将层类重构为EF POCO类的可能性。我已经设法做到了,但当我尝试进行性能测试时,它变得非常可怕。使用下面的类(创建对象、将Key设置为所需的值、调用dataselect),100000次数据加载只需要大约47秒(数据库中只有少量记录)。而

我的应用程序中有一个ADO.Net数据访问层,它使用基本ADO.Net和CRUD存储过程(每个操作一个,例如Select_myTable、Insert_myTable)。您可以想象,在一个大型系统(如我们的系统)中,DA层所需的DB对象数量相当大

我一直在研究将层类重构为EF POCO类的可能性。我已经设法做到了,但当我尝试进行性能测试时,它变得非常可怕。使用下面的类(创建对象、将Key设置为所需的值、调用dataselect),100000次数据加载只需要大约47秒(数据库中只有少量记录)。而存储的Proc方法大约需要7秒

我正在寻找关于如何优化这一点的建议——值得注意的是,我不能更改层的公开功能——只能更改它如何实现方法(即,我不能将上下文所有权的责任传递给BO层)

谢谢

public class DAContext : DbContext
{
    public DAContext(DbConnection connection, DbTransaction trans)
        : base(connection, false)
    {
        this.Database.UseTransaction(trans);

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //Stop Pluralising the Object names for table names.
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        //Set any property ending in "Key" as a key type.
        modelBuilder.Properties().Where(prop => prop.Name.ToLower().EndsWith("key")).Configure(config => config.IsKey());

    }

    public DbSet<MyTable> MyTable{ get; set; }
}

public class MyTable : DataAccessBase
{

    #region Properties

    public int MyTableKey { get; set; }

    public string Name { get; set; }
    public string Description { get; set; }
    public bool Active { get; set; }
    public int CreatedBy { get; set; }
    public DateTime CreatedDate { get; set; }
    public int ModifiedBy { get; set; }
    public DateTime ModifiedDate { get; set; }

    #endregion

    #region constructors

    public MyTable()
    {
        //Set Default Values.
        Active = true;
        Name = string.Empty;
        CreatedDate = DateTime.MinValue;
        ModifiedDate = DateTime.MinValue;
    }

    #endregion

    #region Methods

    public override void DataSelect(System.Data.SqlClient.SqlConnection connection, System.Data.SqlClient.SqlTransaction transaction)
    {
        using (DAContext ctxt = new DAContext(connection, transaction))
        {

            var limitquery = from C in ctxt.MyTable
                             select C;


            //TODO: Sort the Query
            limitquery = FilterQuery(limitquery);

            var limit = limitquery.FirstOrDefault();

            if (limit != null)
            {
                this.Name = limit.Name;
                this.Description = limit.Description;
                this.Active = limit.Active;
                this.CreatedBy = limit.CreatedBy;
                this.CreatedDate = limit.CreatedDate;
                this.ModifiedBy = limit.ModifiedBy;
                this.ModifiedDate = limit.ModifiedDate;
            }
            else
            {
                throw new ObjectNotFoundException(string.Format("No MyTable with the specified Key ({0}) exists", this.MyTableKey));
            }
        }
    }

    private IQueryable<MyTable1> FilterQuery(IQueryable<MyTable1> limitQuery)
    {
        if (MyTableKey > 0) limitQuery = limitQuery.Where(C => C.MyTableKey == MyTableKey);
        if (!string.IsNullOrEmpty(Name)) limitQuery = limitQuery.Where(C => C.Name == Name);
        if (!string.IsNullOrEmpty(Description)) limitQuery = limitQuery.Where(C => C.Description == Description);
        if (Active) limitQuery = limitQuery.Where(C => C.Active == true);
        if (CreatedBy > 0) limitQuery = limitQuery.Where(C => C.CreatedBy == CreatedBy);
        if (ModifiedBy > 0) limitQuery = limitQuery.Where(C => C.ModifiedBy == ModifiedBy);
        if (CreatedDate > DateTime.MinValue) limitQuery = limitQuery.Where(C => C.CreatedDate == CreatedDate);
        if (ModifiedDate > DateTime.MinValue) limitQuery = limitQuery.Where(C => C.ModifiedDate == ModifiedDate);

        return limitQuery;
    }

    #endregion


}
公共类DAContext:DbContext
{
公共DAContext(数据库连接、数据库事务传输)
:底座(连接,错误)
{
this.Database.useTransation(trans);
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
//停止对表名称的对象名称进行多元化。
modelBuilder.Conventions.Remove();
//将任何以“Key”结尾的属性设置为键类型。
modelBuilder.Properties().Where(prop=>prop.Name.ToLower().EndsWith(“key”)).Configure(config=>config.IsKey());
}
公共DbSet MyTable{get;set;}
}
公共类MyTable:DataAccessBase
{
#区域属性
公共int MyTableKey{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共bool活动{get;set;}
public int CreatedBy{get;set;}
公共日期时间CreatedDate{get;set;}
公共int被{get;set;}修改
公共日期时间修改日期{get;set;}
#端区
#区域构造函数
公共MyTable()
{
//设置默认值。
主动=真;
Name=string.Empty;
CreatedDate=DateTime.MinValue;
ModifiedDate=DateTime.MinValue;
}
#端区
#区域方法
public override void DataSelect(System.Data.SqlClient.SqlConnection连接,System.Data.SqlClient.SqlTransaction)
{
使用(DAContext ctxt=新的DAContext(连接、事务))
{
var limitquery=来自ctxt.MyTable中的C
选择C;
//TODO:对查询进行排序
limitquery=FilterQuery(limitquery);
var limit=limitquery.FirstOrDefault();
如果(限制!=null)
{
this.Name=limit.Name;
this.Description=limit.Description;
this.Active=limit.Active;
this.CreatedBy=limit.CreatedBy;
this.CreatedDate=limit.CreatedDate;
this.ModifiedBy=limit.ModifiedBy;
this.ModifiedDate=limit.ModifiedDate;
}
其他的
{
抛出新的ObjectNotFoundException(string.Format(“不存在具有指定键({0})的MyTable,this.MyTableKey));
}
}
}
专用IQueryable筛选器查询(IQueryable limitQuery)
{
如果(MyTableKey>0)limitQuery=limitQuery.Where(C=>C.MyTableKey==MyTableKey);
如果(!string.IsNullOrEmpty(Name))limitQuery=limitQuery.Where(C=>C.Name==Name);
如果(!string.IsNullOrEmpty(Description))limitQuery=limitQuery.Where(C=>C.Description==Description);
if(Active)limitQuery=limitQuery.Where(C=>C.Active==true);
如果(CreatedBy>0)limitQuery=limitQuery.Where(C=>C.CreatedBy==CreatedBy);
如果(ModifiedBy>0)limitQuery=limitQuery.Where(C=>C.ModifiedBy==ModifiedBy);
如果(CreatedDate>DateTime.MinValue)limitQuery=limitQuery.Where(C=>C.CreatedDate==CreatedDate);
如果(ModifiedDate>DateTime.MinValue)limitQuery=limitQuery.Where(C=>C.ModifiedDate==ModifiedDate);
返回查询;
}
#端区
}

当跟踪打开时,选择速度较慢。你绝对应该关闭跟踪并重新测量

看看我的基准


这可能只是一种预感,但是。。。在存储过程中,过滤器定义良好,SP处于编译状态,执行计划合理。您的EF查询将从头构建,并在每次使用时重新编译。因此,现在的任务是设计一种方法,在不同的使用之间编译和保存EF查询。一种方法是重写FilterQuery,使其不依赖于fluent条件方法链。不要在每次参数集更改时附加或不附加新条件,而是将其转换为一个条件,当满足条件时应用过滤器,否则将被1.Equals(1)之类的内容覆盖。这样,您的查询就可以被遵从,并可供重复使用。支持的SQL看起来很时髦,但执行时间应该会提高。或者,您可以设计面向方面的编程方法,其中编译的查询将根据参数值重新使用。如果我有时间,我会在Code Project上发布一个示例。

谢谢您的回复。我尝试将
.AsNoTracking()
添加到ctxt.CoverageLimit中的C中的
var limitquery=中,虽然我确实看到性能下降到46秒(POCO)而不是7秒(存储过程),但这并不是很显著。不幸的是,除非我能使时间接近可比性,否则我无法接受这一变化。我一直使用SqlConnection/SqlCommand/SqlDataReader专门实现高性能,我更喜欢编写自己的TSQL查询,而不是使用LINQ。我发现我可以简化代码而不牺牲