Зарегистрировано: 402




Помощь  Карта сайта

Текст дня

Поднятие тиц и pr

Для начала немного теории (куда уж без неё…): Индекс Цитирования - численный показатель цитируемости сайта. Определяется Яндексом на основании известных ему сайтов. PageRank это мера "важности" страницы, согласно данным поисковой системы Google. PR зависит от числа внешних ссылок на данную ..
Дальше..

Фото дня

Радуга5.png

Радуга5.png



Тексты. Прозариум

Тексты на сайте могут публиковаться как в составе книг, по которым они "разложены", так и по отдельности. Тексты можно публиковать на странице их владельца, в блогах, клубах или рубриках сайта, а так же в виде статей и объявлений. Вы можете публиковать на сайте не только собственные тексты, но и те, которыми хотите поделиться с читателями, соблюдая авторские права их владельцев.
Prozarium CMS | Реклама, сотрудничество | Разработка, продажа сайтов

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



Опубликовано в: Сайт: Публичные рубрики
Клуб: c#
<--Программирование
<--IT Информационные технологии
<--Бизнес по сферам деятельности
Клуб: Программное обеспечение
<--IT Информационные технологии
<--Бизнес по сферам деятельности
Блог: Создание сайтов с CMS на C# и ASP.Net

0





Практическое использование коллекций в C#
/p. v./
27.12.2014


Вы можете помочь проекту 'C Sharp Collection Manager' развиваться, оказав посильную материальную помощь. Спасибо!

Скачать исходный код

