Классические Business Logic Layer
На этой страничке я расскажу как писать собственные бизнес-объекты для AsP2-страничек. На эту тему есть как-бы статейка в MSDN, однако понять по ней что это такое именно - непросто. У меня на сайте также описан один из созданных мною еще в 2005-году бизнес-обьект на базе спец-коллекций.
Для того, чтоб написать нормальный (который я называю классическим BLL) надо чтоб он вызывался из ObjectDataSource, размещенного на страничке. И чтобы контролы могли БЕЗ дополнительных ухищрений быть просто привязаны к этому ObjectDataSource. Для примера рассмотрим вот такую страничку, на которой выводится списочек курсов учебного заведения.
Формируется этот списочек весьма прихотливо - десять принципиально разных режимов его формирования. Плюс коррелированный справа списочек воскресных занятий, соответствующих основному списочку. Самая правая табличка внизу - она как раз и показывает режим работы BLL - для демонстрационных целей. В данном случае - страничка сформировала режим работы BLL - FillBySemesterAndMainSubCategry. C таким коррелированным списочком (который находится чуть выше отладочной панели) я толкнулся впервые и тут тоже есть пара интересных моментов, которые мы посмотрим позже.
Вообще на этом хомячке я описал технику построения и более хитрых BLL - в том числе таких, где перечень режимов работы можно расширять и расширять с помощью плагинов. Разумеется, любой из этих бизнес-обьектов можно вызывать не только со страничек, но из любого ASP2-класса, а тот, что написан на базе спецколлекций - вообще не использует Session и был написан ЕДИНЫМ библиотечным модулем для виндузовых и вэб-приложений.
Но сначала начнем с элементарного. Для того, чтобы контролы могли получать рекордсеты при посредничестве ObjectDataSource - наш BLL должен обязательно хранить в себе экземпляр ДатаТабле и отдавать на него ссылку именно тем методом, который мы укажем в ObjectDataSource.
Как видите, у моего бизнес обьекта есть два метода, возвращающие данные - GetCourseList (для основного списочка) и GetSamSeminarList (для связанного списочки воскресных семинаров по этим же темам). В обоих случаях возврат данных происходит в виде типизированной таблички dsCourses.CourseDataTable. Это, так сказать, внешний интерфейс нашего бизнес обьекта.
Теперь посмотрим его внутреннее устройство. На самом деле есть несколько способов передачи параметров в Бизнес-обьект. Один из них - в ObjectDataSource.Selecting есть параметр e.Arguments, через который и передаются параметры для ObjectDataSource. Но я чаще передаю параметры в бизнес-обьекты через Session. Мне кажется так удобнее - тем более единажду установленный Session, например, с номером семестра, можно использовать В РАЗНЫХ бизнес-обьектах без дополнительного кода, а у меня их только для работы этой страничке четыре штуки.
Итак, мы остановились на том, что параметры для работы Бизнес-обьекта будут сформированы из Session, и по ним бизнес-объект сформирует выходной рекордсет. Теперь начало класса BLL очевидно.
00001: Public Enum Sort_Order 00002: Kursnummer = 1 00003: Stufe = 2 00004: Uhrzeit = 3 00005: DozentIn = 4 00006: End Enum 00007: 00008: Public Enum Course_Mode 00009: FillByNummer = 1 00010: FillBySemester = 2 00011: FillByNummerAndSemester = 3 00012: FillBySemesterAndMainSubCategry = 4 00013: FillByLector = 5 00014: FillBySemesterAndLector = 6 00015: FillBySemesterAndLectorAndMainSubCategory = 7 00016: FillSamBySemester = 8 00017: FillSamBySemesterAndMainSubCategory = 9 00018: FillSamBySemesterAndNummer = 10 00019: End Enum 00020:
Соотвественно обращение к нашему бизнес-обекту со странички будет выглядеть примерно так:
Далее идет определение класса и пара методов, позволяющих со стороны странички наложить фильтр на наш кеш с данными и пересортировать его. Обратите внимание на тртибут класса System.ComponentModel.DataObject, позволяющий кликнуть галочку "show only data component" и из великого множества различных коллекций в этом проекте отобрать НЕСКОЛЬКО .
00021: <System.ComponentModel.DataObject()> _ 00022: Public Class BLLCourseList 00023: 00024: Dim Cn As New dsCourses.CourseDataTable 00025: Dim CnMain As New dsCourses.CourseDataTable 'cphMainContent 00026: Dim CnSecond As New dsCourses.CourseDataTable 'cphSecondaryContent 00027: Dim CnMainDV As DataView = Cn.DefaultView 00028: Dim CnSecondDV As DataView = New DataView(Cn) 00029: Dim CnTa As New dsCoursesTableAdapters.CourseNewTableAdapter 00030: Dim CnCourseFilter As Course_Filter 00031: Dim CnOrder As Sort_Order 00032: Dim CnCourseMode As Course_Mode 00033: Dim CnLectorID As String 00034: Dim CnSemesterID As String 00035: Dim CnMainCategoryID As String 00036: Dim CnSubCategoryID As String 00037: Dim CnCourseID As String 00038: 00039: Private Enum Course_Filter 00040: OnlySamstagsSeminar = 1 00041: WithoutSamstagsSeminar = 2 00042: NoFilter = 3 00043: End Enum 00044: 00045: ''' <summary> 00046: ''' Filling DataSet for type, specified in Session("CourseListMode") - one or more courses 00047: ''' </summary> 00048: Public Sub New() 00049: Me.Refresh() 00050: End Sub 00051: Private Sub ImposeFilter(ByVal FilterType As Course_Filter) 00052: Select Case FilterType 00053: Case Course_Filter.OnlySamstagsSeminar 00054: CnMainDV.RowFilter = "Samstagsseminar='true'" 00055: Case Course_Filter.WithoutSamstagsSeminar 00056: CnMainDV.RowFilter = "Samstagsseminar='false'" 00057: End Select 00058: End Sub 00059: Private Sub ReSort(ByVal OrderID As Sort_Order) 00060: Select Case OrderID 00061: Case Sort_Order.Kursnummer 00062: CnMainDV.Sort = "Kursnummer" 00063: Case Sort_Order.Stufe 00064: CnMainDV.Sort = "StufeOrder desc" 00065: Case Sort_Order.Uhrzeit 00066: CnMainDV.Sort = "DayOfWeek" 00067: Case Sort_Order.DozentIn 00068: CnMainDV.Sort = "Nachname, Vorname" 00069: End Select 00070: End Sub
Обратите также внимание на то, что собственно формирование ДатаСета вынесено в отдельный метод Refresh, ибо созданием бизнес обьектов управляет сам движок ASP2, а вот переформировать рекордсет нам может потребоваться в любой момент. Правда для этого надо на страничке иметь на него ссылку. Это важно. Ибо именно эта ссылка позволяет зацепиться за бизнес, обьект и вызвать у него ВТОРОЙ метод, в данном случае для коррелированного списочка справа.
Собственно получить ссылку на бизнес-объект с главной странички можно так:
Теперь посмотрим собственно сам метод Refresh, готовящий данные.
00071: ''' <summary> 00072: ''' Filling DataSet for type, specified in Session("CourseListMode") - one or more courses and 00073: ''' return TWO datatable - Main (on GetCourseList) and Side(Samstag) on GetSamSeminarList 00074: ''' </summary> 00075: Public Sub Refresh() 00076: If Not (HttpContext.Current.Session("CourseListMode") Is Nothing) Then 00077: ' 00078: Dim T As Course_Mode = CInt(HttpContext.Current.Session("CourseListMode")) 00079: CnCourseMode = T 00080: ' 00081: CnSemesterID = HttpContext.Current.Session("SemesterID") 00082: CnMainCategoryID = HttpContext.Current.Session("MainCategoryID") 00083: CnSubCategoryID = HttpContext.Current.Session("SubCategoryID") 00084: CnLectorID = HttpContext.Current.Session("LectorID") 00085: CnCourseID = HttpContext.Current.Session("CourseID") 00086: CnOrder = CInt(HttpContext.Current.Session("SortOrder")) 00087: If CnOrder = 0 Then CnOrder = Sort_Order.Kursnummer 00088: ' 00089: CnSecondDV.RowFilter = "Samstagsseminar='true'" 00090: CnSecondDV.Sort = "Kursnummer" 00091: ' 00092: CnTa.ClearBeforeFill = True 00093: Select Case T 00094: Case Course_Mode.FillBySemesterAndMainSubCategry 00095: If Not (HttpContext.Current.Session("MainCategoryID") Is Nothing) And _ 00096: Not (HttpContext.Current.Session("SemesterID") Is Nothing) And _ 00097: Not (HttpContext.Current.Session("SubCategoryID") Is Nothing) Then 00098: Try 00099: CnTa.FillBySemesterAndMainSubCategry(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString), New Guid(HttpContext.Current.Session("MainCategoryID").ToString), New Guid(HttpContext.Current.Session("SubCategoryID").ToString)) 00100: Catch ex As System.Data.ConstraintException 00101: End Try 00102: ImposeFilter(Course_Filter.WithoutSamstagsSeminar) 00103: Else 00104: Throw New Exception("Session(""MainCategoryID""), Session(""SemesterID""), Session(""SubCategoryID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=FillBySemesterAndMainSubCategry. ") 00105: End If 00106: ' 00107: Try 00108: CnSecond.Merge(CnSecondDV.ToTable) 00109: Catch ex As System.Data.ConstraintException 00110: End Try 00111: 00112: Case Course_Mode.FillByNummer 00113: If Not (HttpContext.Current.Session("CourseID") Is Nothing) Then 00114: Try 00115: CnTa.FillByNummer(Cn, HttpContext.Current.Session("CourseID").ToString) 00116: Catch ex As System.Data.ConstraintException 00117: End Try 00118: ImposeFilter(Course_Filter.NoFilter) 00119: Else 00120: Throw New Exception("Session(""CourseID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Course. ") 00121: End If 00122: If HttpContext.Current.Session("SemesterID") Is Nothing Then 00123: Dim CMD As New siSMWeb.ExecSQL_RDR() 00124: Dim rdr = CMD.ExecSQL("dbo.nc_SemesterSelectCurrent") 00125: If rdr.Read Then HttpContext.Current.Session("SemesterID") = rdr("SemesterID").ToString 00126: End If 00127: 'В этом режиме боковую панель получим не фильтрацией из главной, а вообще заново 00128: Try 00129: CnTa.FillSamBySemester(CnSecond, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00130: Catch ex As System.Data.ConstraintException 00131: End Try 00132: 00133: Case Course_Mode.FillByNummerAndSemester 00134: If Not (HttpContext.Current.Session("CourseID") Is Nothing) And _ 00135: Not (HttpContext.Current.Session("SemesterID") Is Nothing) Then 00136: Try 00137: CnTa.FillByNummerAndSemester(Cn, HttpContext.Current.Session("CourseID").ToString, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00138: Catch ex As System.Data.ConstraintException 00139: End Try 00140: ImposeFilter(Course_Filter.NoFilter) 00141: Else 00142: Throw New Exception("Session(""CourseID""), Session(""SemesterID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=SemesterAndCourse. ") 00143: End If 00144: 'В этом режиме боковую панель получим не фильтрацией из главной, а вообще заново 00145: Try 00146: CnTa.FillSamBySemester(CnSecond, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00147: Catch ex As System.Data.ConstraintException 00148: End Try 00149: 00150: Case Course_Mode.FillBySemester 00151: If Not (HttpContext.Current.Session("SemesterID") Is Nothing) Then 00152: Try 00153: CnTa.FillBySemester(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00154: Catch ex As System.Data.ConstraintException 00155: End Try 00156: ImposeFilter(Course_Filter.WithoutSamstagsSeminar) 00157: Else 00158: Throw New Exception("Session(""SemesterID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Semester. ") 00159: End If 00160: ' 00161: Try 00162: CnSecond.Merge(CnSecondDV.ToTable) 00163: Catch ex As System.Data.ConstraintException 00164: End Try 00165: 00166: Case Course_Mode.FillByLector 00167: If Not (HttpContext.Current.Session("LectorID") Is Nothing) Then 00168: Try 00169: CnTa.FillByLector(Cn, New Guid(HttpContext.Current.Session("LectorID").ToString)) 00170: Catch ex As System.Data.ConstraintException 00171: End Try 00172: ImposeFilter(Course_Filter.NoFilter) 00173: Else 00174: Throw New Exception("Session(""LectorID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Course_Mode.Lector. ") 00175: End If 00176: ' 00177: Try 00178: CnSecond.Merge(CnSecondDV.ToTable) 00179: Catch ex As System.Data.ConstraintException 00180: End Try 00181: 00182: Case Course_Mode.FillBySemesterAndLector 00183: If Not (HttpContext.Current.Session("SemesterID") Is Nothing) And _ 00184: Not (HttpContext.Current.Session("LectorID") Is Nothing) Then 00185: Try 00186: CnTa.FillBySemesterAndLector(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString), New Guid(HttpContext.Current.Session("LectorID").ToString)) 00187: Catch ex As System.Data.ConstraintException 00188: End Try 00189: ImposeFilter(Course_Filter.NoFilter) 00190: Else 00191: Throw New Exception("Session(""LectorID""), Session(""SemesterID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Course_Mode.SemesterAndLector. ") 00192: End If 00193: ' 00194: Try 00195: CnSecond.Merge(CnSecondDV.ToTable) 00196: Catch ex As System.Data.ConstraintException 00197: End Try 00198: 00199: Case Course_Mode.FillBySemesterAndLectorAndMainSubCategory 00200: If Not (HttpContext.Current.Session("SemesterID") Is Nothing) And _ 00201: Not (HttpContext.Current.Session("LectorID") Is Nothing) And _ 00202: Not (HttpContext.Current.Session("MainCategoryID") Is Nothing) And _ 00203: Not (HttpContext.Current.Session("SubCategoryID") Is Nothing) Then 00204: Try 00205: CnTa.FillBySemesterAndLectorAndMainSubCategory(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString), New Guid(HttpContext.Current.Session("LectorID").ToString), New Guid(HttpContext.Current.Session("MainCategoryID").ToString), New Guid(HttpContext.Current.Session("SubCategoryID").ToString)) 00206: Catch ex As System.Data.ConstraintException 00207: End Try 00208: ImposeFilter(Course_Filter.NoFilter) 00209: Else 00210: Throw New Exception("Session(""LectorID""), Session(""SemesterID""), Session(""MainCategoryID""), Session(""SubCategoryID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Course_Mode.FillBySemesterAndLectorAndMainSubCategory. ") 00211: End If 00212: ' 00213: Try 00214: CnSecond.Merge(CnSecondDV.ToTable) 00215: Catch ex As System.Data.ConstraintException 00216: End Try 00217: 00218: Case Course_Mode.FillSamBySemester 00219: If Not (HttpContext.Current.Session("SemesterID") Is Nothing) Then 00220: Try 00221: CnTa.FillSamBySemester(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00222: Catch ex As System.Data.ConstraintException 00223: End Try 00224: ImposeFilter(Course_Filter.OnlySamstagsSeminar) 00225: Else 00226: Throw New Exception("Session(""SemesterID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=Samstags. ") 00227: End If 00228: ' 00229: Try 00230: CnSecond.Merge(CnSecondDV.ToTable) 00231: Catch ex As System.Data.ConstraintException 00232: End Try 00233: 00234: Case Course_Mode.FillSamBySemesterAndMainSubCategory 00235: If Not (HttpContext.Current.Session("MainCategoryID") Is Nothing) And _ 00236: Not (HttpContext.Current.Session("SemesterID") Is Nothing) And _ 00237: Not (HttpContext.Current.Session("SubCategoryID") Is Nothing) Then 00238: Try 00239: CnTa.FillSamBySemesterAndMainSubCategory(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString), New Guid(HttpContext.Current.Session("MainCategoryID").ToString), New Guid(HttpContext.Current.Session("SubCategoryID").ToString)) 00240: Catch ex As System.Data.ConstraintException 00241: End Try 00242: ImposeFilter(Course_Filter.OnlySamstagsSeminar) 00243: Else 00244: Throw New Exception("Session(""MainCategoryID""), Session(""SemesterID""), Session(""SubCategoryID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=FillSamBySemesterAndMainSubCategory. ") 00245: End If 00246: ' 00247: Try 00248: CnSecond.Merge(CnSecondDV.ToTable) 00249: Catch ex As System.Data.ConstraintException 00250: End Try 00251: 00252: Case Course_Mode.FillSamBySemesterAndNummer 00253: If Not (HttpContext.Current.Session("CourseID") Is Nothing) And _ 00254: Not (HttpContext.Current.Session("SemesterID") Is Nothing) Then 00255: Try 00256: CnTa.FillSamBySemesterAndKursnummer(Cn, New Guid(HttpContext.Current.Session("SemesterID").ToString), HttpContext.Current.Session("CourseID")) 00257: Catch ex As System.Data.ConstraintException 00258: End Try 00259: ImposeFilter(Course_Filter.OnlySamstagsSeminar) 00260: Else 00261: Throw New Exception("Session(""MainCategoryID""), Session(""SemesterID""), Session(""SubCategoryID"") are need for use class ""BLLCourseList"" with Session(""CourseListMode"")=FillSamBySemesterAndMainSubCategory. ") 00262: End If 00263: 'В этом режиме боковую панель получим не фильтрацией из главной, а вообще заново 00264: Try 00265: CnTa.FillSamBySemester(CnSecond, New Guid(HttpContext.Current.Session("SemesterID").ToString)) 00266: Catch ex As System.Data.ConstraintException 00267: End Try 00268: 00269: End Select 00270: 'теперь пересортируем и отфильтруем курсы в главную таблу 00271: If CnMainDV.Count > 1 Then Call ReSort(CnOrder) 00272: Try 00273: CnMain.Merge(CnMainDV.ToTable) 00274: Catch ex As System.Data.ConstraintException 00275: End Try 00276: Else 00277: Throw New Exception("Session(""CourseListMode"") are need for use class ""BLLCourseList"". ") 00278: End If 00279: End Sub
Как видите, это довольно тривиальный код, компонующий параметры для обращения к методам заполнения рекордсета и реализующий все десять способов формирования основного и дополнительного списочков.
Завершающий фрагмент этого BLL - собственно методы, возвращающий данные для ObjectDataSource:
00280: ''' <summary> 00281: ''' Return One or More sorted and filtered Courses (параметры сюда при желании можно передать через e.Arguments события странички CourseListObj_Selecting 00282: ''' </summary> 00283: Public Function GetCourseList() As dsCourses.CourseDataTable 00284: GetCourseList = CnMain 00285: End Function 00286: ''' <summary> 00287: ''' Return SamSeminar, соответствующие главному списку 00288: ''' </summary> 00289: Public Function GetSamSeminarList() As dsCourses.CourseDataTable 00290: GetSamSeminarList = CnSecond 00291: End Function 00292: End Class
Как видите, все довольно просто. Теперь посмотрим, как именно устроен наш ДатаСет, в котором перечислены методы отбора из базы:
В данном случае ДатаСет содержит несколько таблиц для всех Бизнес-обьектов этой странички.
Теперь посмотрим как эти отборы устроены на уровне SQL. Разумеется, такое счастье выпадает не всегда и обычно отборы сложные-пресложные и совершенно не похожи друг на друга. Но в этом случае мне повезло. А возможно я сам организовал себе везение, создав такую вьюшку:
00001: ALTER View [dbo].[CourseList] 00002: as 00003: select 00004: [Course].[CourseID], 00005: [Course].[DefaultRoomID], 00006: [Course].[DefaultDozentID], 00007: [Course].[MainCategoryID], 00008: [Course].[SubCategoryID], 00009: [Course].[SemesterID], 00010: [Course].[CourseString], 00011: [Course].[Kursnummer], 00012: [Course].[Kursbezeichnung], 00013: [Course].[Kursbeschreibung], 00014: [Course].[Kursbeschreibung_lang], 00015: [Course].[Kursstunden], 00016: [Course].[Kurspreis], 00017: [Course].[Skript], 00018: [Course].[Skriptpreis], 00019: [Course].[DefaultKursbeginnZeit], 00020: [Course].[DefaultKursendeZeit], 00021: [Course].[Kursbemerkungen], 00022: [Course].[Lehrmittel], 00023: [Course].[Spalte1Bemerkungen], 00024: [Course].[Spalte2Bemerkungen], 00025: [Course].[Status], 00026: [Course].[Stufe], 00027: [Course].[SortIndex], 00028: [Course].[Eroeffnungsdatum], 00029: [Course].[EroeffnetVon], 00030: [Course].[Mutationsdatum], 00031: [Course].[MutiertVon], 00032: [Course].[AnzTeilnehmer], 00033: [Course].[MinTeilnehmer], 00034: [Course].[MaxTeilnehmer], 00035: [Course].[Samstagsseminar], 00036: [Course].[ErfolgskontoDebitoren], 00037: [Semester].[Semester], 00038: [Room].[Raumnummer], 00039: [Room].[Ort], 00040: [Contact].[Vorname], 00041: [Contact].[Nachname], 00042: left([Course].[DefaultKurstag],2) as DefaultKurstag, 00043: null as SamSemDatum, 00044: case [Course].[DefaultKurstag] 00045: when 'Montag' then 1 00046: when 'Dienstag' then 2 00047: when 'Mittwoch' then 3 00048: when 'Donnerstag' then 4 00049: when 'Freitag' then 5 00050: when 'Samstag' then 6 00051: when 'Sonntag' then 7 00052: end as [DayOfWeek], 00053: case 00054: when len([Course].[Stufe])>0 then [Course].[Stufe] 00055: else 'Z' 00056: end as [StufeOrder] 00057: FROM Course 00058: JOIN Contact ON Course.DefaultDozentID = Contact.ContactID 00059: JOIN Semester ON Course.SemesterID = Semester.SemesterID 00060: JOIN Room ON Course.DefaultRoomID = Room.RoomID 00061: where Samstagsseminar='false' and ShowWeb = N'true' 00062: 00063: union all 00064: 00065: select 00066: [Course].[CourseID], 00067: [Course].[DefaultRoomID], 00068: [Course].[DefaultDozentID], 00069: [Course].[MainCategoryID], 00070: [Course].[SubCategoryID], 00071: [Course].[SemesterID], 00072: [Course].[CourseString], 00073: [Course].[Kursnummer], 00074: [Course].[Kursbezeichnung], 00075: [Course].[Kursbeschreibung], 00076: [Course].[Kursbeschreibung_lang], 00077: [Course].[Kursstunden], 00078: [Course].[Kurspreis], 00079: [Course].[Skript], 00080: [Course].[Skriptpreis], 00081: [Course].[DefaultKursbeginnZeit], 00082: [Course].[DefaultKursendeZeit], 00083: [Course].[Kursbemerkungen], 00084: [Course].[Lehrmittel], 00085: [Course].[Spalte1Bemerkungen], 00086: [Course].[Spalte2Bemerkungen], 00087: [Course].[Status], 00088: [Course].[Stufe], 00089: [Course].[SortIndex], 00090: [Course].[Eroeffnungsdatum], 00091: [Course].[EroeffnetVon], 00092: [Course].[Mutationsdatum], 00093: [Course].[MutiertVon], 00094: [Course].[AnzTeilnehmer], 00095: [Course].[MinTeilnehmer], 00096: [Course].[MaxTeilnehmer], 00097: [Course].[Samstagsseminar], 00098: [Course].[ErfolgskontoDebitoren], 00099: [Semester].[Semester], 00100: [Room].[Raumnummer], 00101: [Room].[Ort], 00102: [Contact].[Vorname], 00103: [Contact].[Nachname], 00104: left([Course].[DefaultKurstag],2) as DefaultKurstag, 00105: case 00106: when isnull(SamSemDatum1,0)=0 then '' 00107: else convert(nvarchar,SamSemDatum1,5) 00108: end 00109: + 00110: case 00111: when isnull(SamSemDatum2,0)=0 then '' 00112: else ' / ' + convert(nvarchar,SamSemDatum2,5) 00113: end 00114: + 00115: case 00116: when isnull(SamSemDatum3,0)=0 then '' 00117: else ' / ' + convert(nvarchar,SamSemDatum3,5) 00118: end 00119: + 00120: case 00121: when isnull(SamSemDatum4,0)=0 then '' 00122: else ' / ' + convert(nvarchar,SamSemDatum4,5) 00123: end 00124: + 00125: case 00126: when isnull(SamSemDatum5,0)=0 then '' 00127: else ' / ' + convert(nvarchar,SamSemDatum5,5) 00128: end 00129: + 00130: case 00131: when isnull(SamSemDatum6,0)=0 then '' 00132: else ' / ' + convert(nvarchar,SamSemDatum6,5) 00133: end 00134: as SamSemDatum, 00135: case [Course].[DefaultKurstag] 00136: when 'Montag' then 1 00137: when 'Dienstag' then 2 00138: when 'Mittwoch' then 3 00139: when 'Donnerstag' then 4 00140: when 'Freitag' then 5 00141: when 'Samstag' then 6 00142: when 'Sonntag' then 7 00143: end as [DayOfWeek], 00144: case 00145: when len([Course].[Stufe])>0 then [Course].[Stufe] 00146: else 'Z' 00147: end as [StufeOrder] 00148: FROM Course 00149: JOIN Contact ON Course.DefaultDozentID = Contact.ContactID 00150: JOIN Semester ON Course.SemesterID = Semester.SemesterID 00151: JOIN Room ON Course.DefaultRoomID = Room.RoomID 00152: where Samstagsseminar='true' and ShowWeb = N'true'
Здесь есть пара моментов, которые могут вызвать гомерический хохот у настоящего гурмана - например запоминание логических величин True/False в базе в виде тектовых строк. Разумееется, вы понимаете, что структуру базы разрабатывал не я... Обратите внимание, как я создал дополнительные столбцы на уровне SQL, чтобы предельно упростить BLL и свести сортировку в ДатаСетах к стандартному методу.
Так вот, создав такую вьюшку, я могу делать множество отборов весьма единообразно - примерно так:
00001: ALTER PROCEDURE [dbo].[nc_CourseSamSelectBySemesterAndMainSubCategory] 00002: @SemesterID uniqueidentifier, 00003: @MainCategoryID uniqueidentifier, 00004: @SubCategoryID uniqueidentifier 00005: AS 00006: SELECT * FROM CourseList WHERE Samstagsseminar='true' and SemesterID=@SemesterID 00007: and MainCategoryID=@MainCategoryID and SubCategoryID=@SubCategoryID 00008: order by Kursnummer 00009: 00010: 00011: ALTER PROCEDURE [dbo].[nc_CourseSamSelectBySemesterAndKursnummer] 00012: @SemesterID uniqueidentifier, 00013: @Kursnummer nvarchar(50) 00014: AS 00015: SELECT * FROM CourseList 00016: WHERE Samstagsseminar='true' and SemesterID=@SemesterID and Kursnummer=@Kursnummer 00017: order by Kursnummer 00018: 00019: 00020: ALTER PROCEDURE [dbo].[nc_CourseSamSelectBySemester] 00021: @SemesterID uniqueidentifier 00022: AS 00023: SELECT * FROM CourseList 00024: WHERE Samstagsseminar='true' and SemesterID=@SemesterID 00025: order by Kursnummer 00026: 00027: 00028: ALTER PROCEDURE [dbo].[nc_CourseSelectByNummer] 00029: @CourseID nvarchar(50) 00030: AS 00031: SELECT * FROM CourseList WHERE Kursnummer = @CourseID 00032: 00033: 00034: ALTER PROCEDURE [dbo].[nc_CourseSelectBySemesterAndLectorAndMainSubCategory] 00035: @SemesterID uniqueidentifier, 00036: @LectorID uniqueidentifier, 00037: @MainCategoryID uniqueidentifier, 00038: @SubCategoryID uniqueidentifier 00039: AS 00040: SELECT * FROM CourseList 00041: WHERE SemesterID = @SemesterID 00042: and DefaultDozentID=@LectorID 00043: and MainCategoryID=@MainCategoryID 00044: and SubCategoryID=@SubCategoryID 00045:
... И так далее. Как видите, процедур много, но для их написания вообще думать не требуется. Это не единственное достоинство. Второе - то, что оптимизатор видит что параметры отборов разные и строит планы отборов по-разному в каждом их отборов. Но, разумеется, такое счастье выпадает далеко не в каждом проекте - значительно чаще все же эти процедуры совершенно непохожи друг на друга.
|