1

I'm writing a POCO generator library using EF Core 3 for .NET Standard 2.0. This library will be used to generate the .cs files via T4 templates in .NET Framework and .NET Core projects.

I've created a wrapper class that stores static functions for all your typical LINQ queries like .Where, .FirstOrDefault, etc.

Here's an example:

public abstract class QueryableTable<T> where T : QueryableTable<T>, new()
{
    public static Func<DatabaseContext, bool, IQueryable<T>> QueryInitializer;

    public static List<T> Where(Expression<Func<T, bool>> predicate, bool eagerLoad = false)
    {
        using (var context = new DatabaseContext())
        {
            return QueryInitializer(context, eagerLoad).Where(predicate).ToList();
        }
    }
}

Now in my model, I use a static constructor to initialize the QueryInitializer within QueryableTable as shown here:

[Table("comment")]
public class Comment : QueryableTable<Comment>
{
    [Key]
    public int Id { get; set; }
 
    public int PersonId { get; set; }

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

    static Comment()
    {
        QueryableTable<Comment>.QueryInitializer = (context, eagerLoad) => 
        {
            return eagerLoad ? 
                context.Set<Comment>().Include(t => t.Person) as IQueryable<Comment> :
                context.Set<Comment>();
        };
    }
}

This works if I call the static Comment constructor prior to accessing the abstract class via Comment.Where(t => t.Id == 1).

However, if I immediately call it without calling the static Comment constructor first, I get a null reference exception on QueryInitializer, as expected.

This all makes sense, but I'm first trying to figure out an elegant way to call the static constructor prior to the static method, and second I'm trying to convince myself that while this design will be useful in practice due to the simplicity of querying via static Class.Where() methods, it doesn't feel right making these methods static.

1 Answer 1

0

I resolved this by making a wrapper around QueryInitializer that creates a new instance of T and immediately drops it for the garbage disposal to come clean up. But, it does call Comment's static constructor which does what I wanted. It's not the cleanest in design, but it works well and is entirely self contained.

protected static IQueryable<T> GetQueryStart(DatabaseContext context, bool eagerLoading)
{
    if (QueryInitializer == null)
    {
        QueryInitializer = (c, e) => { return c.Set<T>(); }; // Default implementation
        new T(); // Trigger static constructor to set custom definition
    {
    return QueryInitializer(context, eagerLoading);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.