Code:
/*Данные хранятся на SQL сервере и при многократном обращении к ним большого количества одновременно подключенных пользователей, последние создают серьезную нагрузку на сервер БД. Кроме того, часто запросы к БД осуществляют выборку одних и тех же данных, что не есть хорошо с точки зрения нагрузки на приложения и серверы. Одним из способов оптимизации связки БД-Приложение, снижения трафика и нагрузки на сервер, является хранение уже полученных с сервера данных на клиенте, если это клиент-серверное приложение. Или, если это web приложение, хранение полученных данных на сервере приложения, особенно, когда сервера БД и приложения разнесены по сети. Для этой цели как нельзя лучше подходят коллекции, хранимые в сессии или в уровне приложения, если они публичны.Ниже предлагается решение для слоя управления данными в связке mssqlserverс C# приложением, как в win, так и asp.net или WCF. По сути, это маппер, проецирующий сущностибизнес-логики приложения на таблицы БД, с использованием хранимых процедур T-SQL.Весь клиентский код сводится к написанию простейших вызовов методов класса маппера ии к созданию конструкторов сущностей. Библиотека позволяет реализовать в приложении довольно сложные структуры данных, не погружаясь в рутину организации доступа и хранения данных, в большей степени позволяя уделять внимание разработчика бизнес логике и UI.Приложение свободно для загрузки и распространяется на условиях GNU General Public License. Не забудьте поблагодарить разработчика, используя ссылку Donate. Успехов! */using System;using System.Reflection;using System.Data;using System.Data.SqlClient;using System.Configuration;using System.Collections;using System.Collections.Generic;using System.Web;using System.Linq;namespace YourNameSpace{        /*В качестве примера, здесь представлены все необходимые для работы с      коллекциями классы клиентского приложения, использующие библиотеку       CollectionManager. Библиотека универсальна и оперирует с любыми типами коллекций     пользовательских классов, описанных в приложении. Она позволяет загружать с      сервера посредством пользовательских хранимых процедур наборы данных,      формирующих экземпляры класса и формировать из этих экземпляров коллекции.      Кроме того, в библиотеке реализованы механизмы извлечения конкретного      экземпляра класса из коллекции, его модификации и вставки обратно в коллекцию      на то же место (сортировка по ID). Помимо этого в библиотеке присутствуют      методы добавления и удаления экземпляров коллекции.       Something - пример прототипа класса, с экземплярами которого работает импровизированная      коллекция.  Класс описывает структуру таблицы БД. */        public class Something : Sortable    {        // наследование от Sortable нужно, если в коллекции нам потребуется         // сортировка по ID        // доступ к БД        public const string conStrAlias = "Your_DB_Alias";        // поля класса        private int id;        /* При использовании класса прототипа, наследуемого от другого класса,         приватное поле id может называться по-другому. */        /*В таком случае, (речь об этом пойдет ниже)  имеет смысл посмотреть в         рефлекторе список полей и скорректировать вызывающие методы. По этой         же причине ключ SomethingID нельзя объявлять в виде          public string SomethingID { get; set; }, но можно объявлять так: */        public int SomethingID        {        get            {        return id;            }        set            {                id = value;            }        }        //поскольку рефлектор гарарантированно найдет приватное поле "id"        public string SomethingName { get; set; }        public int SecondID { get; set; }        // конструкторы класса. их два. используются разными методами библиотеки         // при соответствующих подходах в реализации сущности.        public Something(SqlDataReader reader, int sortID)        {        //этот конструктор нужен для заполнения всей коллекции одним запросом            FillBody(reader, sortID);        }        public Something(int somethingID)        {        using (SqlConnection connection =        new SqlConnection(ConfigurationManager.ConnectionStrings                    [conStrAlias].ConnectionString))            {        using (SqlCommand command = new SqlCommand("GetSomething",                    connection))                {                    command.CommandType = CommandType.StoredProcedure;                    command.Parameters.Add(new SqlParameter("@SomethingID",                        somethingID));                    connection.Open();        using (SqlDataReader reader = command.ExecuteReader())                    {        while (reader.Read())                        {                            FillBody(reader, -1);                        }                        reader.Close(); reader.Dispose();                    }                    command.Dispose();                }                connection.Close(); connection.Dispose();            }        }        // общий для обоих конструкторов метод заполнения полей класса        private void FillBody(SqlDataReader reader, int sortID)        {        try            {        if (!(reader["SomethingID"] is DBNull))                    SomethingID = (int)reader["SomethingID"];        if (!(reader["SomethingName"] is DBNull))                    SomethingName = (string)reader["SomethingName"];        if (!(reader["SecondID"] is DBNull))                    SecondID = (int)reader["SecondID"];            }        catch            {            }        }    }        /* Вся работа с данными в БД приложения сводится к написанию простейших     хранимых процедур для каждой сущности:         Create PROCEDURE GetSomething        @SomethingID int = null,        @SomeParameter int = null,        @ReturnAtOnce bit = null        AS        if @SomethingID is not null             -- тут достаем конкретный экземпляр класса             SELECT ID as SomethingID, SomethingName, SecondID FROM Somethings              WHERE (ID = @SomethingID)        else            begin                 -- тут достаем все записи коллекции (только ID)                      if @SomeParameter is not null                    SELECT ID as SomethingID FROM Somethings Where                     SecondID = @SomeParameter                 else                    SELECT ID as SomethingID FROM Somethings             end      и к созданию в приложении классов, описывающих коллекции и методы для      операций с ними (хранение,  извлечение, модификация)    ***************************************************************    Somethings* - это класс прототип, предоставляющий методы добавления,     удаления и идентификация элементов коллекции    на базе этого класса строим коллекции:*/        public class SomethingsList : ListRealizator    {        public static SomethingsList GetInstance()        {        return SomeGlobalClass.Somethings;        }    }        // класс ListRealizator предоставляет методы добавления, удаления элемента         // коллекции и индексатор. Коллекции наследуют его, реализуя интерфейс IList        public class ListRealizator : CollectionBase    {        public void Add(object obj)        {        List.Add(obj);        }        public void Remove(object obj)        {        try            {        List.Remove(obj);            }        catch            {            }        }        public object this[int itemIndex]        {        get            {        return (object)List[itemIndex];            }        set            {        List[itemIndex] = value;            }        }    }        // класс Sortable, нужный для сортировки элементов в коллекциях при обновлении         // или при вставке новых элементов        public class Sortable    {        private int sortid;        public int SortID        {        get            {        return sortid;            }        set            {                sortid = value;            }        }    }        // класс EntityComparer, используемый для сортировки коллекций по Id        public class EntityComparer : IComparer    {        public int Compare(object tx1, object tx2)        {        // возвращает        //    -1 x < y        //     0  x = y        //     1  x > y        Sortable x = (Sortable)tx1;        Sortable y = (Sortable)tx2;        if (x == null)            {        if (y == null)        return 0;                else        return -1;            }        else            {        if (y == null)        return 1;        else                {        try                    {        int retval = x.SortID.CompareTo(y.SortID);        if (retval != 0)        return retval;        else        return 0;                    }        catch                    {        return 0;                    }                }            }        }    }        /*Коллекций, использующих прототип Somethings мы можем помтроить сколь     угодно много, при этом базовый класс используется один и тот же. В примерах     ниже использованы 
три разных коллекции. Важно не путать их между собой, во 
избежание появления призраков, т.е. экземпляров одной коллекции в другой.
Например, кг яблок разделен на 2 мешка. В одном мои, в другом твои.
Если положить яблоко не в тот мешок (SomethingsList), кто-то удивится, а кто-то
недосчитается. При этом важно, что в обоих мешках яблоки (Something) и между
собой они ничем не отличаются. И твои, и мои яблоки приобретаются в общем
магазине (в куче). При этом, если мои яблоки могут закончиться, можно сходить
в магазин и взять других (в куче), а можно вырастить новые (создать)

*************************** Somethings1 *****************************

это коллекция, использующая класс прототип Somethings и хранящаяся в сессии*/

public class SomethingsList : ListRealizator
{
public static SomethingsList GetInstance()
{
return SomeGlobalClass.Somethings;
// в данном случае это статическая переменная в сессии пользователя,
// хранящая коллекцию. Для каждого пользователя она будет уникальна.
}
}
//**************************** SomethingsHeap **********************
// это вторая коллекция, также использующая класс прототип Somethings, но
// хранящаяся в уровне приложения. В общем случае, коллекция SomethingsList
// может обнуляться, а элементы при заполнении брать из коллекции SomethingsHeap
// или из БД.
public class SomethingsHeapList : ListRealizator
{
public static SomethingsHeapList GetInstance()
{
// тут выбирается экземпляр того же типа Something, но уже из общей
// кучи. сама куча хранится в уровне приложения.
// описание механизма выборки из кучи см. в CollectionManager
// (метод AddCollectionItem)
return SomeGlobalClass.SomethingsHeap;
}
}
// обе коллекции хранят однотипные экземпляры класса Something (возможно, одни
// и те же), при этом сами коллекции хранятся в разных местах и имеют разный
// жизнеенный цикл.
public class SomeGlobalClass
{
// ****************************** эта коллекция хранится в сессии сайта
// (она индивидуальна для каждого юзера)
public const string conStrAlias = "Your_DB_Alias";
public static SomethingsList Somethings
{
get
{
if (HttpContext.Current.Session["Somethings"] == null)
HttpContext.Current.Session.Add("Somethings",
SomeGlobalClass.GetSomethings(new SomethingsList()));
return HttpContext.Current.Session["Somethings"] as SomethingsList;
}
set
{
if (HttpContext.Current.Session["Somethings"] == null)
HttpContext.Current.Session.Add("Somethings", value);
else HttpContext.Current.Session["Somethings"] = value;
}
}
// еще одна коллекция того же типа, для примера
public static SomethingsList Somethings2 { get; set; }
//**************** эта коллекция хранится в уровне приложения (это может
//быть куча, общая для всех)
private static SomethingsHeapList _SomethingsHeap;
public static SomethingsHeapList SomethingsHeap
{
get
{
if (_SomethingsHeap == null)
_SomethingsHeap = (SomethingsHeapList)
SomeGlobalClass.GetSomethings(new SomethingsHeapList());
return _SomethingsHeap;
}
set
{
_SomethingsHeap = value;
}
}
/*при изменении таблицы БД, на которой строится эта коллекция, потребуется
обновление этой коллекции или ее элементов. если это не реализовано,
то потребуется перезапуск всего приложения, с тем, чтобы элементы коллекции
обновились.*/

//******************* пример метода извлечения элемента (экземпляра класса
// Something) из произвольной коллекции
public static Something GetSomething(int somethingID,
CollectionBase collection)
{
// тут происходит обращение к CollectionManager, откуда возвращается
// экземпляр коллекции с id = somethingID
return (Something)CollectionManager.GetCollectionItem(somethingID,
"id", collection, typeof(Something));
// если элемента в коллекции нет, он добавляется в нее из конструктора
// сущности
}
//******************* извлечение из сессии коллекции Somethings и пример
// построения на ее базе двумерной коллекции Somethings
public static void CopySomethings()
{
foreach (Something something in SomeGlobalClass.Somethings)
{ int somethingID = something.SomethingID; int ID2 = something.SecondID; /* Тут следует пояснить, что в CollectionManager есть переопределенный метод, который использует конструктор с двумя ID. Это нужно в случае, если процедура на сервере собирает записи из разных источников данных. Например, параметр SecondID определяет таблицу, данные из которой объединяются в результирующий запрос. Тогда экземпляр в коллекции ищется сразу по двум id (по сути, это двумерный массив с двумя ключами)*/ Something sms2 = (Something)CollectionManager.GetCollectionItem (somethingID, "id", ID2, "SecondID", SomeGlobalClass.Somethings2, typeof(Something)); } } /******************* первичное заполнение коллекций элементами. Процедура выдергивает список ID, по которым ищутся или создаются экземляры класса Something (в данном случае метод универсален для всех коллекций Somethings, SomethingsHeap, Somethings2), Получив id, CollectionManager смотрит, есть ли в переданной ему коллекции экземпляр сущности с этим id. Если его там нет, вызывается конструктор сущности и элемент добавляется в коллекцию.*/ public static CollectionBase GetSomethings(CollectionBase collection) { //в метод передается коллекция, которую надо заполнить. заполнение коллекции // производится из хранимой процедуры с параметрами Hashtable parameters = new Hashtable(); int SomeParameter = 1; //параметры при обращении к процедуре могут быть необязательны, равно //как параметров можно передавать неограниченное количество любого типа. if (SomeParameter == 1) parameters["@SomeParameter"] = SomeParameter; //тут происходит обращение к CollectionManager, откуда возвращается //коллекция. return CollectionManager.GetCollection("GetSomething", "SomethingID", conStrAlias, collection, typeof(Something), parameters); } public static CollectionBase GetSomethings(int SomeKeyID) { SomeGlobalClass.Somethings = null; Hashtable parameters = new Hashtable(); parameters["@SomeKeyID"] = SomeKeyID; /* обратите вниманеи на последний параметр true в методе GetCollection. его присутствие обязывает передать в конструктор класса готовый reader, а в SQL процедуру передается параметр @ReturnAtOnce, и тогда процедура вернет весь набор записей за один проход со всеми полями сущности. если этот параметр опущен, то по умолчанию процедура вызывается один раз для получения списка ID экземпляров класса, а после, при создании конкретного экземпляра класса вызывается еще раз, уже с параметром SomethingID для получения всех полей экземпляра с заданным ID. */ return (SomethingsList)CollectionManager.GetCollection("GetSomethings", "SomethingID", conStrAlias, new SomethingsList(), typeof(Something), parameters, true); } // или такой вариант, если нам надо вернуть типизированный список public List<Something> GetSomethings() { return GetSomethings().OfType<Something>().ToList(); } /*в случае, если в БД источник данных изменился (например, обновилась таблица), обновляем соответствующий экземпляр коллекции. при этом этот экземпляр класса будет удален из коллекции, создан заново и вставлен туда, где был (сортировка по SomethingID). в методе UpdateCollectionItem если элемента в коллекции нет, он не добавляется(!)*/ public static void OperateCollectionItem(int somethingID, CollectionBase collection) { CollectionManager.UpdateCollectionItem(somethingID, "id", collection, typeof(Something)); /* переопределенный метод использует конструктор с двумя ID (см. выше). В качестве второго ключа передаем поле SecondID класса Something, а в качестве параметра процедуры переменную SecondID. Например: */ int SecondID = 100; CollectionManager.UpdateCollectionItem(somethingID, "id", SecondID, "SecondID", collection, typeof(Something)); // в случае, если нам надо добавить новый экземпляр в одномерную // коллекцию c id = somethingID CollectionManager.AddCollectionItem(collection, typeof(Something), somethingID, somethingID, -1); // переопределенный метод использует конструктор с двумя ID. CollectionManager.AddCollectionItem(collection, typeof(Something), somethingID, SecondID, -1); } } //********* собственно сама библиотека CollectionManager в полном виде public static class CollectionManager { /* метод GetCollection, принимающий имя хранимой процедуры, наименование ключевого поля набора или класса, параметры процедуры, строку подключения к базе, заполняемую(возвращаемую) коллекцию, тип класса-прототипа сущности, имеет несколько переоределений*/ public static CollectionBase GetCollection(string ProcName, string idFieldName, string conStrAlias, CollectionBase collection, Type collElementType, Hashtable parameters, bool FillAtOnce) { // для одного ID и FillAtOnce return GetCollection(ProcName, idFieldName, string.Empty, conStrAlias, collection, collElementType, parameters, FillAtOnce); } public static CollectionBase GetCollection(string ProcName, string idFieldName, string conStrAlias, CollectionBase collection, Type collElementType, Hashtable parameters) { // для одного ID return GetCollection(ProcName, idFieldName, string.Empty, conStrAlias, collection, collElementType, parameters, false); } public static CollectionBase GetCollection(string ProcName, string idFieldName, string idFieldName2, string conStrAlias, CollectionBase collection, Type collElementType, Hashtable parameters) { // для двух ID return GetCollection(ProcName, idFieldName, idFieldName2, conStrAlias, collection, collElementType, parameters, false); } public static CollectionBase GetCollection(string ProcName, string idFieldName1, string idFieldName2, string conStrAlias, CollectionBase collection, Type collElementType, Hashtable parameters, bool FillAtOnce) { // для двух ID и FillAtOnce //задание параметров для процедуры //пример: //Hashtable parameters = new Hashtable(); //parameters["string"] = "строка"; //parameters["int"] = 21; // ********************* !!! Внимание!!! Коллекция автоматически не //очищается. Нужно следить за этим самостоятельно, передавая при //необходимости new() using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings [conStrAlias].ConnectionString)) { using (SqlCommand command = new SqlCommand(ProcName, connection)) { command.CommandType = CommandType.StoredProcedure; foreach (DictionaryEntry de in parameters) { command.Parameters.Add(new SqlParameter(de.Key.ToString(), de.Value)); } if (FillAtOnce) //говорит процедуре вернуть все сразу command.Parameters.Add(new SqlParameter("@ReturnAtOnce", true)); connection.Open(); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { if (idFieldName2 == string.Empty) { if (FillAtOnce) { //метод использует готовый reader для //формирования экземпляра класса. //при этом хранимая процедура возвращает //полный набор полей по всем //строкам(один запрос на коллекцию) //в конструкторе класса процедура уже не //вызывается для создания экземпляров. //данный метод подходит для вытаскивания //сложных запросов с вычисляемыми полями. CollectionManager.AddCollectionItem (collection, collElementType, reader); } else //в данном методе используется отдельный //запрос для создания каждого экземпляра //коллекции. подходит для статических табличных //данных. CollectionManager.GetCollectionItem( (int)reader[idFieldName1], "id", collection, collElementType); } else // для коллекций с 2-мя ключами (двумерный массив). // такие коллекции строятся из разных источников со // схожей структурой. например, когда SQL возвращается // с использованием инструкции Union. // первый параметр передает ID записи, второй - ID // источника записей CollectionManager.GetCollectionItem( (int)reader[idFieldName1], "id", Int32.Parse(reader[idFieldName2].ToString()), "id2", collection, collElementType); } reader.Close(); reader.Dispose(); } command.Dispose(); } connection.Close(); connection.Dispose(); } return collection; } public static void AddCollectionItem(IList collection, Type collElement,
SqlDataReader reader)
{
//тут попадаем на переопределенный конструктор класса, который
//заполняет элемент коллекции данными ридера
object lstItem = Activator.CreateInstance(collElement, reader,
collection.Count);
collection.Add(lstItem);
}
public static object GetCollectionItem(int iD, string idFieldName,
IList collection, Type collElement)
{
// по умолчанию используем коллекции с одним ключом. 2-й передаем как
//заглушку
return GetCollectionItem(iD, idFieldName, -1, string.Empty,
collection, collElement);
}
public static object GetCollectionItem(int iD1, string idFieldName1,
int iD2, string idFieldName2, IList collection, Type collElement)
{
try
{
if (!(iD1 > 0)) return null;
// если элемента в коллекции нет, он добавляется
if (collection.Count > 0)
{
int fld1 = -1;
int fld2 = -1;
Type collElemType = collection[0].GetType();
System.ReflectionFieldInfo[] elemClassFields =
collElemType.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
if (idFieldName2 == string.Empty && iD2 == -1)
{
// одномерный массив
for (int j = 0; j < elemClassFields.Length; j++)
{
if (elemClassFields[j].Name == idFieldName1)
{
fld1 = j;
for (int i = 0; i <= collection.Count - 1; i++)
{
try
{
if ((int)elemClassFields[fld1].GetValue
(collection[i]) == iD1)
return collection[i];
}
catch
{
break;
}
}
break;
}
}
}
else
{
// двумерный массив
for (int j = 0; j < elemClassFields.Length; j++)
{
if (elemClassFields[j].Name == idFieldName1)
// j - индекс имени поля первого ключа
fld1 = j;
}
for (int j = 0; j < elemClassFields.Length; j++)
{
if (elemClassFields[j].Name == idFieldName2)
// j - индекс имени поля второго ключа
fld2 = j;
}
for (int i = 0; i <= collection.Count - 1; i++)
{
try
{
if ((int)elemClassFields[fld1].GetValue
(collection[i]) == iD1
&& (int)elemClassFields[fld2].GetValue
(collection[i]) == iD2)
return collection[i];
}
catch
{
break;
}
}
}
}
return AddCollectionItem(collection, collElement, iD1, iD2);
}
catch
{
}
return null;
}
public static object AddCollectionItem(IList collection, Type collElement,
int iD1, int iD2)
{
return AddCollectionItem(collection, collElement, iD1, iD2,
collection.Count);
}
public static object AddCollectionItem(IList collection, Type collElement,
int iD1, int iD2, int SortID)
{
object lstItem = null;
try
{
//элемент добавляется
if (iD2 == -1)
{
/* возможны случаи, когда коллекция состоит из элементов,
общих для разных коллекций. например, коллекции Collection_A и
Collection_B содержат одни и те же элементы типа Coll_Elements.
при этом Collection_A и Collection_B хранятся в сессии и могут
изменяться и обнуляться при действиях пользователя. коллекция
Coll_Elements содержит прототипы для Collection_A и Collection_B,
которые хранятся в уровне приложения, и не должна обнуляться в
течении жизни приложения. при обнулении списков Collection_A и
Collection_B, мы попадаем на создание нового экземпляра класса
Coll_Elements, т.е. сюда. Нам надо вместо создания нового
экземпляра забрать в Coll_Elements (в куче) уже существующий
экземпляр и подсунуть его в Collection_A или Collection_B. */

switch (collElement.Name) { case "Something": if (collection.GetType().Name != "SomethingsHeapList") //ищем экземпляр в куче lstItem = GetCollectionItem(iD1, "id", SomeGlobalClass.SomethingsHeap, typeof(Something)); break; } if (lstItem == null) { if (collElement.BaseType == typeof(Sortable)) lstItem = Activator.CreateInstance(collElement, iD1, SortID); else lstItem = Activator.CreateInstance(collElement, iD1); } } else { // для двумерного массива. работа с кучей не реализована пока. if (collElement.BaseType == typeof(Sortable)) lstItem = Activator.CreateInstance(collElement, iD1, iD2, SortID); else lstItem = Activator.CreateInstance(collElement, iD1, iD2); } collection.Add(lstItem); } catch { } return lstItem; } public static void UpdateCollectionItem(int iD1, string idFieldName, IList collection, Type collElement) { UpdateCollectionItem(iD1, idFieldName, -1, string.Empty, collection, collElement); } public static void UpdateCollectionItem(int iD1, string idFieldName1, int iD2, string idFieldName2, IList collection, Type collElement) { if (!(iD1 > 0)) return; // если элемента в коллекции нет, он не добавляется if (collection.Count > 0) { int fld1 = -1; int fld2 = -1; Type collElemType = collection[0].GetType(); System.ReflectionFieldInfo[] elemClassFields = collElemType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (idFieldName2 == string.Empty && iD2 == -1) { // одномерный массив for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName1) { fld1 = j; for (int i = 0; i <= collection.Count - 1; i++) { try { if ((int)elemClassFields[fld1].GetValue (collection[i]) == iD1) { collection.Remove(collection[i]); if (collElement.BaseType == typeof(Sortable)) AddCollectionItem(collection, collElement, iD1, -1, i); // i - порядковый номер элемента в //коллекции else AddCollectionItem(collection, collElement, iD1, -1); break; } } catch { break; } } break; } } } else { // двумерный массив for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName1) // j - индекс имени поля первого ключа fld1 = j; } for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName2) // j - индекс имени поля второго ключа fld2 = j; } for (int i = 0; i <= collection.Count - 1; i++) { try { if ((int)elemClassFields[fld1].GetValue(collection[i]) == iD1 && (int)elemClassFields[fld2].GetValue (collection[i]) == iD2) { collection.Remove(collection[i]); if (collElement.BaseType == typeof(Sortable)) AddCollectionItem(collection, collElement, iD1, iD2, i); // i - порядковый номер элемента в коллекции else AddCollectionItem(collection, collElement, iD1, iD2); break; } } catch { break; } } } } SortCollection(collection, collElement); } public static void SortCollection(IList collection, Type collElement) { /* Теперь, если базовый класс коллекции наследуется от класса Sortable, надо отсортировать коллекцию по SortID, чтобы изменяемый экземпляр занял свое место в коллекции после его обновления (остался в той же строке коллекции). При создании экземпляра класса и добавлении его в коллекцию (AddCollectionItem), свойству SortID в его базовом классе присваивается текущий порядковый номер в коллекции, в порядке получения записей из БД или из другого источника. При обновлении экземпляра в коллекции, после его модификации в БД, он удаляется из коллекции и создается вновь, после чего снова добавляется в конец коллекции. При этом ему присваивается старый SortID и после сортировки коллекции, обновленный экземпляр встает на свое место.*/ if (collElement.BaseType == typeof(Sortable)) { EntityComparer Comp = new EntityComparer(); IComparer comparer = (IComparer)Comp; ArrayList al = ArrayList.Adapter(collection); al.Sort(comparer); } } public static void SortCollectionBack(IList collection) { ArrayList al = ArrayList.Adapter(collection); al.Reverse(0, collection.Count); } public static void RemoveCollectionItem(int iD1, string idFieldName, IList collection, Type collElement) { RemoveCollectionItem(iD1, idFieldName, -1, string.Empty, collection, collElement); } public static void RemoveCollectionItem(int iD1, string idFieldName1, int iD2, string idFieldName2, IList collection, Type collElement) { if (!(iD1 > 0)) return; // если элемента в коллекции нет, он не добавляется if (collection.Count > 0) { int fld1 = -1; int fld2 = -1; Type collElemType = collection[0].GetType(); System.ReflectionFieldInfo[] elemClassFields = collElemType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (idFieldName2 == string.Empty && iD2 == -1) { // одномерный массив for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName1) { fld1 = j; for (int i = 0; i <= collection.Count - 1; i++) { try { if ((int)elemClassFields[fld1]. GetValue(collection[i]) == iD1) { collection.Remove(collection[i]); break; } } catch { break; } } break; } } } else { // двумерный массив for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName1) // j - индекс имени поля первого ключа fld1 = j; } for (int j = 0; j < elemClassFields.Length; j++) { if (elemClassFields[j].Name == idFieldName2) // j - индекс имени поля второго ключа fld2 = j; } for (int i = 0; i <= collection.Count - 1; i++) { try { if ((int)elemClassFields[fld1].GetValue(collection[i]) == iD1 && (int)elemClassFields[fld2].GetValue(collection[i]) == iD2) { collection.Remove(collection[i]); break; } } catch { break; } } } } } } // ************************************************************************************ // Пример реализации класса сущности // ************************************************************************************ public class Book { private int id; public int BookID { get { return id; } set { id = value; } } public int TextID { get; set; } public bool ForeignBook { get; set; } public double
Rating { get; set; } public int Position { get; set; } public int PhotoID { get; set; } public DateTime DateCreation { get; set; } public DateTime Modified { get; set; } public int Count { get; set; } public int CountAll { get; set; } public string Caption { get; set; } public Author Creator { get; set; } public Guid CreatorID { get; set; } public bool Published { get; set; } public Book(int bookID) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["CmsDb"].ConnectionString)) { using (SqlCommand command = new SqlCommand("GetBookDetails", connection)) { command.CommandType = CommandType.StoredProcedure; command.Parameters.Add(new SqlParameter("@BookID", bookID)); connection.Open(); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { try { DateCreation = Convert.ToDateTime(reader["DateCreation"]); Modified = Convert.ToDateTime(reader["Modified"]); BookID = (int)reader["BookID"]; Caption = (string)reader["Caption"]; Position = (int)reader["Position"]; PhotoID = (int)reader["PhotoID"]; Published = (bool)reader["Published"]; Count = (int)reader["NumberOfTexts"]; CountAll = (int)reader["NumberOfAllTexts"]; Rating = 0; if (!(reader["Rating"] is DBNull)) Rating = Convert.ToDouble(reader["Rating"]); ForeignBook = false; if (!(reader["ForeignBook"] is DBNull)) ForeignBook = (bool)reader["ForeignBook"]; TextID = 0; if (!(reader["TextID"] is DBNull)) TextID = (int)reader["TextID"]; Creator = new Author(new Guid((string)reader["CreatorID"])); CreatorID = Creator.CreatorID; } catch { } } reader.Close(); reader.Dispose(); } command.Dispose(); } connection.Close(); connection.Dispose(); } } } public class PublicBooksList : ListRealizator { public static PublicBooksList instance = new PublicBooksList(); //коллекция одна на всех юзеров public PublicBooksList() { Hashtable parameters = new Hashtable(); parameters["@ClubID"] = SessionManager.SiteRootClub; parameters["@SiteID"] = SessionManager.SiteID; instance = (PublicBooksList)CollectionManager.GetCollection("GetClubBooks", "BookID", "DbConnectionAlias", this, typeof(Book), parameters); } public static PublicBooksList GetInstance() { return instance; } public static PublicBooksList GetPublicBooks() { Hashtable parameters = new Hashtable(); parameters["@ClubID"] = SessionManager.SiteRootClub; parameters["@SiteID"] = SessionManager.SiteID; return (PublicBooksList)CollectionManager.GetCollection("GetClubBooks", "BookID", "DbConnectionAlias", instance, typeof(Book), parameters);
}
}
public class UserBooksList : ListRealizator
{
public static UserBooksList GetInstance()
{
return SessionManager.UserBooks;
}
}
}
/* Вот собственно и все, что пока хотелось сказать по этому поводу.
Описанный здесь подход успешно используется на этом сайте (prozarium.ru),
на сайте CityGuide(probki.net), а также в ряде других проектов.

май 2010.
Copyright © pterodactilus.vulgaris
Евгений Трифонов, Санкт-Петербург
mailto: pterodactilus@rambler.ru
*
Upd 02.2014
В исходный код, доступный для скачивания по ссылке выше, добавлена поддержка ID в Guid.

*/