Disco Dancer Disco Dancer - 2 months ago 6
C# Question

Define a variable of one class from another class

So following is the set up of different classes that I need to create:

Author – AuthorId, AuthorName, DateOfBirth, State, City, Phone.
Publisher – PublisherId, PublisherName, DateOfBirth, State, City, Phone.
Category – CategoryId, CategoryName, Description.
Book – BookId, Category, Title, Author, Publisher, Description, Price, ISBN, PublicationDate.

Now as you can see Author in Book and AuthorId in Author classes are the same.How to achieve this in C#


First of all, you need to distinguish relational design from object-oriented design.

Object-oriented programming (from now just OOP) isn't relational but hierarchical, thus, there's no concept of foreign key.

Also, in OOP there're two kinds of relations between objects:

  • Inheritance. If you've implemented two classes A and B and you can say that B is A, then you need to use inheritance. For example, a Cat is an Animal.
  • Composition. If you've implemented two classes A and B and you can say that A has a B, then you need to use composition. For example, a Car has a Wheel.

Now take these rules and try to apply them to your particular case:

  • A Book has an Author. Bingo! You need to use composition.

Composition is expressed by declaring a property of the class that's owned by the enclosing type.

In your case:

public class Book
     public Author Author { get; set; }

While the following code sample would be wrong:

public class Book
    public int AuthorId { get; set; }

...because OOP is hierarchical, thus, you don't search the author associated to the Book, but you traverse Book to get Author's information.

In other words, in OOP your foreign key is an object reference to the associated object.

Let's see a summary of how to do things in the right way in OOP when you want to get the Author of a given Book:

BookRepository bookRepo = new BookRepository();
Book book = bookRepo.GetById(302);
Author author = book.Author;

Now let's see a wrong sample:

BookRepository bookRepo = new BookRepository();
Book book = bookRepo.GetById(302);

AuthorRepository authorRepo = new AuthorRepository();
Author author = authorRepo.GetById(book.AuthorId);

Don't you feel that last wrong sample doesn't feel natural in OOP world? Why you need to perform an additional query to get the whole Author object? This feels very relational!

In the other hand, there's nothing wrong with associating an unique identifier to Author or any object, because you need to uniquely distinguish each one from others, and, in addition, the underlying data storage might by relational and may need to store and retrieve objects based on their primary key/foreign key.

OP has also asked on some comment...

What if I only want to give the book object access only to authorid and nothing else. Because by this method I am able to access all of author's elements.

Welcome to the world of interfaces. One of their use cases is publishing information. Or, in other words, publishing just what you want to publish:

public interface IUniquelyIdentifiable
     int Id { get; set; }

public class Author : IUniquelyIdentifiable
     public int Id { get; set; }
     // ...and the rest of properties

Now you just need to associate IUniquelyIdentifiable to Book instead of Author:

public class Book
     public IUniquelyIdentifiable Author { get; set; }

...and you can still set a full Author on Book:

Book book = new Book();
book.Author = new Author();

This will hide everything excepting Author.Id, while in some parts of your code you can cast IUniquelyIdentifiable to Author:

// It'll set null to the whole variable if the 
// implementation of IUniquelyIdentifiable isn't Author
Author author = book.Author as Author;

BTW you need to be cautious if you're going to use an OR/M, because it may be harder to map your object model to the target relational model.

IMHO, as a general rule, I wouldn't hide object properties for objects that can be persistent (i.e. those that can be saved to a database).