EF的高性能插入和重复控制

时间:2015-06-29 22:58:30

标签: c# asp.net sql-server entity-framework

我知道SQL的基础知识,因此我学会了创建插入查询,如下所示:

queryAccount.AppendLine(
    string.Format(
        "Insert INTO Account(Number_Account, DoID, ClientID) Select "
            + "{0}, "
            + "(Select id From AccountDO Where Number_do = {1}), "
            + "(Select id From Client Where Number_Client = {2})"
            + "Where not exists(Select * From Account Where Number_Account = {0});",
        item.Client.NumberAccount,
        item.Client.NumberDo,
        item.Client.NumberClient));

在该查询中,我将数据添加到具有两个FK(DoIDClientID)的“帐户”表中,并且还检查该帐户是否已存在。通常,要从平面文件插入数据,我使用String Builder来创建多个插入查询。

这在一些低要求的项目中运作良好,但现在我手中有更大的挑战。我需要创建一个每天导入新数据的网站,因此让“导入模块”遵循最佳实践非常重要。

到目前为止我做了什么:

  • 我的数据库模型:大约20个表,包含各种关系(包括多对多);
  • 使用实体模型代码生成器在APS .Net项目中生成相应的模型。

我需要做什么:

  • 执行批量数据插入,我这样做的方式很慢,可能不安全;
  • 插入该数据,避免重复,并使用适当的外部表ID;

这就是为什么我需要你的帮助,我怎样才能最好地利用现有的技术来实现我的目标?是否可以使用实体框架(EF)以便轻松地将帐户列表添加到DataSet中?。

2 个答案:

答案 0 :(得分:4)

您的要求:

  1. 快速安全地执行批量数据插入。
  2. 插入数据,避免重复使用正确的外来表ID。
  3. 充分利用现有技术。
  4. 使用实体框架(EF)轻松地将帐户列表添加到DataSet中?
  5. 如果使用EF从C#代码插入数据,可以考虑使用参数化的sql查询,使插入更安全,不受SQL注入攻击。

    使用Data.SqlClient.SqlCommand.Parameters.Add

    MSDN:SqlCommand.Parameters Property

    public void InsertCustomer(Integer customerID, DateTime activityDate) {
        String sql = "INSERT INTO Customers (customerID, ActivityDate) VALUES (@customerID, @activityDate);";
        Data.SqlClient.SqlCommand cmd = new Data.SqlClient.SqlCommand(sql);
        cmd.CommandType = CommandType.Text;
        cmd.Parameters.Add("@customerID ", Data.SqlDbType.Int).Value = customerID;
        cmd.Parameters.Add("@activityDate ", Data.SqlDbType.DateTime).Value = activityDate;
        try {
            using (SqlConnection connection = new Data.SqlClient.SqlConnection(YourConnectionString)) {
                connection.Open();
                cmd.Connection = connection;
                cmd.ExecuteNonQuery();
            }
        } catch (Exception ex) {
            throw ex;
        }
    }
    

    但是,如果使用SSIS或T-SQL BULK INSERTS,则插入作业应该运行得更快。

    以下是我找到的资源:

    Insert and Update Records with an SSIS ETL Package

    • SQL Server Integration Services(SSIS)
    • 提取变换加载(ETL)

    Bulk Import and Export of Data (SQL Server)

    • (cmd line)bcp utility
    • (T-SQL)BULK INSERT
    • (T-SQL)INSERT ... SELECT * FROM OPENROWSET(BULK ...)

    Optimizing Bulk Import Performance

    • 使用最少的日志记录
    • 从多个客户端并行导入数据到单个表
    • 使用批次
    • 禁用触发器
    • 禁用约束
    • 在数据文件中订购数据
    • 控制锁定行为
    • 以原生格式导入数据

    Prerequisites for Minimal Logging in Bulk Import

    最小日志记录要求目标表满足以下条件:

    • 该表未被复制。
    • 指定表锁定(使用TABLOCK)。
    • 表格不是内存优化表。

    表是否可以进行最小日志记录还取决于表是否已编制索引,如果是,则表是否为空:

    • 如果表没有索引,则最少记录数据页。
    • 如果表没有聚簇索引但具有一个或多个非聚簇索引,则始终最少记录数据页。但是,如何记录索引页取决于表是否为空:
      • 如果表为空,则最少记录索引页。
      • 如果table非空,则会完全记录索引页。
      • 如果表具有聚簇索引且为空,则数据和索引页的记录最少。相反,如果表具有聚簇索引且非空,则无论恢复模型如何,都会完全记录数据页和索引页。

    Bulk Inserts via TSQL in SQL Server

    • BULK INSERT - SQL Server 2005& 2008
    • INSERT ... SELECT * FROM OPENROWSET(BULK ...) - SQL Server 2005& 2008

答案 1 :(得分:3)

假设您已正确映射数据库(代码优先或数据库优先),您应该有一些映射到您的上下文的表。例如:

public class DataModel : DbContext
{
    /* more code ... */

    public virtual DbSet<User> Users { get; set; }

    /* more code ... */
}

DbSet类公开了一种可用于批量插入的AddRange方法。因此,假设您有一组User个对象,您可以这样做:

public class SomeClass
{
    public int InsertUsers(params User[] users)
    {
        using(var context = new DataModel())
        {
            context.Users.AddRange(users);
        }
    }
}

将在一个事务中插入用户(假设基础数据存储区支持事务)。