简体   繁体   中英

Insert Func<T, int> value into linq-2-sql query

i have a multi-tenant application and all data is in the same database. We split the data for each tenant by a objectToTenant table.

In a generic Repository class i want to implement a method which filters the objects just by specifying which property of the object is the tenantToObjectRelationId and what type is the object (needed because different types are stored in the relation table)

The call i want to make should look like this:

// Specialized Repository class 
var allItemsForTenant =
    this.AllForTenant(item => item.RelationId, 123);

and therefore i've implemented this method:

// Generic Repository class
public virtual IQueryable<T> AllForTenant(
    Func<T, int> getObjectToTenantRelationId, string objectType)
{
    var result =
        from item in this.context.GetTable<T>( )
        join tenantObject in (
            from tenantRelationRecord in objectTenantRelationRepo.All( )
            where tenantRelationRecord.TenantId == Global.TenantId
            where tenantRelationRecord.ObjectTypeId == type.TypeId
            select tenantObjectRecord)
            on getObjectToTenantRelationId( item ) equals tenantObject.ObjectId
        select item;

    return result;
}

but at the moment i get a NotSupportedException

Für die System.Object DynamicInvoke(System.Object[])-Methode gibt es keine unterstützte Übersetzung in SQL.

which is caused by the Func<T, int> method which cannot be translated into sql.

How do i need to change the Func<T, int> so that it can be translated or does someone another solution?

Instead of passing in a Func<T, int> pass in a IQueryable<Tuple<T, int>> or something similar. This way LINQ to SQL knows how to translate it to SQL:

// Generic Repository class
public virtual IQueryable<T> AllForTenant(
    IQueryable<Tuple<T, int>> objectToTenentRelationIds, string objectType)
{
    var tenantObjects =
        from tenantRelationRecord in objectTenantRelationRepo.All()
        where tenantRelationRecord.TenantId == Global.TenantId
        where tenantRelationRecord.ObjectTypeId == type.TypeId
        select tenantObjectRecord;

    var result =
        from item in this.context.GetTable<T>()
        join objectToTenentRelationId in objectToTenentRelationIds
            on objectToTenentRelationId.Item1 equals item
        join tenantObject in tenantObjects
            on objectToTenentRelationIds.Item2 equals tenantObject.ObjectId
        select item;

    return result;
}

A simplest fix would be to pass Expression<Func<T,int>> instead of just Func<T,int> . Passing an expression would allow the tree visitor to "step into" your expression rather than bounce off its name.

What's nice is that if you pass lambdas, the compiler will automatically create Expression<Func<T,int>> out of them, thus the only thing you have to change is the signature of your AllForTenant method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM