1

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#

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
datavinci
  • 795
  • 2
  • 7
  • 27
  • If you set the AuthorId on the author object, and then set the Author variable = to the author object, the book object would then contain an author object that has the AuthorId set to the value you put in Author-AuthorId. Is this what you are asking? – Jeremy Armstrong Aug 07 '16 at 15:03
  • I am asking to replicate the functionality of foreign key of sql in C#. That is how to use a variable of one class in another one. – datavinci Aug 07 '16 at 15:05
  • @DiscoDancer Check my answer, I believe it should clarify your doubts about how to design in OOP world ;) – Matías Fidemraizer Aug 07 '16 at 16:04

2 Answers2

5

Your Book object could have a reference to the Author inside the class, as shown below.

public class Author
{
    public int AuthorId { get; set; }
    public string AuthorName { get; set; }
}

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

   public Book(Author author)
   {
     _author = author;
   }

   public void PrintBookAuthor()
   {
     Console.WriteLine(_author.AuthorName);
   }
}

Then to setup:

Author author = new Author();
author.AuthorName = "Darren Davies";

Book programmingBook = new Book(author);
programmingBook.PrintBookAuthor();
Darren
  • 68,902
  • 24
  • 138
  • 144
  • i dont want to use the variable in the class constructor but outside it.How to do it? – datavinci Aug 07 '16 at 15:07
  • @DiscoDancer - you could change the access modifier to `public` rather than `private` and access the `author` object directly from the `Book` class, but IMO this breaks encapsulation. – Darren Aug 07 '16 at 15:09
  • Like this -->>public Author _author { get; set; } -->>public _author.AuthorId {get; set;} .....?? – datavinci Aug 07 '16 at 15:10
  • @DiscoDancer - yes. If you are making it public, it could be renamed to `Author` rather than `_author` to conform to C# naming conventions. – Darren Aug 07 '16 at 15:11
  • Its showing error that _author is not an interface when i write -->>public _author.AuthorId {get; set;} – datavinci Aug 07 '16 at 15:15
  • @DiscoDancer - it should be `public Author Author { get; set; }` - You will also have to set this variable when you instantiate your `Book` object. – Darren Aug 07 '16 at 15:18
  • int Author.AuthorId { get; set; } -->> showing error – datavinci Aug 07 '16 at 15:26
  • @DiscoDancer - because Author.AuthorId is not a valid property name. Please read comment above and look at the answer I've provided. – Darren Aug 07 '16 at 15:27
  • @DarrenDavies Private properties starting with `_` isn't a .NET convention. Property identifiers are homogeneous independently of property's access modifier :/ – Matías Fidemraizer Aug 07 '16 at 15:53
2

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).

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Hey nice and informative answer.But i have one doubt regarding this. 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. – datavinci Aug 07 '16 at 16:27
  • @DiscoDancer You can use interfaces to hide information. Let me update the answer to explain it better, hold 5 minutes :) – Matías Fidemraizer Aug 07 '16 at 16:52
  • @DiscoDancer Ok see the update at the bottom of the answer – Matías Fidemraizer Aug 07 '16 at 17:02
  • hey i also found out that if set other properties to private,you cant access.Do u see any advantages of your method of interfaces against the use of this private keyword? – datavinci Aug 07 '16 at 19:48
  • @DiscoDancer The problem with private properties is that you won't be able to set them outside the whole class... – Matías Fidemraizer Aug 07 '16 at 22:23