我正在尝试使用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但未真正了解如何使用它的信息。不确定这是否是我问题的正确方向。
答案 0 :(得分:2)
如果您正在寻找使用DataSet的答案,那就不是了。相反,我想提供一个替代建议:如果可能,请不要使用DataSet。
(这当然是一个偏好的问题,但这是我的建议的原因:DataSet,特别是当他们是无类型的时候,有缺点是非常通用 - 他们没有什么样的固有知识对象存储在它们内部。将它与你的“逻辑对象”进行对比,这些对象具有它们的概念以及它们可能具有的功能。后来,当你需要维护代码时,这些对象将更容易理解而不是一个不透明的DataSet!除此之外,你似乎已经确定了你的域对象,并且似乎首先遇到了DataSet的困难。)
我没有为您的场景使用DataSet
,而是为这些逻辑对象(Car
,Door
和Hinge
编写一些数据提供程序类,每个类都得到相应的数据提供者类:ICarProvider
,IDoorProvider
,IHingeProvider
)并在您使用数据加载表单时从中收集所需的数据。
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。:你甚至可以更进一步。对于表单,定义代表一个门或一个铰链的各种用户控件。他们可以直接从Door
或Hinge
类获取数据。然后,创建一个用户控件,可以分别从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配合得很好。