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 may have transcription errors.
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. uh... i want to talk about uh... i don't see a way of uh... so what is that don't see it uh... something like a month ago uh... somebody came up uh... into my uh... into my office and say hey you're going to have a talk at the breed of the ceiling to talk about that don't see what i can say okay what am i going to talk about and say oh that's your problem you know sets and don't see you left you know you're the advanced u_f_ guy did with it So I took a piece of paper and started, you know, jotting notes on it and say, OK, 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 customer doing. I can talk about all the features in UF. We have plenty of features. And I went to see the other member of the team and ask, 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 web objects demo, you know. You see the demo is always starting, oh, I have this model file somewhere on my disk, you know, 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. going to take half of my time. And the second thing I want to talk about is about the new feature 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 pretty good.
So let's start. How to design a good U? 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 UF. But we know what real life is, and you have to integrate with what's already there, what exists, 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 UF, 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. I'm sorry.
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-- 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 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 thing.
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 key, 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 handle it. Just you know, if you have, if you're in Oracle, that's a sequence. If you have a 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 in its data, some kind of blob value. On the application side, you make this in NSData, and you make it exactly 12 bytes long. What's going to happen there is WebObjects.uf 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, so it's way faster. You notice my stump here, WebLogix 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. Third 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 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, 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 UF 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 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 check boxes, 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 primarkey that was checked on one of the ration chips. And of course nothing was working because he was trying to propagate primarkey, 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.
Just wanted to know what this thing... I didn't know what this thing was doing, so just checked it." So this is-- every single check box in this little panel is really important. If you check propagate from RT, 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. We have examples of 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 modified 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 checkbooks are the same way. If the checkbooks 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 relationship 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. And last but not least, do the demo. You know the direct to Java client demo that Andreas did. Just take the template for direct to Java client, drop your model in there, compile thing, run the thing. And 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 directory-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. You know, if they are optional, if they are not optional, etc. So that's a good way of validating your model file. Thank you. 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 multiple choices. The first one is you do an aerogeneric 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 object in Java and put your instance variable here, you are, every time you change your model file or you you change your database, that's change your model file, and then you want to change your enterprise object, you are going to have to do some maintenance, because you are going to have to add and remove all these instance variables and accessor and 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. Web objects and EOF, when they access your EOs, don't need the accessor. So you don't have to implement all the list of accessors. 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, Eugenic record, 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 accessing your object to put value into it, or to get value out of your object, we are using key value coding. It's really important when you write your code to understand how key value coding is working.
This is actually-- this is going to-- the 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, your WebObjects application, When 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 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 difference between the two? Well, the difference are easy. That'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 set name.
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. 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 WebObject is 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 our name first. It's not going to go through your method. So in your method, you can enhance your business logic by putting some... some kind of behavior when you do the set name. You can imagine in set name changing a timestamp on your object to set the latest time that your object was changed or anything like that. So you can use this in your business logic. And this is something that most people are not aware of.
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 the EOF is going to behave the same way than WebObjects is. Little word of warning. Again, WebObjects 5 for Java.
So, 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? The 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 they have this security thing, and when you have a private thing, it's really private, 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 WebObjects5 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 solution that we can, you know, run some loops around and do something there, But be aware of that.
Validation, still implementing your logic. Validation, validate name or validate first name, validate whatever, validate salary. Just implement this method on your object, it's going to be called automatically when a web object is changing. Every time it's going to be called automatically if web object 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 is good. 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, validateName 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 and your modified 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 method, validate for delete, validate for insert, I call it at the end of the request response loop. And validate for save is, of course, called every time you press 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. And 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, the right 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. But 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 to let this 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 add object to both side or reaction chip with key. If you use anything else, you might run into trouble because if your model change 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. It's a class property. It's not a class property. 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 just filling the blank. So please use this one.
I don't have time to go into that. Keep your EOs clean. Don't put EU access specific code in there. Don't put WebObject specific code in there. Because if you do that, one day you're going to regret it. If you have your EO on the server using WebObjects, and you put some WebObject specific code that you tie this thing with your component and whatever, and then months later you have your dear manager coming and say, hey, you know, we need the Java client look cool. I saw that WWDC. I want this thing in Java client tomorrow, all right?
And if you have WebObjects code in there, you won't be able to do it. Because in Java client, on the client side, there is no WebObjects. You just have UF, right? And you don't have U access either. You have U distribution. So keep these things separate. Everything you need for Neo is inside Neo Controls. The only one exception that I can agree on is the EU Utilities. EU Utilities is actually in EU Access and is bringing things that are used pretty, that's things, common things, back, back to your EO. So you can eventually use EO utilities. We have an EO utility in Java Client 2 that's working differently, it's working with EO distribution instead of working with, with U-axis.
So that's it for the first part of our presentation. 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 they 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. It's not a rigid thing. You have to do it-- I saw Eric on stage. He told me to do this, this, and this. No. You can cycle. 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 is 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 eogeneric 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 more flexible than the customer object. It's less maintenance. And you ask for it. Raise your hands, the one who asked for subclassable eogeneric record. That's it? Why did you bother? OK. Actually, I think maybe there was only one person, but he was really vocal then.
Important feature in 4.5, shared editing context. This is your regular WebObjects application with two editing contexts, two object graph, as I should say, editing context. And what shared editing contexts introduce is a way to have another editing context that's in the middle and that contain 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 destination of reaction ships. Because you should have a reaction ship going outside of the shared editing context to another editing context. And imagine that you have something, the reaction ship going from this blue object there to the purple editing context. Now you're in the red editing context and you follow the reaction ship and, "Oh, I'm going to the blue object," and then following this other reaction ship, and you do end up having an object graph that's spawning multiple analytic 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 you need to scope change. In -- from the 202 -- UF202 WebObjects 4.01, 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 leading 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 adding context 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. Talked about it yesterday also. You fetch an object in an editing context, we create the 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, this actually, these gotchas, this one apply 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 ending context to another, you know, 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. And 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. And let's say I'm creating an editing context. So in my timeline, I have this proper editing context created there. Now-- I fetch an object into this editing context. At the time of the fetch, EU 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 third leading 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, oh, object change in store, and update the object everywhere if the snapshot change.
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 that when you're editing context knows it and uh... 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 objects 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 useful. is actually a little cleaner, but it's possible only with 4.5.
Still following? Nobody's sleeping yet? Fine. Different 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 2-1 fault, like I have in my little graphic there, or too many faults.
So that means that if your entity has something like 10 relationships, 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. So fetch performance is impacted by these kind of things. It's usually fine, but we have-- to add to the performance is 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 in a pointer and get information that's at the end of a pointer and having the fault firing for you? You would have to do actually something. So what's default faulting? Default faulting says when you fetch an object and there is 10 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 10 reaction chips and you fetch 50 objects, you are going to create your 50 objects, but you only are going to create 10 objects for your reaction chips. And we're 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 fault. 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 default fault, give me my real fault. Give me the thing I should have got when I fetch. 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 default 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 it is read-read relationship.
When I say it's optional, it's actually optional unless you use EOGenericRecord. If you subclass EOGenericRecord, EOGenericRecord 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 with the stored key value coding. And stored key value coding on EOGenericRecord 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, you know, 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 are going to create-- 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 pointer to point to the right class and doing some insane things in there. And default faulting actually gets 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 tricks, the trick we are playing in Objective-C is actually not working at all in Java. In Java, you just say object, new object, 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 deferred 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.
Number of you ask 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 database, before we try to reconnect, we ask you some questions saying, Should I try to reconnect to the same database, to another database? 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. Could be while following something in your business logic, could be while following a dot notation inside Web Objects, 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 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 the delegate to control the behavior. Why did I put an S at delegate? 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, we fetch it, and do all that. And that's going to be fine.
Four-five 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 on this thing everywhere. And it's just, it's a lifesaver. What?
Another for five feature, LDAP adapter. Lot of requests for LDAP adapter. Hey, we want to access LDAP. We want to validate our user. We want to have all these things. So now we have an LDAP adapter. Interesting feature, the LDAP adapters can read the date, 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. So the LDAP adapter has a static method that's authenticate user, and you pass its username, password and the information about you know told you that thingy there what's up for you 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? 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-- 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, is, I've seen a lot of our customers trying to force EOF to work in the way they think EOF should work.
And you think, oh, EOF should work this way. So 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 coerce EOF into coming there and work the way I want it to work. Damn it.
And after that, you know, a couple of months later, we received, I sit in my office, I received an email from support telling me, you know, I have this weird bug and I don't understand it. So I look at the bug, can't reproduce it, I don't know anything. And then they said, "Send me an example." Well, you know, 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 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. And 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, right? So message, work with EOF, not against it. try to understand how EOF is working and try to play with EOF. There is a lot of room to play with EOF. So 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 is 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 the EOF. That's it. Thank you.