Search code examples
c#ef-code-first

Is it possible that two different classes have a property -a collection of classes and each object knows which of the first two classes it belongs to?


I have next 3 classes

class Review
{
   public int Id{get; set;}
   public string Text{get; set;}
   public ICollection<Comment> Comments{get; set;}
//some additional properties
}
class User
{
   public int Id{get; set;}
   public string Name{get; set;}
   public string Login{get; set;}
   public ICollection<Comment> Comments{get; set;}
//some additional properties
}
class Comment
{
   public int Id{get; set}
   public string Comment{get; set;}
   public ??? Target{get; set;}
}

In this context, a Target is what the comment was attached to. And for some things, I need to know exactly who the target is - a specific user or a specific review. And inheriting from the interface is not suitable due to the strong distinction in the parameters. And i need to use database so object type not for that kind of situation(as i know).


Solution

  • From the code provided you can use object or dynamic for Target.

    But you may prefer using a base class for Review and User like BaseObjectWithComments to be able to write BaseObjectWithComments Target, which is a little better.

    So we can move some members to this root class.

    Also we can add a constructor for Comment to pass the owner.

    public abstract class BaseObjectWithIdAndComments
    {
      public int ID { get; set; }
      public ICollection<Comment> Comments { get; set; }
    }
    
    public class Review : BaseObjectWithIdAndComments
    {
      public string Text { get; set; }
    }
    
    public class User : BaseObjectWithIdAndComments
    {
      public string Name { get; set; }
      public string Login { get; set; }
    }
    
    public class Comment
    {
      public int ID { get; set; }
      public string Text { get; set; }
      public BaseObjectWithIdAndComments Target { get; set; }
      public Comment(BaseObjectWithIdAndComments owner, int id, string comment)
      {
        Target = owner;
        ID = id;
        Text = comment;
      }
    }
    

    Test

    var review = new Review();
    var user = new User();
    
    review.Comments = new List<Comment>();
    user.Comments = new List<Comment>();
    
    review.Comments.Add(new Comment(review, 1, "review comment 1"));
    review.Comments.Add(new Comment(review, 2, "review comment 2"));
    
    user.Comments.Add(new Comment(user, 1, "user comment 1"));
    user.Comments.Add(new Comment(user, 2, "user comment 2"));
    
    Console.WriteLine("Owner of review comment #1: " + review.Comments.ElementAt(0).Target.GetType().Name);
    Console.WriteLine("Owner of user comment #2: " + user.Comments.ElementAt(1).Target.GetType().Name);
    

    Output

    Owner of review comment #1: Review
    Owner of user comment #2: User
    

    About using a database, you need to change the design.

    For example the fields of the table may be like:

    CommentID
    ReviewID
    UserID
    Text
    

    But this is not clean, so you may prefer to have 2 tables to be more conventionnal: UserComments and ReviewComments, thus each of these tables will have a OwnerID pointing to Users or Reviews.

    Thus you can load data in the instances of the previous classes while setting the owner reference as indicated.

    enter image description here

    Maybe you can consider using an ADO.NET typed DataSet that does all the work for you while being able to use Visual Studio RAD Designers:

    Typed DataSets (MS Docs)

    How to: Create and configure datasets in Visual Studio (MS Docs)

    Beginning C# 2005 Databases (Wrox)