Tools • 55:23
This is an in-depth exploration of new and advanced features of EOF 4.5. It includes shared editing contexts, deferred faults, and schema synchronization, as well as batch faulting, prefetching, complex many-to-many, delete rules, and stored procedures.
Speaker: Eric Noyau
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good morning, everybody. I hope you will understand me. Even with my French accent, I'm going to try to talk slowly so everybody can understand, especially the Japanese people in the box there that told me to just please talk slowly, otherwise we don't understand anything. I want to talk about Advanced EOF.
So what is Advanced EOF? Something like a month ago somebody came into my into my office and said, "Hey, you're going to have a talk at WWDC. You're going to talk about Advanced EOF." I can say, "Okay, what am I going to talk about?" I say, "Oh, that's your problem. That's Advanced EOF.
You're the Advanced EOF guy. Deal with it." So I took a piece of paper and started, you know, jotting notes on it and said, "Okay, what can I talk about?" I can talk about how to write an adapter, or I can talk about some stupid things that I've seen some customers doing.
I can talk about all the features in EOF, you know, we have plenty of features. And I went to see the other member of the team and asked, you know, "What can I talk about?" And everybody had a different idea about what I should talk about. And I didn't end up with this list. I could have filled the 18 sessions just with just the content of the list.
So it was really hard to find something that's advanced and something that's interesting. And I finally tried to reduce this thing in a session that lasts just an hour. And I finally reduced it and reduced it and then re-upholstered the session. And it was still two hours, so I reduced it a little more. And I did end up with an agenda that contained only two items. But these are good items.
First item is what I want to cover is how do you do a good enterprise object? What's the process? What should be the mindset at every step on the way? It's actually a real problem. When you see all these demos of direct-to-Java client, direct-to-web, or any kind of WebObjects demo, you see the demo is always starting, "Oh, I have this model file I have somewhere on my disk.
Just drop it there." But actually making the model file and getting to this where you can just drop some model file in your application and having everything work is actually quite tough. So I want to talk about this. It's going to take half of my time. And the second thing I want to talk about is about the new features in 4.5. We introduced a lot of really cool things in 4.5.
And who in the room is using 4.5? That's, that's... okay. So I want to point out what are the little things that we did, and the big thing that we did in 4.5 that were not in 4, that were not here before, and that you can use in your applications, and some of them are really good.
So, let's start. How to design a good EOF? Where do you start? Well, you start with your data model. You start with your data. You start with what's in your database. Most of the time, you have an existing database that you have to deal with. Some of the time, you have the liberty to create your own database, and that's better because you can make better decisions to integrate with EOF. But, you know, we know what real life is, and you have to integrate with what's already there, what exists, you know, and deal with this database administrator who is in no way going to change his view and giving you nice access to his table.
So when you look at what's in your database and you're thinking about integrating with EOF, the first thing is think about the performance implications of the design. If your customer table, every row has a 10 megabyte blob in it, well, you're not going to have good performance because you're going to fetch these blobs over and over and over again, and it's going to take all your time.
Also, when you look at a database, especially a database that's really split in little tables all over the place, you have a tendency to think, "Oh, I can model that with object inheritance. That would be great. I can have this 20-legger of inheritance thing, and it's going to be great." But the problem is, there is a performance problem with inheritance. Inheritance is working, but it's a dangerous thing.
If you go with something that's too deep, you're going to have a really, really hard time keeping the performance up and being able to fetch all these things, not mentioning that Sometimes you're going to have some problems with EOF in certain cases of inheritance that you are going to need to deal with it. If you don't have any inheritance, that's way simpler to work with EOF.
Another thing are trigger and stored procedures. EOF is working fine with trigger and stored procedures, but you have some work to do in order to make this thing work. By default, we don't do anything in this area. The worst I've seen was actually an internal project at Apple, where we've seen this internal application, and we decided to try to write a prototype to replace the existing application using EOF and Java Client, actually.
And so we asked the DBA, a person in ISNT in charge of database, "Hey, give us database access, right?" And this person gave us So, we had an access to a database that was really weird. It gave us an access to a bunch of views, views on everything in the database. No real table, just views, read-only views all over the place. And to modify the database was, oh, we have all these stored procedures that you can call and doing other things.
And what they did, actually, was encoding all their business logic in the stored procedure there, all their validation rules and everything. From the database standpoint, that makes some sense. From the DBA position, he doesn't want his database to be touched in a way he doesn't understand it. But for an EOF point of view, this is a nightmare.
It's just insane. You cannot just, you have to modify all your updates, you have to modify all your delete, you have to modify all your fetch, because of course all the view he was giving us were doing joins in the back, so they were relatively slow. In order to get data, we had to fetch from multiple views and doing join between the views and getting the same data multiple times. This was just insane.
And to be honest with you, we gave up. We decided that it was not worth the trouble, and we banged on the DBAA until it gave us real access to the database, to the real tables. And at that time, we discovered why there was views, is because the real database was, you know, an old database that was revised and revised and revised and revised. And this was just a mess, and it took us something like a week just to understand what was in the database.
And finally, last thing you have to think about is how your primary key are generated in the database. That's something that's important. And we kind of defer this thing. Oh, I'll deal with it later. And you have to think it right away, because it's going to impact the design. It's going to change the way you interact with the database.
I have a slide on primary key generation here showing off the four main ways that EOF supports generating primary keys. The first, easiest way is you control the database. You are the only user of the database, or you're creating the database. Let the EO adapter or underlet adjust.
If you're in Oracle, that's a sequence. If you're on Sybase, that's a stored procedure. If you're using ODBC, that's just a separate table that we read and update and do these kind of things. It's working just fine, but you have to be aware that actually this is the slowest way you can do primary key.
Every time you insert an object, you're going to do an additional round trip to the database to get the primary key for this object. So if you insert 200 objects, that's 200 round trips. So if you don't insert a lot of objects, that's fine. If you insert a lot of objects, you may want to try one or the other approach.
The second approach is, in your database you make the primaric of your object NSData, some kind of blob value. On the application side, you make this an NSData, and you make it exactly 12 bytes long. What's going to happen there is WebObjects.EOF is going to generate this primaric for you.
creating something from the process ID, the IP address, a timestamp, and some other stuff. We generate something unique on the application side and stuff that in the snapshot and send that to the database server. So we don't make any round trips. It's way faster. You notice my stump here, Web Objects 5 for Java.
Why is it there? Well, you know, we're going pure Java. In pure Java, we don't have a process ID, right? And we have no way to get one, so we had to change this feature, actually. And I just want to point out that for the next three of the WebObjects, the 12-byte binary is going to be a 24-byte binary. So if you're using this feature, you have to be aware of that, because that means that your database is going to need to change when you're going to transition from 4.5 to 5 for Java.
That's why I've used this little red warning there. So the way of generating primary keys is to use delegate, database context, new primary key, and you basically do whatever you want in there. You just return a dictionary containing your primary keys, and at the end of it, this is -- you can, for example, do that to -- with Oracle, you can use sequences the same way that we do, but instead of asking, you know, one number at a time, you can just go there and ask for 100 numbers and then reuse them in memory, and when you are out of them, you ask for the next batch of 100.
So that's a way to solve the performance issue with the first one. And finally, a way that's actually really simple. You make the primary key a class property attribute, so it's part of your object, and in a way, from insertion, you just stuff something in there, and that's your primary key. Simplest way to do it.
So once you have your data model, you understand what's going to be in your database, how you're going to generate your primary key, how you're going to make EOF interface with your stored procedure, how you're going to deal with the triggers, all this kind of information, well, it's time to build your model file to model this mapping between your database and your objects.
The first thing is spend time on your model file. Your model file is really important. That's what your application, that's what EOF is going to rely on to mess with your objects. So if there is something wrong in the model file, we are going to mess something wrong with your objects.
So make sure you click on all the inspector, you look all around, you understand all of the checkboxes, read the documentation. I've seen a bug from a customer once saying, "Hey, this thing is not working at all." And I was trying to reproduce it, and impossible to reproduce it.
I finally asked him, "Send me your model file and your database, and send me this huge thing in a mail attachment." And I looked at it, and I looked in the model file, and there was little checkbox like Propagate Primarii Key that was checked on one of the relationships.
And of course, nothing was working because he was trying to propagate Primarii Key, something that should not propagate. Just bad. So I told him, "Just take your model file, check out this thing. It's working just fine." And why did you check this thing? He said, "Oh, I don't know.
I just wanted to know what this thing was doing, so I just checked it." And so this is every single checkbox in this little box. So this little checkbox in this little panel is really important. If you check Propagate Primarii Key, you better know what this thing is doing, because otherwise you're going to get in trouble.
A good way to see if your relationships are good is we actually spend some time in the model file, in the stupid model file we have in our examples, the studio and movie, and the one you see in all the demos. The reason why you see them in all the demos is because they are actually good model files. You drop them in any demo, and your demo is going to work because the model file is well-constructed.
So what you can do is compare your relationships. If you have too many relationships, go look in the movie database, the relationship between the movie and talent for the directors of a movie, and see if the checkbox are the same way. If the checkbox are not the same way, if you have something slightly different, try to understand why.
Just go look at all these relationships everywhere in the example. I think we have all the possible relationships defined in our model file. We have too many, we have too one, we have one propagated primarities, we have optional to one, mandatory to one. I think we have almost everything.
Last but not least, do the demo. The direct to Java client demo that Andreas did. Just take the template for direct to Java client, drop your model in there, compile the thing, run the thing. If the application you get back looks good, there is a really good chance that your model is good. If the application you get back is showing some entities, some kind of relationships you don't expect there, if the query window contains all your entities, there is probably something wrong in the relationships.
Because the way direct to Java client works is it's analyzing your model and making guesses on what's good and not good based on the different relationships and how you specify the relationships. If they are optional, if they are not optional, etc. So that's a good way of validating. evaluating your model file.
And finally, once you have your database that's all set up, you have a model file to work with it, it's time to implement your logic. And implementing your logic, you have-- So, you have multiple choices. The first one is you do an EO generic record. It's just the data.
You don't need anything else in the data. So, that's fine. That's working in all cases. Second case is you want, you can use custom enterprise objects where you can actually build some logic in the implement methods. But when you subclass custom objects in Java and put your instance variable here, every time you change your model file or you change your database, that's change your model file, and then you want to change your enterprise object, it's going to, you are going to have to do some maintenance. Because you are going to have to add and remove all these instance variables and access all that stuff. So, in 4.5, I already talked about that.
yesterday, I think. You can subclass your generic record. It gives you less maintenance because you don't have to maintain all these instance variables. And it gives you better performance in Java because you don't have to cross a bridge with all your attributes all the time. So that's an example of a few EO generic record class.
I like, it's a personal preference, I like to have a public final string with a name, so I can use key value coding with no names. And this is the way you implement two accessors. You're not forced to implement your accessors, by the way. WebObjects and EOF, when they access your EOs, don't need the accessor, so you don't have to implement all the list of accessor. You know, if you have 30 attributes in your objects, you don't need to implement 60 methods and 30 final strings. You can just remove everything, unless you need it in your business logic to access it. Keeps the thing smaller if you don't put everything in there.
So, Eogenic Recur, you can see here this stored value for key and text stored value for key thingy. I want to talk a little more about this, because when EOF and WebObjects are using, accessing your object to put value into it, or to get value out of your object, we are using key value coding. And it's really important when you write your code to understand how key value coding is working.
This is actually a slide that's going to take a while. We have two ways of accessing your objects. We either use key value coding or we use stored key value coding. And for both of these ways to access your object, we have a get method and a set method, and different ways of finding all this information. So let's start with the simplest way. Key value coding, you know, your WebObjects application.
You have a binding in your UI that's bound to your display group and your object.name. WebObjects is going to use key value coding to get to your object. And what's it going to use? Well, it's going to look in your object and say, "Okay, what do we have in there? Is there a method name?" If there is no method name, it's going to look for an instance variable name, name.
If there is still nothing, it's going to try for underbar name as a method and underbar name as an instance variable. Fairly easy. By the way, this search is done only once, you know, once per class. We do the search and then we cache information and then we have this thing that, you know, you don't want to know.
So this is fast, even if it seems that it's doing a search, a search, a search, a search. This is plentiful fast. The set method is doing exactly the same thing. It's looking for a set method saying set name. It's doing-- it's looking for an instance variable name. It's looking for another set name and another name.
Same kind of search. Now, key value coding is used by WebObjects. WebObjects is using only key value coding. It's never using stored key value coding, because WebObjects is a user of your EO. It's just getting information from your EO, displaying it in the UI, and when the user changes something, it's putting back something in your EO. Stored key value coding is another beast. Stored key value coding is coming from the other side of your EO. This is something we use when we fetch data from the database and put it in your EO.
So this stored key value coding is used exclusively by EOF. It's mostly used when we snapshot. It's used when we fetch. It's used when there is anything that has to do with the persistence of the object. We use stored key value coding instead of using key value coding. So what are the differences between the two? Well, the differences are easy. It's just the order of the search.
We look for the underbar before looking for the real thing. And the same thing for the set method. So what does this give you? Imagine that in your object you have an instance variable name and a variable name. And you have a method name and a method setName.
So when you're going to fetch your data from the database, we're going to go straight to your instance variable. It's under the name. That's the first one I'm going to find. We're going to go straight to this instance variable, stuff the data in it, and that's it. Now when, and when you save the object, we are going to go straight to the instance variable again, get the data there, and save it to the database. Now that's different in key value coding because you have this method name and this method set name.
So that means that when WebObjects are going to access your object, or when any user is going to access your object, it's going to... to execute some of your code. So you can actually do something else in this code, because it's not going to impact the fetch performance, because the fetch performance is going to access the end-of-bar name first.
It's not going to go through your method. So in your method, you can enhance your business logic by putting some...
[Transcript missing]
By being careful, you can do some things that are in your access source that are executed only when a user is changing something, not when EOF is fetching.
Of course, you can change your behavior. You can say, oh, I don't want you to access my field directly, or I don't want to use stored access, or just always use key value coding and never use stored key value coding, and then EOF is going to behave the same way that WebObjects is. Little word of warning, again, WebObjects 5 for Java.
Key value coding is, the way we do it is we use the Objective-C runtime. So the way we do it in 4.5 is we use the Objective-C runtime. Even if you're on Java, we use the Objective-C runtime. That means that if you have a, you know, private string name, who cares about the private, right? Objective-C runtime, we just stuff the data in your private variable, no problem.
Well, we've gone pure Java. And pure Java, that's the thing interesting, is it has this security thing, and when you have a private thing, it's really private, you can't access it. So, and same thing for protected. If you are in a separate package and your instance variable is protected, well, we won't be able to access it with key value coding or stored key value coding or whatever. So, look at your EOs, actually look at your components, too. If you have anything that's private or protected, maybe key value coding won't be able to access it when you converge to WebObjects 5 or Java.
It's probably going to be covered by a reason or somewhere, because it's going to be an interesting problem. We have some solutions. You can put everything. For private, there is no solution. For private, it's private, we can't access it. For protected, we have some solutions that we can't access. Okay. So, we can, you know, run some loops around and do something there, but be aware of that.
Validate, validation, still implementing your logic, validation, validate name, or validate, you know, first name, validate whatever, validate salary. Just implement this method on your object, it's going to be called automatically when a WebObject is changing. Every time, it's going to be called automatically if WebObject is changing it, or display group is changing it.
In all other cases, it's not going to be validated. You see this WebObjects file for Java. You notice that my validate name is taking an object, not a string. Actually, I think that this build, now we can put a string in there. So, I should have removed this sticker because we actually fixed it. So, you can put string or you can put objects, and we're going to find the method.
The method ValidateForSave, ValidateForDelete, ValidateForInsert, by default, the three of them do exactly the same thing. They go to the model file, basically, and check, you know, everything you check on the model file, if it's mandatory, not mandatory, whatever. And it's also calling all these validate methods, validate name, and whatever.
You can override these methods on your EO. If you override them, call super, because if you don't call super, all the validation that's in your model file is never going to happen. And don't update your objects while you're doing a validation. You're validating something that somebody's passing you. You're not changing your object at that time. Changing your object is done in set name. And these three methods, ValidateForDelete, ValidateForInsert, are called at the end of the request-response loop. And ValidateForSave is, of course, called every time you press the save button in your editing context.
Other method you can implement on your EO, unable to set null for key. If in your database you have some kind of number or float, whatever, and in your EO you have a float or a double or something that you cannot put null in it, this method is going to be called on your EO. If this method doesn't exist, we are going to throw an exception. In this method, you can do the behavior you want. You can use another variable to note that this thing is actually null.
Interesting method also, AwakeFromInsertion. It's good every time you insert an object into an editing context. We call it AwakeFromInsertion. It's a good place to do all the initialization for your object. And finally, AwakeFromFetch. That's when we get your object from the database, we fetch it, we put it into your editing context, we call a wake from fetch when we're done with it.
You can use this awake from fetch method to set up, for example, derived value. If you have a customer object with a first name and last name and you want a full name accessor, in a wake from fetch, you can drill this full name. Actually, this is a bad example. I won't recommend that.
I would actually do that lazily, build a full name the first time somebody's asking for it. There is some interesting thing you can do in there. Methods you should not override, on the other hand, are probably willChange and willRead. willRead is used for faulting, and willChange is used to detect that you are maybe going to change a subject.
Maybe. That's not guaranteed. When will change is called, maybe the object is not going to change after all. So if you use will change to say, I've seen use of will change saying, "Okay, I'm going to override will change, and every time I receive a will change, I'm going to change a timestamp on my object, because my object is going to change, so I want the latest timestamp." This is actually not the right place to do it, because it's called sometimes when there is no changes at all.
I should go a little faster. I'm going to run out of time there. Reaction chip management. The only one method you should know about is addObject to both sides or ReactionChip with key. If you use anything else, you might run into trouble because if your model changes and you don't change your logic, you may get some kind of inconsistency.
This method is the only one that's taking care of everything. If you use this method everywhere, you're safe. You have the relationship, you don't have the relationship, the class properties, not the class properties, it's going to work in all cases. So it's a long method to type, but you have completion in Project Builder, so that's easy. You press F2 on Windows and Escape on Mac OS X server and it's just filling the blank. So please use this one.
[Transcript missing]
So that's it for the first part of our presentation. You know, how I see you should do a good EO. Start from the bottom. Start from the data. And build your EO model. Spend time on your EO model. Really important. Spend time on your EO model. Validate your EO model. Make sure that that is correct. Don't let your junior programmer go in there and click on all the check boxes, because you want to see what this thing is working. And the last thing you do is implement your logic.
You can, of course, cycle this thing. OK? It's not a rigid thing. You have to do it-- you know, I saw Eric on stage. He told me to do this, this, and this. No. You can cycle it. Just be careful when you cycle to keep everything in sync. And keep the thing in sync always from the top to the bottom.
There are some alternate ways of doing this. If you are starting fresh and writing an application and you have control over everything, you can start from the model file and then generate a database. But personally, I still prefer to start with the database, but that's probably a personal preference at this point.
So, let's move on to the new features in 4.5, the thing that might cause you trouble or might actually save your butt in some cases. First one, we talk about subclass EO generic record. I'm going to spend more time on it. It's giving you performance if you are in 4.5 using Java.
And it's giving, it's more flexible than the customer objects. It's less maintenance. And you ask for it. You know, raise your hands, the one who asked for subclass, subclassable EO generic record. That's it? Why did you bother? Okay. Eric Noyau Actually, I think maybe there was only one person, but he was really vocal then.
Important feature in 4.5: shared editing contexts. This is your regular WebObjects application with two editing contexts, two object graphs, as I should say, editing contexts. And what shared editing contexts introduce is a way to have another editing context that's in the middle and that contains some objects that are shared by all the other editing contexts in your application.
This shared editing context in the middle is read-only, because if you share data, you cannot change the data. Remember that every editing context on both sides may be running a different thread and these kind of things. So this data in the middle is read-only. No way to change it.
These objects in the middle also are only destinations of reaction chips. Because, you know, you should have a reaction chip going outside of the shared editing context to another editing context. Imagine that you have a reaction chip going from this blue object there to the purple editing context.
Now you're in the red editing context, and you follow the reaction chip, and you're like "Oh, I'm going to the blue object, and then I'm following this other reaction chip." And you do end up having an object graph that's spawning multiple editing contexts, and that's bad. You don't want to do that, ever.
Never, never. Don't do that. If you do it, you're going to have really big troubles and weird crashes and everything. So the idea is unique in scope change. From the EOF 2.0 to WebObjects 4.0.1, the unique in scope was an editing context. That was the end of the story. Now, the unique in scope changes the editing context plus its eventual shared editing context. The two together is your unique in scope. You have to be aware of it in some cases, but really if you're doing some weird things. Usually it's fairly transparent.
To put your objects into the shared editing context, there is a checkbox in your modeler. You can check to say, oh, this thing is shared, and that's it. And now, no matter where you fetch it, when you fetch it, it's going to be in the shared context. And that's going to be-- shared between all the editing contexts in your application everywhere. It's good for read-only data. It's good, for example, if you have a catalog app, you can put all your products in there and whoever is browsing your catalog application is reusing the same objects over and over again.
Third interesting feature: snapshot ref counting. We talked about it yesterday also. You fetch an object in an editing context, we create a snapshot down there. Now you fetch an object in another editing context, we now ref count this snapshot. And when the two objects are gone from memory, the snapshot is gone too.
It's just really simple. That's a feature you always thought was already in EOF, right? So, now it is. I'll help you reduce memory footprint, help you snapshot freshness, because if nobody's using any memory, it's gone. So next time you need it, you're going to refresh it, so it's going to be fresher.
A couple of little gotchas with this feature that are actually interesting. If you used to use global ID, actually these gotchas, this one applies only to Objective-C. If you used to use your global ID all the way around and passing global ID to move an object from one editing context to another, look at your code and make sure you retain it, because now global IDs are going away. Before they were never going away, but now they are.
I'm pointing this thing because actually we had the problem in our example framework. In the movie example, if you diff the 401 and the 405, you're going to see the bug. So be careful with that. And if your application assumes that because you fetch an object once, you have the snapshot down there, that's not true anymore. I don't think you should make assumptions like that anywhere. But if you do, be careful when you move to 4.5.
Next feature is actually the hardest to explain. It's a simple concept, but it's difficult to explain. So the yellow arrow up there at the top is a timeline going from the past to the future. Let's say I'm creating an editing context. So in my timeline, I have this proper editing context created there.
I fetch an object into this editing context. At the time of the fetch, EO Access is putting a timestamp on this snapshot, saying, "Hey, have we seen this snapshot from the database at that time?" And mark it, remember it. Now you create a second editing context and fetch an object into it.
So every editing context has a lag time. What we mean by lag time, the time of the creation of the editing context minus its lag time give us an absolute date. And from this absolute date, we determine if we can use a snapshot or not. If the snapshot we have in memory is after this absolute date, we are going to use it. If the snapshot we have in memory is before, we just are going to trash this snapshot and fetch the object again.
So here you can see that after this fetch, I snapshot at that time on the timeline, and then I created the second editing context. And the date that's giving me the absolute time is the date of the creation of the editing context. And in that case, we see that this object there is fine. It's in my time lag, so I'm going to reuse the snapshot.
Now if I create a third editing context here, You see the timeline again, and the lag time, and you see that the object is not in the lag time. So in that case, in this shared editing context, if I fetch the object, I'm going to actually refetch from the database, update the snapshot, and of course send the notification saying, "Object change in store," and update the object everywhere if the snapshot changes.
And re-put a new timestamp on this object, on this snapshot, so next time another editing context is going to need it, it's going to be there. So what does that mean? That means that every time you create a new editing context, you have the potential to refetch some objects from the database, because your editing context was created later.
So you can control the freshness of the data. The shorter the lag time you use for your editing context, the shorter lifespan your snapshots are going to have. That means that if you don't use the objects, if you don't fetch these objects really often, you are not going to update and generate all this freshness update all over the place.
We are going to fetch from the database only if you need it. And we are going to refresh only if you know, we know that when you're editing, your editing context knows it. And, um, It's also an easy way to get updated data. You want to update a certain graph of objects in your application.
Well, that's really easy. You create an editing context. You set its fetch timestamp to now. So you remove all the lag. So you create an editing context. You remove all the lag. You say, we fetch everything now. And you fetch the object graph you want to fetch. That's going to mean that you are going to update the snapshots at the bottom for every single object that you're fetching this new editing context.
And at the same time, refresh things in all your other editing contexts. So you can use this instead of fetch specification with the refreshing objects and all that. That's actually another way to perform the same task that I think is... It's actually a little cleaner, but it's possible only with 4.5.
Still following? Nobody's sleeping yet? Fine. Deferred faulting. Another 4.5 feature. This is a pre-4.5 application. You're fetching a bunch of objects. And what does happen when you fetch an object? You fetch the object, and then for every relationship around this object, we're creating a fault. Either a two-and fault, like I have in my little graphic there, or a too-many fault.
So that means that for, if your entity has something like, you know, 10 reaction chips, and you fetch 50 objects, well, you are going to create these 50 objects, and you are going to create another 500 objects around them. All right. So fetch performance is impacted by these kind of things. It's usually fine, but we have... To help the performance, it's actually a really good feature. Of course, it's a trade-off.
If we don't do that, that means that we don't have the transparency of, do you just follow a pointer and get information that's at the end of the pointer and having the fault firing for you? You would have to do, actually, something. So what's deferred faulting? Deferred faulting says, when you fetch an object and there is ten reaction chips, we are going to create one object per reaction chip.
No more. So if you fetch, if I take my example again, you have ten reaction chips and you fetch fifty objects, you are going to create your fifty objects, but you are only going to create ten objects for your reaction chips. And we are going to make every single EO that you fetch point to these shared objects. We call this shared object deferred fault. These objects are actually not faults. They are just a way to get a fault later.
And how does that work is when you need the destination of the relationship, before following the pointer, you ask this deferred fault, "Give me my real fault. Give me the thing I should have got when I fetched." And we have a new method to do that that's named WillReadReactionShip, and you pass yourself as an argument and you send that to the deferred fault, and you get the real fault.
This feature is optional. You don't have to implement it. It's giving you big advantages. It's giving you faster fetches, and it's less memory usage because you don't create all these objects all over the place. And the only method you should know to work with this is read-read relationship.
When I say it's optional, it's actually optional unless you use EOG. If you subclass EOG, EOG is using deferred faulting all over the place. But it's completely transparent for you because you don't have instance variable. You just access the dictionary of stored key value coding. And stored key value coding on EOG knows how to do these things. So it's completely transparent for you.
Another interesting side effect of this feature is inheritance. Remember inheritance, when you're pointing, when you're in Objective-C and you have a relationship to the top of an inheritance tree there. When we fetch your object, we create your relationship, but we don't know what kind of object is going to be at the end of our relationship.
It could be the top of an inheritance tree or anything below, any kind of object. So the way we do that in Objective-C is saying, "Hey, we don't know which object is going to be, so we're going to look at this hierarchy and create the largest piece of memory that could fit one of these objects and allocate this thing there." And then when we fire the fault, we are going to play some tricks with the Objective-C runtime, changing the ISA pointer to point to the right class and doing some insane things in there. And then we're going to actually get rid of all of that, because default faulting, you have a default fault, you don't have the real object.
So that means that when you're firing the fault, what we do if there is any inheritance involved, we are going to go fetch from the database the information and get the role before creating the object. So we know what objects we need to create. And the trick we are playing in Objective-C is actually not working at all in Java.
In Java, you just say object, new object, and that's the end of it. There's no way to change the ISA pointer and do all this magic that we used to do. So the only way in pure Java that inheritance is going to work, this way, via default faulting.
Another 4.5 feature, database reconnection. In 4.5, if you lose your connection to the database, we're going to try to reconnect automatically. A number of you asked for this thing. You can change the behavior. We have two delegates that you can use. You can, if there is, if we try, if we lose a connection to the database, before we try to reconnect, we ask you some questions saying, "Hey, should I try to reconnect to the same database, to another database, or do you want to handle the reconnection by yourself?" One thing you need to know is all these things assume that you're connecting to the same database. That means that we are not throwing away any snapshots. So if you're connecting to a different database, it's your responsibility to make sure that your snapshots match what are in the database so you don't have optimistic locking failure when you shouldn't have one.
We change the behavior of missing faults, coming back to how do you create an object. You fetch an object, and you have a fault to this. It's only for 2.1. You have a relationship to another object, and this object, when you fetch, you have a foreign key for it. So you are going to create-- we can create a global ID, create this thing, and say, OK, we need this object later. Here it is. And then you touch this subject. You go to the database, and this object's not there. Oops.
What happened in 4.0 and before was we just gave up and said, "Oh, you don't have these objects in the database. Your database isn't consistent. Too bad. Let's throw an exception." Problem with this exception, it was thrown all over the place. You don't know where to cache it. It could be while following something in your business logic. It could be while following a dot notation inside WebObjects, some kind of bindings. It was actually thrown all over the place. It was really, really hard to cache.
So in 4.5, we are not sending an exception when we discover these problems. We are just noting that there is a problem, and we send you an empty object. The exception is going to be thrown on save. If you try to save and don't do anything about this object, you're going to get an exception saying, "Hey, you're trying to save something, but your database was inconsistent in the first place, so deal with it." And you can, at this point, insert this new object and do everything.
You can use a delegate to control the behavior. Why did I put an S at delegate? It's the only one delegate you need to know for this is database context fail to fetch object. If you want the previous behavior, you can just throw an exception in there and that's it. You have the previous behavior. Or in this method, you can actually deal with the problem and say, oh, yeah, I'm missing this object. Let me go insert it into the database, refetch it, and do all that, and that's going to be fine.
4.5 feature, another one that's good. This one, I love it. On your adapter, your adapter context, your database context, you can call a method that's set default delegate. It's a class method. You call this once and you'll be done with it. You don't have to go phishing, tracking all the exit, or also notification, "Hey, I have created a new channel. Oh, geez, I need to be the delegate of this thing." Just one place and you're the delegate of everything. Yeah. I don't know why we didn't do that before. Just... probably two hours when I'm playing around with this thing everywhere. And it's just... it's a lifesaver.
Another 4.5 feature, LDAP adapter. A lot of requests for LDAP adapter. I think, hey, we want to access LDAP. We want to validate our user. We want to, you know, to have all these things. So now we have an LDAP adapter. Interesting feature, the LDAP adapters can read, update, delete.
It's an adapter. It's working like any other EO adapter in EOF. The interesting thing is you don't need a model file to do authentication. You don't need to build a big model file to do that. Authentication is actually a really simple protocol. The LDAP adapter has a static method that's authenticate user, and you pass its username, the password, and the information about, you know, all the LDAP thingy there.
What subtree, what, you know. And this thing is returning... What is this thing returning? Probably returning a Boolean. Yes, no. Is it true? Is it false? Can you... Is this user legitimate or not? So, the thing interesting is this is an interesting feature because it's really lightweight and you don't need a Neo model for it. And that's the most common use of the YieldApp adapter. So here we go. List of all the five features I went over. I don't think it's complete. It's probably missing a couple, but these are the most important ones in EOF.
That's a... I want to, before I finish this thing, I want to stress one thing that I've seen done over and over and over again. And I'd like to I don't know, try to influence you in not doing these things again. I've seen a lot of our customers trying to force EOF to work in the way they think EOF should work.
And it's, you know, you think, oh, EOF should work this way, so, you know, no, EOF is working this way, so I'm writing my code thinking that EOF is working this way, and then I come to the conclusion, after a while, I say, hey, this is not working like this at all. Oh, Jesus, it was working this other way. And instead of trying to fit with EOF, what you're trying to do is, you know, coerce EOF into coming there and work the way I want it to work, damn it, you know.
Eric Noyau After that, a couple of months later, I sit in my office. I receive an email from support telling me, "I have this weird bug and I don't understand it." I look at the bug, can't reproduce it, don't know anything, and then they say, "Send me an example." Well, it's the whole customer application, it's 20 meg of stuff, and you do end up trying to find to reproduce this thing, and you do end up finding that it's because you try to coerce this thing into working the way you think it should work and not try to use it the way it worked.
By doing that, you're going to introduce bugs and it's going to be impossible for us to fix them because it's actually in your code. So message, work with EOF, not against it. Just try to understand how you can use it the way it is working and try to play with EOF.
There is a lot of room to play with EOF. We have delegates everywhere. We have a lot of ropes that you can hang yourself with. You don't need to do your stuff to hang yourself with. You can just use EOF the way it was intended to be and you can eat yourself with it. So take that as a message. Please try to work with it. Try to understand how EOF is working. EOF is really powerful. There was a lot of features. There was a lot of features. There was a lot of features in it.
If you think there is something that EOF is not doing, well, talk to somebody else. Maybe he's going to tell you a different view. There is always ten ways of doing something. And there is these ten ways. There is three that are going to work well with EOF and there is seven that are not going to work well with EOF. Try to use the three that are going to work with EOF. And that's it.