Source Code

Entity Framework 5 Code First Relationships

One to Zero or Many

Our hero see his pencils in a new light.

“Take me to your reading room,” commanded the Professor. “We shall eat en route.”

Edward’s room was modest. He was too young to have acquired many items, but he hoped someday to study something so interesting that he’d have to build an addition. For now, he just had a desk, some chairs and a couch. Plus, his framed mosaic of his favorite authors.

“Yes, yes. Quite nice, though it lacks some fire. We’ll see if we can’t kindle you, eh?”

The Professor laughed to himself. Apparently this was a joke only he understood. He suddenly stepped to the desk.

“See? Here?”

Edward timidly shook his head.

“Your pencils, my boy. How many?”

“Three. Sir.”

Professor Relvar picked them up, scrutinizing. “Good quality wood. Decent whittling. Proud of your work?”

“Yes, I guess so. I’ve seen nicer. My dad’s are fantastic!”

“Just so! Just so! We can appreciate our work while being modest. Have you considered this remarkable object? We value them highly, teaching everyone how to whittle and assemble their own pencils. Works of art, some people’s. Ms. Turner turns out terrific ones--or so she tongue-twistingly intones. Would you buy a pre-made pencil? Of course not! You dream of making your own. We’re all the same in this way. The pencil is today’s subject.”

Everyone, [he continued, sitting behind the desk], can have a Pencil. Not everyone does, and, while I personally don’t understand them, many people have done great work without a pencil. So, a person can whittle and own zero or more pencils. But a pencil always belongs to just one person. This is called a One to Zero or Many relationship, and it is very common. In fact, it may be the most common relationship.

Here is how we’ll model it:

LearingEFSchema.cs

public class Person...
...
//Navigation
public virtual ICollection<LibraryCard> LibraryCards { get; set; }
public virtual ICollection<Magnifier> Magnifiers { get; set; }
public virtual ICollection<Pencil> Pencils { get; set; }

public Person()
{
    LibraryCards = new HashSet<LibraryCard>();
    Magnifiers = new HashSet<Magnifier>();
    Pencils = new HashSet<Pencil>();
}

public class Pencil
{
    //Primary Key
    public int PencilId { get; set; }
    [Required(AllowEmptyStrings = true)]
    public string Nickname { get; set; }
    //Foreign Key column
    public int PersonId { get; set; }

    //Navigation
    public virtual Person Person { get; set; }

    public Pencil()
    {
        Nickname = "";
    }
}

LearningEFDb.cs

public class LearningEFDb: DbContext
 {
     public DbSet<LibraryCard> LibraryCards { get; set; }
     public DbSet<Magnifier> Magnifiers { get; set; }
     public DbSet<Pencil> Pencils { get; set; }
     public DbSet<Person> Persons { get; set; }

We introduce one new wrinkle, today. We’re requiring a Nickname, and yet we’re not! We allow an empty string. Why, you may ask?

[The Professor waited patiently until Edward sheepishly asked, “Why, Professor?”]

I’m so glad you asked. Many fields should not allow nulls. Names are a good example. Let’s say we stored first, middle and last names in nullable table columns. To concatenate them and display the full name, we would have to convert nulls to empty strings, otherwise the full name would become null. I’m sure there’s something philosophical to say about how objects added to a void becoming the void, but that isn’t my field.

Let’s add to our program and try to set a pencil’s nickname to null.

Program.cs

Console.WriteLine("Add/save Pencil setting Nickname to null.");
Pencil pencil = new Pencil() { Nickname = null, Person = edward };
_db.Pencils.Add(pencil);
SaveChanges();
Console.WriteLine("Set Nickname to empty string and save");
pencil.Nickname = "";
SaveChanges();

Console.WriteLine("Retrieve pencil, change Nickname, save");
pencil = _db.Pencils.First();
Console.WriteLine("Pencil: " + pencil.Nickname + ", Person: " + pencil.Person.Name);
pencil.Nickname = "Blue";
SaveChanges();
pencil = _db.Pencils.First();
Console.WriteLine("Pencil: " + pencil.Nickname + ", Person: " + pencil.Person.Name);

Running the program now produces a Pencils table like so:

T-SQL

create table Pencils (
 PencilId int not null identity primary key,
 Nickname nvarchar(max) not null,
 PersonId int not null foreign key references Persons(PersonId) 
)

And produces the following output:

Create Person without a name.
Saving changes.
  ERROR: The Name field is required.
Add the required name and Library Card and save.
Saving changes.
Successful save.
Get the record we just saved, and display.
Person: Edward Farley has card: 123
Create and save Magnifier with required serial number
Saving changes.
Successful save.
Retrieve Magnifier, show it doesn't belong to someone.
Magnifier: Bar123, Person: available
Edward gets the Magnifier. Save and retrieve.
Saving changes.
Successful save.
Magnifier: Bar123, Person: Edward Farley
Try to add duplicate magnifier
Saving changes.
  ERROR: Magnifier with this serial nbr already exists.
Add/save Pencil setting Nickname to null.
Saving changes.
  ERROR: The Nickname field is required.
Set Nickname to empty string and save
Saving changes.
Successful save.
Retrieve pencil, change Nickname, save
Pencil: , Person: Edward Farley
Saving changes.
Successful save.
Pencil: Blackwing, Person: Edward Farley
Finished

Tomorrow, Edward, we’ll meet here. Do not keep me waiting! That’s simply bad manners. Now, what are you grinning at?


Sunyata (Void-ness)
Vocabulary of Interlinked Datasets
Blackwing Pencil