具有多个级别的相关表的DataSet

时间:2011-01-09 09:00:08

标签: c# .net winforms dataset

我正在尝试使用DataSet和DataAdapter在DataTables中“过滤”和“导航”DataRows。

情况: 我有多个逻辑对象,例如汽车,门和铰链。 我正在加载一个表格,该表格将显示完整的车辆信息,包括每个车门及其各自的铰链。在这个表格中,表格应显示每扇车的1个车厢,4个车门和2个铰链的信息。

是否可以使用SINGLE DataSet来导航此数据?即car_table中的1个DataRow,door_table中的4个DataRow和hinge_table中的8个DataRow,并且仍然能够在不同对象及其关系之间正确导航? AND,能够轻松地使用DataAdapter.Update()吗?

我已阅读有关DataRelation但未真正了解如何使用它的信息。不确定这是否是我问题的正确方向。

3 个答案:

答案 0 :(得分:2)

如果您正在寻找使用DataSet的答案,那就不是了。相反,我想提供一个替代建议:如果可能,请不要使用DataSet。

  
    

(这当然是一个偏好的问题,但这是我的建议的原因:DataSet,特别是当他们是无类型的时候,有缺点是非常通用 - 他们没有什么样的固有知识对象存储在它们内部。将它与你的“逻辑对象”进行对比,这些对象具有它们的概念以及它们可能具有的功能。后来,当你需要维护代码时,这些对象将更容易理解而不是一个不透明的DataSet!除此之外,你似乎已经确定了你的域对象,并且似乎首先遇到了DataSet的困难。)

  

我没有为您的场景使用DataSet,而是为这些逻辑对象(CarDoorHinge编写一些数据提供程序类,每个类都得到相应的数据提供者类:ICarProviderIDoorProviderIHingeProvider)并在您使用数据加载表单时从中收集所需的数据。

var carId = ...;
Car car = carProvider.GetCarById(carId);

然后您将门数据的加载委托给Car类(因为门“属于”汽车)。使该类具有集合属性Doors(例如,类型为ICollection<Door>)。在Car课程中,您可以按如下方式加载门数据:

public ICollection<Door> Doors { get; private set; }

private readonly IDoorProvider doorProvider = ...;

...
this.Doors = doorProvider.GetDoorsOfCar(this);

同样,委托将铰链数据加载到Door类,因为铰链似乎在逻辑上“属于”门。然后,Door类将具有Hinges属性(再次,例如类型为ICollection<Hinge>)。同样,您的Door类可能会加载铰链数据,如下所示:

public ICollection<Hinge> Hinges { get; private set; }

private readonly IHingeProvider hingeProvider = ...;

...
this.Hinges = hingeProvider.GetHingesOfDoor(this);

当您加载表单时,只需将控件的值设置为car对象的相应属性。


P.S。:我的回答对您的对象模型和对象之间的关系做了很多假设。随意调整我对你实际拥有的对象模型的答案。

P.P.S。:你甚至可以更进一步。对于表单,定义代表一个门或一个铰链的各种用户控件。他们可以直接从DoorHinge类获取数据。然后,创建一个用户控件,可以分别从ICollection<Door>(或ICollection<Hinge>)初始化自己,并在其中创建正确数量的Door / Hinge子控件本身。这样,您应该能够使用数据绑定直接从Car对象加载表单数据。


回复杰克的前两条评论:

不,我的意思不一样。我所说的是你可以做得比使用DataSet更好。我个人会努力寻求一种根本不使用DataSet的解决方案。我有这样的想法:

interface ICarProvider
{
    Car GetCarById(int id);
    ICollection<Car> GetAllCars();
}

public CarProvider : ICarProvider { ... }
// ^ implementation that loads Car objects, e.g. from a relational database

public class Car
{
    public int Id { get; private set; }
    public ICollection<Door> Doors { get; private set; }

    public Car(int id, IDoorProvider doorProvider)
    {
        this.Id = id;
        this.Doors = doorProvider.GetDoorsOfCar(this);
    }
    ...
}

public interface IDoorProvider
{
    ICollection<Door> GetDoorsOfCar(Car car);
    ...
}

public class DoorProvider : IDoorProvider { ... }
// ^ similar to CarProvider, but loads data for Doors instead.

public class Door
{
    public int Id { get; private set; }
    public ICollection<Hinge> Hinges { get; private set; }

    public Door(int id, IHingeProvider hingeProvider)
    {
        this.Id = id;
        this.Hinges = hingeProvider.GetHingesOfDoor(this);
    }
    ...
}

...

然后,您可以直接(通过someControlDisplayingCarData.DataSource = someCar;)对这些对象进行数据绑定,而不是针对DataSet。

答案 1 :(得分:1)

只需在Car对象中添加一些属性,这样您就可以按照自己喜欢的方式显示汽车信息。

partial class Car
{
  public string Doors
  {
     get
     {
        var sb = new StringBuilder();
        foreach(var door in this.Doors)
        {
           sb.Append(door.Name);
        }
     }
     return sb.ToString();
  }

  public string Hinges
  {
     get
     {
        var sb = new StringBuilder();
        foreach(var door in this.Doors)
        {
           foreach(var hinge in door.Hinges)
           {
             sb.Append(hinge.Name);
           }
        }
        return sb.ToString();
     }
   }
}

编辑:如果您希望能够通过Car对象修改门,只需将setter添加到这些属性中,而解耦逻辑与getter中的连接相反。

如果您希望在更改对象后将数据更新到数据库,有几种方法可以实现,但DataTables的使用限制了您手动实现代码的可能性和力量。

您可以通过实现INotifyPropertyChanged接口来跟踪对象的更改,并设置一些布尔属性存储信息(如果对象被修改),您还可以存储原始对象的副本并比较它的属性 - 所有这些都可以得出结论,您可能最终会实现你自己的ORM

因此,当演示文稿部分需要更新数据库以使用现有的ORM解决方案来实现读写数据时,基本上会更好。LINQ2SQL的学习曲线很短。

答案 2 :(得分:0)

您可以使用单个数据集执行此操作,但这取决于您是在数据库中存储复杂对象/ UD类型还是简单相关元组。以下是后者的一个例子:

           Car
           id
           door1id FK references Door
           door2id ditto
           door3id ditto
           door4id ditto


           Door
           id
           position (e.g. drivers side front, driver's side rear, passenger-front, passenger-rear
           hinge1id FK references Hinges
           hinge2id ditto


           Hinges
           id
           hingetypeid FK references HingeType


           HingeType
           id
           hingetype

使用ADO.NET,您可以创建数据集并在客户端断开连接的数据集中定义关系。

另一种方法是定义(嵌套)类型并将类型传递给后端。制造的组件与OODBMS配合得很好。