DataSet с несколькими уровнями связанных таблиц - PullRequest
2 голосов
/ 09 января 2011

Я пытаюсь использовать DataSet и DataAdapter для «фильтрации» и «навигации» по DataRows в DataTables.

СИТУАЦИЯ: У меня есть несколько логических объектов, например Автомобиль, дверь и петли. Я загружаю форму, которая отображает полную информацию об автомобиле, включая каждую дверь и соответствующие петли. В этом сенарио форма должна отображать информацию для 1 автомобиля, 4 дверей и 2 петли для каждой двери.

Можно ли использовать ОДИНОЧНЫЙ набор данных для навигации по этим данным? т.е. 1 DataRow в car_table, 4 DataRow в door_table и 8 DataRow в hinge_table, и при этом вы все еще сможете правильно перемещаться между различным объектом и их отношениями? И, легко в DataAdapter.Update ()?

Я читал о DataRelation, но не очень понимаю, как его использовать. Не уверен, что это правильное направление для моей проблемы.

Ответы [ 3 ]

2 голосов
/ 09 января 2011

Если вы ищете ответ на вопрос об использовании DataSets, это не так.Вместо этого я хотел бы предложить альтернативное предложение: если возможно, не используйте DataSets.

(Это, конечно, вопрос предпочтения, но вот причина моего предложения:Недостатками данных, особенно когда они нетипизированного типа, является то, что они очень универсальны - они не обладают внутренним знанием того, какие объекты хранятся внутри них. Сравните это с вашими «логическими объектами», которые имеют представление о том, что ониЕсть, и какие возможности они могут иметь. Позже, когда вам нужно будет поддерживать ваш код, такие объекты будет гораздо проще для понимания, чем непрозрачный 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.


PS : Мой ответ содержит довольно много предположений о вашей объектной модели и отношениях между вашими объектами.Не стесняйтесь адаптировать мой ответ к объектной модели, которую вы на самом деле получили.

PPS : Вы могли бы даже пойти еще дальше.Для вашей формы определите различные пользовательские элементы управления, которые представляют одну дверь или одну петлю.Они могут получить свои данные непосредственно из Door или Hinge класса.Затем создайте пользовательский элемент управления, который может инициализировать себя из ICollection<Door> (или ICollection<Hinge>, соответственно), и который создает правильное количество дочерних элементов управления Door / Hinge внутри себя.Таким образом, вы сможете использовать привязку данных для загрузки данных формы непосредственно из Car объекта.


Ответ на первые два комментария от Джейка:

Нет,Я имел в виду что-то другое.Я сказал, что вы можете добиться большего успеха, чем использование DataSets.Я лично стремился бы к решению, которое вообще не использует DataSets.Я имел в виду что-то вроде этого:

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;), а не к DataSets.

1 голос
/ 09 января 2011

Просто добавьте несколько свойств к объекту 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, просто добавьте сеттеры к этим свойствам с логикой развязки, обратной конкатенации, выполненной в геттерах.

Если вы хотите обновить данные в базе данных после изменения объектов, есть несколько способов сделать это, но использование DataTables ограничивает ваши возможности и заставляет внедрять код вручную.

Вы можете отслеживать изменения объектов, реализуя интерфейс INotifyPropertyChanged и устанавливая некоторые логические свойства, хранящие информацию, если объект был изменен, вы также можете сохранить копию исходного объекта и сравнить его свойства - все это приводит к выводу, что вы, вероятно, в конечном итоге будете реализовывать ваш собственный ORM .

Таким образом, для вас было бы лучше, когда часть презентации требует обновления базы данных для использования существующего решения ORM для чтения-записи данных, LINQ2SQL имеет короткую кривую обучения.

0 голосов
/ 09 января 2011

Вы можете сделать это с одним набором данных, но это зависит от того, храните ли вы сложные объекты / типы 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...