2010-10-20 2 views
3

Мы создали внутренний инструмент, который генерирует весь доступ к данным, каждая таблица имеет класс, представляющий его данные и все общие операции. (Подумайте об облегченной структуре Entity).Вопрос о интерфейсах C# и, возможно, generics

Эти объекты DataAccess всегда имеют конструктор, который получает строку подключения, и функцию загрузки, которая получает SqlDataReader.

Что-то вроде этого:

class Customer 
{ 
    public string ConnStr; 
    public int Id; 
    public string Name; 

    Public customers(string connStr) 
    { 
     ConnStr = connStr; 
    } 

    public Customer Load(SqlDataReader) 
    { 
     if(reader.Read()) 
     { 
      Id = reader["Id"].ToString(); 
      Name = reader["Name"].ToString(); 
     } 
    } 
} 

Я хочу написать статический метод доступа утилита Data, которая позволит мне написать мой SQL и получить список объектов, в свою очередь, после этого предыдущего примера объекта:

Я как-то не могу понять, как с этим бороться, я пробовал интерфейсы, но они не позволяют конструкторам или статическим методам, и с помощью generics - я не могу вызвать методы, которые мне нужно для инициализации объекта (конструктор + загрузка), вот моя последняя попытка, прокомментировал секту п, что не работает:


public static List<T> GetList<T>(string connStr, string SQL, params SqlParameter[] prms) 
     { 
      List<T> list = new List<T>(); 

      using (SqlConnection conn = new SqlConnection(connStr)) 
      { 
       conn.Open(); 

       SqlCommand cmd = new SqlCommand(SQL, conn); 
       foreach (SqlParameter param in prms) 
       { 
        cmd.Parameters.Add(param); 
       } 

       using (SqlDataReader reader = cmd.ExecuteReader()) 
       { 

        //T item = new T(connStr); 
        //item.Load(reader); 
        //list.Add(item); 
       } 
      } 

      return list; 
     } 

Btw, мы заинтересованы в открытом поиске нашего генератора DATAACCESS, это удивительно - это позволяет очень юбилеям, доступ к объектам БД + создает яваскрипт слой доступа к данным что дает вам ПОЛНЫЙ КОНТРОЛЬ вашей БД из javascript (конечно, это имеет последствия для безопасности, которые можно управлять).

Если кто-нибудь здесь знает, как «с открытым исходным кодом» проекта, как это или любой компании, которая хочет присоединиться к разработке этого продукта - пожалуйста, не стесняйтесь связаться со мной: [email protected]

Спасибо продвижение, Эйтан

+0

OT, но с точки зрения пуриста, эти доменные объекты знают ** много ** о постоянстве, что не обязательно является их ответственностью. Я также думаю, что DataContext мог бы сделать большую часть этой привязки для вас без какого-либо кода доступа к данным в сущности бесплатно ['ExecuteQuery '] (http://msdn.microsoft.com/en-us/library/ bb361109.aspx) –

+0

Лассе поднимает интересный момент о том, кто называет Read; во многих отношениях было бы предпочтительнее принимать «IDataRecord», а не «IDataReader' /' SqlDataReader »- при условии, что им нужна только одна строка. –

ответ

3

Load достаточно просто - вы могли бы:

interface IDataEntity { 
    void Load(SqlDataReader reader); 
} 

затем:

public static List<T> GetList<T>(string connStr, string SQL, 
     params SqlParameter[] prms) where T : IDataEntity, new() 
{ 
    .... 
    T item = new T(); 
    item.Load(reader); 
    list.Add(item); 
} 

new T(connStr) сложнее - это действительно необходимо это значение? Общественная собственность была бы проще:

interface IDataEntity { 
    void Load(SqlDataReader reader); 
    string ConnectionString {get;set;} 
} 
class Customer : IDataEntity 
{ ... } 

и т.д. Существует не встроенная (язык) поддержки параметризованных родовых конструкторов. Вы можете взломать его, но во многих случаях параметризованные формы Activator.CreateInstance достаточно быстры (по сравнению с доступом к данным по сети, отражение незначительно). Если вам нужна параметризованная версия, это можно сделать с помощью Expression и т. Д. (Дайте мне знать, если вы хотите пример).

+0

Привет, Марк, спасибо большое, единственная коррекция заключается в том, что ограничение new() должно появиться после IDataEntity. –

+0

@ Эйтан - спасибо; код блокнота; p –

2

Почему не проходит Возведения к способу:

T item = new T(); 
item.SetConn(connStr); 

И не забывайте:

public static List<T> GetList<T>(string connStr, string SQL, params SqlParameter[] prms) 
    where T : new 
{ 
1

Это не будет работать, как вы хотите. SQL-классы для .net не сильно типизированы.Невозможно сказать из запроса, как SELECT * FROM Customers... объект какого класса должен быть построен. Это возможно, если все ваши существа происходят из одного класса, объявляющего:

public virtual Entity Load(SqlDataReader reader) 

и ваш общий метод имеет ограничение:

public static List<T> GetList<T>(string connStr, string SQL, params SqlParameter[] prms) 
    where T : Entity, new() 

, то вы можете сделать:

T entity = new T(); 
entity.Load(reader); 
2

Вам нужно перейдите к размышлению, если вы не хотите изменить, как ваши классы работают на пути конструкторов.

Вы можете сделать это:

while (reader.Read()) 
{ 
    T item = Activator.CreateInstance(typeof(T), new object[] { connStr }) as T; 
    item.Load(reader); 
    list.Add(item); 
} 

(обратите внимание здесь, я сделал это ответственность выше петли для вызова .read на читателя)

Обратите внимание, что если вы не подвергать метод нагрузки через интерфейс, вам нужно называть это и отражением.

Я хотел бы сделать это:

public interface IDataObject 
{ 
    void Load(IDataReader reader); 
} 

А затем реализовать это для Клиента:

public class Customer : IDataObject 
{ 
    ... 

И затем добавить ограничение на ваш метод GetList:

public List<T> GetList<T>(string connStr, string sql, params SqlParameter[] parameters) 
    where T : IDataObject 
+0

Хорошее место на 'Read'; На самом деле, интересно, будет ли еще лучше IDataRecord. –

+0

Возможно, лучше с IDataRecord, согласился. –

Смежные вопросы