none
Method with two classes as parameters RRS feed

  • Question

  • Hi,
    how can I write a method that uses classes (T Generic class with Context class)?

    I have two classes:

    class Reminders
    {
        [Key]
        public int ReminderId { get; set; }
        public string ReminderContent { get; set; }
    }
    class RemindersContext : DbContext 
    { /* Rest of the code */ }
    
    class HistoryReminders
    {
        [Key]
        public int HistoryId { get; set; }
        public int ReminderId { get; set; }
        public string ReminderHistoryContent { get; set; }
    }
    class HistoryContext : DbContext
    { /* Rest */}

    I would like to get data by primary key using one method.
    I have this method, but I want to avoid copy and paste of the code for another class:

    static List<HistoryReminders> GetDataHistoryRemindersById(int rowId)
    {
        var list = new List<HistoryReminders>();
        using (var ctx = new HistoryContext())
        {
            // for speed up
            ctx.Configuration.ProxyCreationEnabled = false;
            foreach (var item in ctx.DbHistoryReminders)
            {
                if (item.HistoryId == rowId)
                {
                    list.Add(new HistoryReminders
                    {
                        HistoryId = item.HistoryId,
                        ReminderId = item.ReminderId,
                        ReminderHistoryContent = item.ReminderHistoryContent,
                        DateReminderExecuted = item.DateReminderExecuted
                    });
                }
            }
        }
        return list;
    

    One more question is - is it a good practice to create a such method using classes as a parameters?

    Thursday, October 4, 2018 8:29 AM

Answers

  • This is really an EF question, not a C# one. We'll move your question.

    EF already supports finding an object by its primary key so you don't really need a generic method unless you want to do other things. At this point though there are multiple approaches you could take depending upon how flexible you are.

    In your code you have 2 different DbContext objects. Are you using DDD or something such that you have different contexts as needed? In general you won't have a separate context for each entity in your system, you'll have 1 per app context and it will contain all the related tables.

    The next question would be, can you change the POCOs you're using? Given that both of your POCOs share a common set of data I would recommend having one inherit from the other (e.g. HistoryReminders inherits from Reminders). Then you can define an extension method that works with Reminders and cover  both types.

    I think you're going to be hard pressed to create a generic method that accepts the types and context types and does anything generic because there is no relationship between the context types at this point. So without making a (really not) generic method that uses arbitrary expressions to get to the context-specific logic then your generic method isn't going to work. You could of course throw in interfaces but that is adding a layer to try to solve a problem that shouldn't really exist.

    So, given your method how would you see it working for both types? It takes a HistoryId (which only HistoryReminders has) and returns back the matches. What would that mean for just Reminders?

    BTW this can be done far more efficiently in LINQ. Your code requires the entire table to be brought back to your code and then you copy the items into yet another object. Aren't they the same types?

    //GetDataHistoryRemindersById as a simple LINQ query
    ctx.DbHistoryReminders.Where(x => x.HistoryId == rowId).ToList();

    Converting that to a helper method like you originally had on some other type (since it clearly isn't a method on the context itself.

    static List<HistoryReminders> GetDataHistoryRemindersById ( int rowId )
    {
       //This really isn't a good idea, the context lifetime
       //probably shouldn't be controlled by a method, consider
       //making this an extension method on the context itself
       using (var ctx = new HistoryContext())
       {
          ctx.Configuration.ProxyCreationEnabled = false;
    
          return ctx.DbHistoryReminders.Where(x.HistoryId == rowId).ToList();
       };
    }



    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by bobis123 Thursday, October 4, 2018 6:21 PM
    Thursday, October 4, 2018 2:01 PM
    Moderator

All replies

  • Hello,

    If I do understand you correctly you need to replace

    class HistoryContext : DbContext { ... }

    with

    class HistoryContext : MyContext {}
    
    class MyContext : DbContext
    {
    protected virtual YourMethod() {}
    }


    Sincerely, Highly skilled coding monkey.

    Thursday, October 4, 2018 8:46 AM
  • I will look later into your suggestion using virtual.

    In my question firstly I thought like this:

    // usage would be: var listReminderById = List<Reminders> GetData<Reminders>(2); // usage would be: var listHistoryReminderById = List<HistoryReminders> GetData<HistoryReminders>(3);

    static List<T> GetData<T>(T value, int rowId) //pseudo code { var list = new List<T>(); using (var ctx = new <T>(HistoryContext)) { (...) } return list; }



    • Edited by bobis123 Thursday, October 4, 2018 9:22 AM p
    Thursday, October 4, 2018 9:07 AM
  • This is really an EF question, not a C# one. We'll move your question.

    EF already supports finding an object by its primary key so you don't really need a generic method unless you want to do other things. At this point though there are multiple approaches you could take depending upon how flexible you are.

    In your code you have 2 different DbContext objects. Are you using DDD or something such that you have different contexts as needed? In general you won't have a separate context for each entity in your system, you'll have 1 per app context and it will contain all the related tables.

    The next question would be, can you change the POCOs you're using? Given that both of your POCOs share a common set of data I would recommend having one inherit from the other (e.g. HistoryReminders inherits from Reminders). Then you can define an extension method that works with Reminders and cover  both types.

    I think you're going to be hard pressed to create a generic method that accepts the types and context types and does anything generic because there is no relationship between the context types at this point. So without making a (really not) generic method that uses arbitrary expressions to get to the context-specific logic then your generic method isn't going to work. You could of course throw in interfaces but that is adding a layer to try to solve a problem that shouldn't really exist.

    So, given your method how would you see it working for both types? It takes a HistoryId (which only HistoryReminders has) and returns back the matches. What would that mean for just Reminders?

    BTW this can be done far more efficiently in LINQ. Your code requires the entire table to be brought back to your code and then you copy the items into yet another object. Aren't they the same types?

    //GetDataHistoryRemindersById as a simple LINQ query
    ctx.DbHistoryReminders.Where(x => x.HistoryId == rowId).ToList();

    Converting that to a helper method like you originally had on some other type (since it clearly isn't a method on the context itself.

    static List<HistoryReminders> GetDataHistoryRemindersById ( int rowId )
    {
       //This really isn't a good idea, the context lifetime
       //probably shouldn't be controlled by a method, consider
       //making this an extension method on the context itself
       using (var ctx = new HistoryContext())
       {
          ctx.Configuration.ProxyCreationEnabled = false;
    
          return ctx.DbHistoryReminders.Where(x.HistoryId == rowId).ToList();
       };
    }



    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by bobis123 Thursday, October 4, 2018 6:21 PM
    Thursday, October 4, 2018 2:01 PM
    Moderator
  • Hi,

    I don’t have good knowledge in EF, so I’m in learning phase.

    That's why I posted the question first time in "Learning - Small Basic." section,
    but others told me to move it here.

    Anyway, you are correct about POCO classes, I could use inheritance, I forgot.
    And I will listen to your advice and expand the context class, making an extension method.
    And make use of linq.

    Thank you!

    Thursday, October 4, 2018 6:21 PM