【问题标题】:business service calls multiple methods on the Data Access Layer each opening a connection业务服务调用数据访问层上的多个方法,每个方法都打开一个连接
【发布时间】:2012-10-23 01:45:40
【问题描述】:

我正在调用 UnitDataProvider 类的 2 个方法的 unitservice 中执行此伪代码。

var units = dataProvider.GetChildrenUnits(parentId);
unit.HierarchyIndex = units.Where( u => u.TemplateId == unit.TemplateId && u.ParentId == null).Max( u => u.HierarchyIndex) + 1;
dataProvider.AddSiblingUnit(unit);

每个方法都会打开一个连接。

如何将其重构为仅使用 1 个连接或重用打开的连接?

或者您认为每个 dataprovider 方法调用的连接正常吗?

解决方案:数据库上的所有数据访问逻辑都是在 DAL 而不是 BLL 内完成的,因为我认为以下对于我的业务来说没有业务逻辑,它只是数据库逻辑。

public void AddSiblingUnit(Unit unit) 
        {
            if (unit.ParentId == null)
            {
                throw new OnlyOneRootNodeIsAllowedException("Only one Root node is allowed!", null);
            } // Server side check if the root is selected because 2 root units are not allowed

            lock (_lockObject)
            {
                using (var trans = new TransactionScope())
                using (var con = new SqlConnection(_connectionString))
                using (var cmd = new SqlCommand())
                {
                    cmd.Connection = con;
                    con.Open();

                    // SELECT HierarchyIndex for the new inserted sibling
                    string selectCommandText = "SELECT HierarchyIndex FROM UNIT WHERE UnitId = @UnitId"; // UnitId of the selected sibling
                    cmd.CommandText = selectCommandText;
                    cmd.Parameters.AddWithValue("UnitId", unit.UnitId); // the parentId which is the selected UnitId 
                    int hierarchyIndexOfSelectedSibling = Convert.ToInt32(cmd.ExecuteScalar());
                    int hierarchyIndexOfNewSibling = hierarchyIndexOfSelectedSibling + 1;

                    // UPDATE all sibling units whose HierarchyIndex is greater than the HierarchyIndex of the selected sibling
                    string updateCommandText = "UPDATE UNIT SET HierarchyIndex = HierarchyIndex + 1 WHERE HierarchyIndex >= @HierarchyIndex AND ParentId = @ParentId";
                    cmd.CommandText = updateCommandText;
                    cmd.Parameters.AddWithValue("HierarchyIndex", hierarchyIndexOfNewSibling);
                    cmd.Parameters.AddWithValue("ParentId", unit.ParentId);
                    cmd.ExecuteNonQuery();

                    // INSERT new sibling
                    string insertCommandText = "INSERT INTO UNIT (Name,TemplateId,CreatedAt,HierarchyIndex,ParentId) VALUES (@Name,@TemplateId,@CreatedAt,@HierarchyIndex,@ParentId);Select Scope_Identity();";
                    cmd.CommandText = insertCommandText;
                    cmd.Parameters.AddWithValue("Name", unit.Name);
                    cmd.Parameters.AddWithValue("TemplateId", unit.TemplateId);
                    cmd.Parameters.Add("CreatedAt", SqlDbType.DateTime2).Value = unit.CreatedAt;
                    unit.UnitId = Convert.ToInt32(cmd.ExecuteScalar());

                    trans.Complete();
                } 
            }
        }

【问题讨论】:

    标签: c# database-connection data-access-layer business-logic-layer


    【解决方案1】:

    您可以在 dataProvider 类中使用连接池。

    这将允许您重用连接,但如果您打算让您的应用程序成为多线程的,那么您遇到这种方法的问题。除非你确保你的连接池有一个线程安全的实现,这说起来容易做起来难。

    【讨论】:

    • ok 上面的方法不完整。现在该方法有 3 个数据提供者调用。 GetXX、UpdateSiblings 和 AddSibling。您如何看待在 UnitService 中使用跨所有 3 个数据提供程序方法的 TransactionScope。然后每个 dataprovider 方法也必须传递一个连接对象。你怎么看?
    • 这可能行得通,但我很好奇你将如何抽象它以使其从外部不可见。另外,应用程序是基于 Web 还是基于桌面?
    • 它是一个 asp.net mvc web 应用程序。 “......所以从外面看不到......”是什么意思? unitService.AddSibling(Unit unit) 现在正在调用 3 个 dataprovider 方法,每个方法还传递一个连接对象。事务在服务中启动和完成。您究竟在哪里看到问题?能否请您换个说法?
    • 那为什么不为每个请求使用一个连接呢?
    • 这正是我之前所说的。 TransactionScope 跨越 3 个方法,每个方法都接受一个打开的连接对象。这是你的担心吗?
    猜你喜欢
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多