如何使用ADO.NET和存储过程在数据库中保存复杂的C#对象?

时间:2014-12-25 02:51:05

标签: c# sql sql-server stored-procedures ado.net

我有一个复杂的C#对象,需要在数据库中的多个表(大约12个)中保存:

class Foo
{
    public Guid FooId { get; set; }
    public Bar[] Bars { get; set; }
}

class Bar
{
    public Guid BarId { get; set; }
    public Guid FooId { get; set; }
    public Baz[] Bazs { get; set; }
}

class Baz
{
    public Guid BazId { get; set; }
    public Guid BarId { get; set; }
    // And so on ...
}

问题:

  1. 将此复杂对象(Foo的实例)作为输入发送到存储过程的最佳方法是什么?
  2. 在存储过程中,如何将相应的FooBarBaz表与其父ID相关联(例如Bar需要其父FooId })?

2 个答案:

答案 0 :(得分:3)

以下是您可能想要考虑建模的大致轮廓。这不是一个完整的骨架(因为你可能想要稍微使用范围),但应该给出一个大致的想法。我在几个项目中使用了类似的模型。

如果这些类都遵循相同类型的数据模型,则可以对这些类进行抽象。

class Foo
{
    public Guid FooId { get; private set; } // Only allow the object to define its Id.
    public List<Bar> Bars { get; set; } // Use a dynamic storage object.
    private bool Deleted { get; set; } // Monitors if the object has been deleted in the DB.

    public Foo()
    {
        this.FooId = Guid.Empty;
        this.Deleted = false;
        Bars = new List<Bar>();
    }

    public Foo(Guid fooId)
    {
        this.Deleted = false;

        this.FooId = fooId;
        LoadFromDatabase();

        Bars = new List<Bar>();
        LoadBarsFromDatabase();
    }

    private void LoadFromDatabase()
    {
        // Read from DB, set local variables...
    }

    private void LoadBarsFromDatabase()
    {
        // Psuedocode to load all Bars.
        foreach (var barData in barIdsLinkedToFooTable.Rows)
        {
            Bars.Add(new Bar(this, barData["barId"]));
        }
    }

    public void SaveToDatabase()
    {
        // If FooId is Guid.Empty, the record is new.
        // You may also want to consider the Deleted property value.
        // Either generate the new Guid first or let SQL do it for you in your SP.

        // Save Foo to DB with stored proc.

        // Save Bars.
        foreach (var bar in Bars)
        {
            bar.SaveToDatabase();
        }
    }

    public void Delete()
    {
        // Delete via a stored proc.
        // Might be a good idea to set SQL to cascade the delete,
        //  this way all the children will be deleted automatically.

        this.Deleted = true;
    }
}

class Bar
{
    public Guid BarId { get; private set; } // Only allow the local object to generate Id.
    public Foo ParentFoo { get; set; } // Store a reference to the parent.
    public List<Baz> Bazs { get; set; } // Use a dynamic storage object.
    private bool Deleted { get; set; } // Monitors if the object has been deleted in the DB.

    public Bar(Foo parentFoo)
    {
        // New Bar object.
        this.BarId = Guid.Empty;
        this.ParentFoo = parentFoo;
        this.Bazs = new List<Baz>();
        this.Deleted = false;
    }

    public Bar(Foo parentFoo, Guid barId)
    {
        // Create from existing object.
        this.Deleted = false;

        this.BarId = barId;
        this.ParentFoo = parentFoo;
        LoadFromDatabase();

        Bazs = new List<Baz>();
        LoadBazsFromDatabase();
    }

    /* DB methods for load, save, and delete similar to above. */
}

答案 1 :(得分:1)

理论上,您应该将复杂对象序列化为XML并将其作为参数传递给存储过程。

在存储过程代码中,您可以查询此XML。 TSQL Parse XML in Stored Procedure

结果你可以达到很高的性能,但这种方式可能变得难以维护,因为存储过程必须知道如何处理复杂的对象。