LINQ On DbContext.Set()

2019-06-03 16:11发布

问题:

So, basically I am trying to get a DbSet returned from entity name (string). This is how far I have gotten:

var customers = db.Set(Type.GetType("App.Model.Customer, 
                                     App.Model, 
                                     Version=1.0.0.0, 
                                     Culture=neutral, 
                                     PublicKeyToken=null"));

But then I cannot perform other LINQ like Any() or Single(). Why is that and how can I change it to do so?

回答1:

The non-generic overload of DbContext.Set returns an equally non-generic DbSet. One of the interfaces this class implements is IQueryable, again, non generic. That's the reason why it can't serve as input to any of these LINQ extension method that are defined on the generic type IQueryable<T>.

So in fact, if you still want to use LINQ, you only postpone the moment when you have to convert to a generic IQueryable. You could do...

var customers = db.Set(Type.GetType(...)).Cast<Customer>().Where(c => ...)

...but then of course you lose the whole point of defining the type dynamically, at runtime.

Once you start dynamically, you have to continue dynamically. One way to do that is by adding System.Linq.Dynamic to your project. Then you can write queries like...

var customers = db.Set(Type.GetType(...)).Where("CustomerId = @0", 1);

...which will return you the Customer (wrapped in an IQueryable<Customer>) having CustomerId == 1.

You can even use the Find method:

var customer = db.Set(Type.GetType(...)).Find(1);

This will return a single Customer instance.



回答2:

With the requirements you have, no, if the requirements were to change you might be able to work around it. If you get your type as string at runtime, how do you believe you could possibly program against it before you even compile the code?

Static typing need static types to work, you can do some ninja dynamics with interfaces to get around part of it, but your question provides no such information.



回答3:

Try casting the non-generic IQueryable to a generic (where the generic property is a super class or even just object), e.g.:

((IQueryable<object>)context.Set(Type.GetType(...))).Count();

This worked for me!