First, share your recent feelings: people who hate you can always find reasons to hate you.
Start of Text
If you are reading this series for the first time, go to index & writing plan to find and read the first two articles in the architectural design series. reading these articles in sequence will give you a better reading experience.
It is strongly recommended to use the source code to read this article: Click here to download (you can run it directly and the database will be automatically generated locally)
The factory implementation has been completed. In the factory, we use the pre-compiled command to implement model switching:
#define A#if Busing Model.B;using DBaccess.B;#endif#if Ausing Model.A;using DBaccess.A;#endif
To switch the model, you only need to change # define a to # define B, which is very convenient (although it still makes me a little uncomfortable)
However, too many pre-compiled commands should not be used. In fact, I am already upset when there is something to change.
Therefore, in the DM layer (data operation layer) and service layer (business logic layer), we cannot see any specific model class name.
In this example, the class names teacher and contact cannot appear in DM and service.
Because every place where the class teacher and class contact appear, we must add the pre-compiled commands mentioned above. In actual projects, this will lead to a lot of changes to the switching model, and may lead to unexpected errors.
The DM layer uses generics to solve the problem. The Code is as follows:
Public class dmbase {protected dbcontext dB; Public dmbase (dbcontext dB) {This. DB = dB ;} /// <summary> /// select one /// </Summary> /// <typeparam name = "T"> </typeparam> /// <Param name = "entity"> the entity here does not actually work, only the record of the first matching record is returned for the compiler type </param> // <Param name = "Predicate"> λ expression </param> // <returns>, if no record exists, null is returned. </returns> Public Virtual t findone <t> (T entity, func <t, bool> Expression) where T: class, New () {return this. DB. set <t> (). firstordefault (expression );} /// <summary> /// select all /// </Summary> /// <typeparam name = "T"> </typeparam> /// <Param name = "entity"> the entity here does not actually work, it is only used by the compiler to evaluate the type </param> Public Virtual iqueryable <t> findall <t> (T entity) where T: Class, new () {return this. DB. set <t> ();} Public Virtual void insert <t> (Params T [] entities) where T: Class, new () {If (entities! = NULL & entities. length> 0) {var set = This. DB. set <t> (); foreach (VAR item in entities) {set. add (item) ;}} Public Virtual void Delete <t> (Params T [] entities) where T: Class, new () {If (entities! = NULL & entities. length> 0) {var set = This. DB. set <t> (); foreach (VAR item in entities) {set. remove (item) ;}}/// <summary> // submit the transaction // </Summary> Public void commit () {This. DB. savechanges ();}}
My comments also show that the findone and findall methods do not need parameters, but an entity parameter is input for the compiler to evaluate the type.
Thanks to xanthodont, this DM was modified in your version and encapsulated well.
After writing the DM layer, the next step is the major concern: the service layer
The following code demonstrates how to obtain all teacher and associate teacher with contact.
Public object findallteacher () {// get a context var context = contextfactory. getcontext (); // GET teacher and contact from factory // var A = modelfactory must be used here. getteacher (); var B = modelfactory. getcontact (); var alist = modellistfactory. getteacherlist (); dmbase dm = new dmbase (context); // use the previously obtained teacher and contact to input the DM layer, facilitating the compiler to deduce the type var contact = DM. findall (B); var Teacher = DM. findall (a); // business logic. Associate teacher with contact. var result = teacher. join (contact, O => O. ID, r => r. teacherid, (O, R) => New {TT = O, AA = r}); Result = result. orderbydescending (O => O. AA. email); // process data foreach (VAR item in result) {A = item. TT;. contact = item. AA; alist. add (a) ;}return alist ;}
Note: Here I use object as the return type, because I do not know that the returned value is ilist <model. a. teacher> or ilist <model. b. teacher>. Fortunately, we only need to disassemble the box once.
Next, we will demonstrate how to insert:
public bool AddTeacher<T, T1>(T teacher, T1 contact) where T : class,new() where T1 : class,new() { try { var context = ContextFactory.GetContext(); DMbase dm = new DMbase(context); dm.Insert(teacher); dm.Insert(contact); dm.Commit(); return true; } catch { return false; } }
Only when DM. Commit () is executed will the two insert statements be committed to the database, ensuring transaction consistency.
Put aside
PS: Yesterday was the birthday of the blogger, and he was one year old. If you have any chance to read the garden friends here, don't mean your blessing :)