After a long vacation, I have a lot of rest, so I will continue to talk about my feelings about nhib.pdf.
Since it is an ORM framework, it is natural to map the o end to R. As for the set, it is the most common in O, and it is also a very easy representation of the r side. For example, a question (question) can contain multiple answers (answer), so myCodeThere is a structure like this:
Public class Question { Public Virtual int Questionid { Get ; Set ;} Public Virtual string Name { Get ; Set ;} Private Iset < Answer > M_answers; Public Iset < Answer > Answers { Get { If ( This . M_answers = Null ) This . M_answers = New Hashedset < Answer > (); Return this . M_answers ;}Private set { This . M_answers = Value ;}}} Public class Answer { Public Virtual int Answerid { Get ; Set ;} Public Virtual string Name { Get ; Set ;} Public Virtual Question Question {Get ; Set ;}}
So here is a question: why does the answers attribute need to be read and written at the same time? Some may say that Nhibernate supports direct read/write of private variables, so that the read-only attribute can be exposed to the outside. This statement is true (and I already use private set here), but it is not something I'm not satisfied. More accurately, my question is, "Why does Nhibernate need to set the entire collection container "? Imagine that during normal development, all our operations are to add/delete objects to a collection, without being silly in modifying the collection attributes of objects. Because this set is maintained by the object itself, rather than being handed over to the outside world for "one pot of ends" setting.
The container attributes that can be set are not just sensory issues. If I use the above code, I may do this when inserting data into the database:
VaRQuestion =NewQuestion(); Question. Answers. Add (NewAnswer{Name ="Answer 1",Question = question}); Question. Answers. Add (NewAnswer{Name ="Answer 2",Question = question});// Put it into session
Check whether the two red sentences are redundant? It is not just redundant. The problem here is that if the question attribute can be set freely in this way, is it possible that the answer does not match the question? The creation is fine. If you need to operate two question or answer at the same time in a scenario, their relationship may be complicated. This is the case for nhib.pdf. It requires us to manually maintain the bidirectional references of Question and Answer. Otherwise, insertion, deletion, and update may be incorrect.
Some people's solution is to add additional methods, such as addanswer:
Public classQuestion{...Public voidAddanswer (AnswerAnswer ){If(Answer. question! =Null) {Answer. Question. Answers. Remove (answer);} answer. Question =This;This. Answers. Add (answer );}}
The addanswer method can be used to automatically strip the relationship between answer and the original question and establish a connection with the new question. Similarly, deleting an answer object from a question object or modifying the question attribute of an answer object will cause changes in the relationship between the two parties. However, even if we provide a complete link maintenance method, question. Answers is exposed to the outside, developers can still modify the answers set.
Therefore, the best way is to provide a way to maintain the relationship in the collection. For example, in this regard, LINQ to SQL does a good job:
Public partial class Question { Private Static Propertychangingeventargs Emptychangingeventargs = New Propertychangingeventargs ( String . Empty ); Private int _ Questionid; Private string _ Name; Private Entityset < Answer > _ Answers; Public Question (){This . _ Answers = New Entityset < Answer > ( New Action < Answer > ( This . Attach_answers ), New Action < Answer > ( This . Detach_answers ));} Public int Questionid {...}Public String Name {...} Public Entityset < Answer > Answers { Get { Return this . _ Answers ;} Set { This . _ Answers. Assign ( Value );}} Private void Attach_answers ( Answer Entity) {entity. Question =This ;} Private void Detach_answers ( Answer Entity) {entity. Question = Null ;}}
Let's take a look at how considerate we are to using LINQ to SQL. The automatically generated code will help us maintain the bidirectional relationship between question and answer. Of course, some logic is in the question attribute of the answer class. If you are interested, you can observe it yourself. However, the problem with LINQ to SQL is that it uses a special type of entityset, which uses two callback functions to publish the addition/deletion of elements in the set. It is reasonable to say that if we want to use this "automatic maintenance" method in nhib.pdf, we can use a custom set type, for example:
private Iset answer m_answers; Public Iset answer answers { Get { If ( This . m_answers = null ) This . m_answers = New callbackset answer (...); return this . m_answers;} private set { This . m_answers = value ;}
Unfortunately, when creating an object, we naturally use callbackset <answer>, which contains the logic we define. But what if this code is used?
VaRQuestion = session. Get <Question> (1); question. Answers. Add (NewAnswer{Name ="Answer 1", Question = question}); question. Answers. Add (NewAnswer{Name ="Answer 2", Question = question}); Session. Flush ();
When obtaining the question object from the database, nhib.pdf sets the answers attribute "whole" as its own Iset <answer> Object "independently"-because of delayed loading, it is not necessarily a hashedset <answer>. In other words, although nhib.pdf can maintain the logic of attributes, it cannot maintain the logic of custom sets. In my opinion, nhib.pdf can discard the set operation of the set attribute and add all objects through the add method of the set. In fact, this can also achieve delayed loading of sets, just like abandoning the mandatory virtual requirements for all methods and implementing delayed loading of objects.
To avoid misunderstanding of nhib.pdf as I did last time, I did another test-I should have made no mistake this time. Of course, it would be better if nhib.pdf supports custom set types, and we have a solution to this problem. But I don't know how to do it. If you know, please let me know. In my opinion, the current problem is that nhib.pdf has a defect in poco support. If so, our model will have to be moved to nhib.pdf.
Another interesting question about the nhibibset is-please pay attention to the above four lines of code (get-add-flush), which is a very standard and very common way to add answer objects. It is a pity that when the Iset <answer> Add method is called to add an answer object, a database query operation is triggered, load all answers under the current question -- but in my opinion this is not necessary at all. I just "add" and didn't want to query it. In fact, nhib.pdf can help me save the new answer object. Why do we need to increase the fearless overhead? Of course, I admit that this method will cause some trouble. For example, you need to divide the Set Operations into two types: "read" and "write". When the "write" Operation occurs, data is not loaded, the database query is performed only when the database is read for the first time. The separation of "read" and "write" should have been like this.
So who has done that? It is also a LINQ to SQL statement. In fact, there are a lot of considerations about the details of LINQ to SQL, and it is very easy to use-if I am not "Spoiled" by it, I may not care about the issue of nhiberante.
It is a pity that the support for LINQ to SQL in the "ing method" of Orm's life is too limited, which greatly limits the project's acceptance of it.
Related Article
- my feelings about nhib.pdf (1): misunderstandings about the delayed Loading Method
- my feelings about nhib.pdf (2): Why Virtual everywhere
- my feelings about nhib.pdf (3): support for some embarrassing collections
- my feelings about nhibtor (4): An exciting interceptor mechanism