Search code examples
c#pocodevforce

How to access the EntityManager that the NamedQuery is running on for a POCO class in DevForce


I am writing a POCO class in a DevForce based application that has a number of Named Queries and I cannot figure out how to access the Entity Manager from inside the Named Query.

I have placed shortened code from inside of our Entity Managers partial which is below:

    public partial class BearPawEntities
{
    public EntityQuery<OrderView3> OrderView3s()
    {
        return new EntityQuery<OrderView3>("OrderView3s", this);
    }
}

Here is one of the basic things I was trying just to get this working before I write the heavier queries:

    [EnableClientAccess]
public class PocoServiceProvider
{

    public PocoServiceProvider() { }

    public IQueryable<OrderView3> GetOrderView3s()
    {
        var currentUser = new EntityQuery<User>().Include(u => u.Role.RoleCheckPoints).Include(u => u.CoveringForUsers)
                .FirstOrDefault(u => u.UserName == System.Threading.Thread.CurrentPrincipal.Identity.Name);

        List<OrderView3> orderView3s = new List<OrderView3>();
        for (int i = 1; i < 150; i++)
        {
            orderView3s.Add(new OrderView3()
            {
                Id = i,
                CustomerCode = $"Customer {i}",
                Invoices = i
            });
        }
        return orderView3s.AsQueryable();
    }

    ...
}

If I remove the code to get the current user then my example works and I get the list returned to the client but whenever I try and call the new EntityQuery<> function I get an exception with the detail {"No EntityManager for this query"}.

I have tried passing in the EntityManager as a parameter but then I get told it is not serializeable (which I expected). I have set the query.EntityManager property on the code within the BearPawEntities class but that looks to me like it is more enabling you to use differing managers if required rather than passing it to the query.

I have also tried the extension method approach that I saw in the samples in the DevForce documentation.

At this point I am stumped and would appreciate any help!

Many thanks in advance

Lee


Solution

  • DevForce keeps a pretty strict distinction between "client-side" and "server-side", and doesn't ever pass the client-side EntityManager to the server. When you see a server-side EntityManager, injected by DevForce as either a method parameter or property, that's a new instance of the EM created for that single purpose.

    That doesn't mean you can't create a new instance of your own, you just need to take care how you create it. When DF creates a server-side EM, it's considered already authenticated and thus won't pass through an IEntityLoginManager, and it also uses simple method invocations to the EntityServer instead of WCF. The authentication issue can be tricky depending on your implementation (a custom composition context can help with this), but you should also construct the EM with the EntityServiceOption.UseLocalService option set to avoid WCF overhead.

    Named queries have a somewhat different workflow than other queries. Usually, you can use an EntityServerQueryInterceptor to control authorization and filtering, but the named query method is invoked before the interceptor. This means that authorization will be performed "late", maybe later than wanted if you need to use the user's identity to build/execute the query.

    A workaround for this might be to use a custom IPrincipal in your IEntityLoginManager implementation to ensure that all information required to authorize queries (and saves) is available directly from the thread's CurrentPrincipal, which DF will always set for the request. Doing this would avoid having to requery User information each time a query is executed.