Могу ли я создать собственный класс, который наследуется от строго типизированного DataRow? - PullRequest
3 голосов
/ 11 мая 2010

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

У меня есть один проект в моем решении, который содержит DataSet.xsd. Этот проект компилируется в отдельную сборку (Data.dll). Схема базы данных включает в себя несколько таблиц, расположенных более или менее иерархически, но единственный способ на самом деле связать таблицы - это объединение. Я могу получить, например DepartmentRow и EmployeeRow объекты из автоматически сгенерированного кода. EmployeeRow содержит информацию от соответствующего сотрудника DepartmentRow через объединение.

Я делаю новый отчет для просмотра нескольких отделов и всех их сотрудников. Если я использую существующую схему доступа к данным, все, что я смогу получить, это вывод в виде электронной таблицы, где каждый сотрудник представлен в одной строке, а информация об отделе повторяется снова и снова в соответствующих столбцах. E.g.:

Department1...Employee1...
Department1...Employee2...
Department2...Employee3...

Но клиент хотел бы, чтобы каждый отдел отображался как заголовок со списком сотрудников под каждым. E.g.:

- Department1...
      Employee1...
      Employee2...
+ Department2...

Я пытаюсь сделать это, унаследовав иерархические объекты от автоматически сгенерированных объектов Row. E.g.:

public class Department : DataSet.DepartmentRow {
    public List<Employee> Employees;
}

Таким образом, я мог бы вкладывать данные в отчет, используя набор объектов Department в качестве источника данных, каждый из которых помещал бы свой список сотрудников в подотчет.

Проблема в том, что это дает мне ошибку The type Data.DataSet.DepartmentRow has no constructors defined. И когда я пытаюсь создать конструктор, например,

public class Department : DataSet.DepartmentRow {
    private Department() { }
    public List<Employee> Employees;
}

В дополнение к первой появляется ошибка 'Data.DataSet.DepartmentRow(System.Data.DataRowBuilder)' is inaccessible due to its protection level..

Есть ли способ выполнить то, что я пытаюсь сделать? Или я должен попробовать что-то еще?

Ответы [ 3 ]

4 голосов
/ 11 мая 2010

Мне удалось унаследовать от строки данных в быстром тесте. Обратите внимание, что он находится в той же сборке, что и класс строк данных. Конструктор класса строк данных помечается как «внутренний».

using System;
using System.Data;

namespace Blah
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class Class1 : MyDataSet.MyTableRow
    {
        public Class1(DataRowBuilder rb) : base(rb)
        {
            //
            // TODO: Add constructor logic here
            //
        }
    }
}
2 голосов
/ 12 мая 2010

Я не уверен, что такое компоновка сборки. Если ваш новый наследующий тип находится за пределами «Data.dll» и вам нужен доступ к внутреннему конструктору ... Если вы все еще можете изменить эту сборку, вы можете попробовать добавить «InternalsVisibleToAttribute» (http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx). Надеюсь это поможет.

1 голос
/ 02 июня 2010

Я, в конце концов, нашел обходной путь, который имеет следующие преимущества:

  1. Мне не нужно добавлять друга в сборку данных; Мне нужно изменить только один файл в той части сборки, где я обычно делаю изменения.
  2. Мне не нужно менять автоматически сгенерированный код, который будет перезаписан, как только он будет сгенерирован

В файле выделенного кода для набора данных (DataSet.cs, доступ к которому произошел в VS2008 путем расширения DataSet.xsd), я добавил новое частичное определение класса, которое добавляет открытый конструктор с другой сигнатурой, но функционально идентичный существующий внутренний конструктор:

public partial class DataSet {
    public partial class DepartmentRow {
        public DepartmentRow(global::System.Data.DataRowBuilder rb, string discard) : this(rb) { }
    }
    public partial class EmployeeRow {
        public EmployeeRow(global::System.Data.DataRowBuilder rb, string discard) : this(rb) { }
    }
}

Затем я могу использовать этот конструктор в своем производном классе:

public class Department : DataSet.DepartmentRow {
    public Department(global::System.Data.DataRowBuilder DataRowBuilder rb) : base(rb, "discard") { }

    public List<Employee> Employees;

    public string[] SomeFrequentlyUsedGroupOfFields {
        get {
            return new string[] { this.OneField, this.AnotherField };
        }
    }

    public bool CanUserSeeDepartmentInformation(int UserID) { }
}

И вуаля!

К сожалению, после достижения этого результата я понял, что он не очень полезен, потому что автоматически сгенерированный код в DataSetTableAdapters.DepartmentTableAdapter по-прежнему возвращает объекты типа DataSet.DepartmentRow, и мне пришлось бы понизить значение, чтобы получить мой Department объект с дополнительными свойствами / методами. Это недопустимо, и я не вижу простого способа обойти этот факт.

Я мог бы просто переместить всех своих новых членов в частичный код класса, но я не уверен, какие спецификации архитектуры могли бы нарушить. (Кажется, есть какое-то произвольное применение различия между логикой данных и бизнес-логикой.)

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