2011-05-30 8 views
8

LINQ-2-SQL mantiene un mapa de identidad para que las siguientes llamadas a entity.First(e => e.Id == id) no causen consultas adicionales más allá del primero para un contexto.¿Hay alguna manera de buscar un elemento en el mapa de identidad de L2S?

¿Hay alguna forma de preguntar a L2S si existe un elemento en particular en el mapa de identidad?

Pregunto esto porque hay soporte para .Attach que le permite adjuntar entidades a un contexto, sin embargo, el método exceptuará si el elemento ya existe en el mapa de identidad.

En un escenario de interoperabilidad, puedo cargar entidades en un orm diferente, más rápido y adjuntar, sin embargo, no tiene sentido buscar una entidad si ya está en el mapa de identidad.

Respuesta

6

No hay una buena manera ... puedes hackear tu entrada, sin embargo. Por ejemplo imagine que tiene un objeto User que sabe que está codificado por medio Id:

var user = // get some user 
var dataContext = // your DB context 

const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic 
     | BindingFlags.Public; 
object commonDataServices = typeof(DataContext) 
    .GetField("services", AllInstance) 
    .GetValue(dataContext); 
object identifier = commonDataServices.GetType() 
    .GetProperty("IdentityManager", AllInstance) 
    .GetValue(commonDataServices, null); 
MethodInfo find = identifier.GetType().GetMethod("Find", AllInstance); 
var metaType = dataContext.Mapping.GetMetaType(typeof(User)); 
object[] keys = new object[] { user.Id }; 
var user2 = (User)find.Invoke(identifier, new object[] { metaType, keys }); 
bool pass = ReferenceEquals(user, user2); 

Pretty-tanto cada acceso es no pública; Esperaría que esto suck a nivel de rendimiento a menos que use DynamicMethod para falsificar el acceso de otro tipo.

Y como una versión DynamicMethod:

(sí, soy difícil de codificación a una clave int ... que podría hacer cualquier valor individual mediante la sustitución de la int con object, y simplemente dejar caer el OpCodes.Box, typeof(int) - o puede que sea un argumento params object[] y pasarlo directamente)

static readonly Func<DataContext, Type, int, object> identityLookup = BuildIdentityLookup(); 

static Func<DataContext, Type, int, object> BuildIdentityLookup() 
{ 
    var quickFind = new DynamicMethod("QuickFind", typeof(object), new Type[] { typeof(DataContext), typeof(Type), typeof(int) }, typeof(DataContext), true); 
    var il = quickFind.GetILGenerator(); 

    const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; 
    il.Emit(OpCodes.Ldarg_0); // DB 
    var services = typeof(DataContext).GetField("services", AllInstance); 
    il.Emit(OpCodes.Ldfld, services); // services 

    var identifier = services.FieldType.GetProperty("IdentityManager", AllInstance); 
    il.EmitCall(OpCodes.Callvirt, identifier.GetGetMethod(true), null); // identifier 

    il.Emit(OpCodes.Ldarg_0); // identifier DB 
    var mapping = typeof(DataContext).GetProperty("Mapping"); 
    il.EmitCall(OpCodes.Callvirt, mapping.GetGetMethod(), null); // identifier mapping 

    il.Emit(OpCodes.Ldarg_1); // identifier mapping type 
    il.EmitCall(OpCodes.Callvirt, mapping.PropertyType.GetMethod("GetMetaType"), null); // identifier metatype 

    il.Emit(OpCodes.Ldc_I4_1); // identifier metatype 1 
    il.Emit(OpCodes.Newarr, typeof(object)); // identifier metatype object[] 
    il.Emit(OpCodes.Dup); // identifier metatype object[] object[] 
    il.Emit(OpCodes.Ldc_I4_0); // identifier metatype object[] object[] 0 
    il.Emit(OpCodes.Ldarg_2); // identifier metatype object[] object[] 0 id 
    il.Emit(OpCodes.Box, typeof(int)); // identifier metatype object[] object[] 0 boxed-id 
    il.Emit(OpCodes.Stelem_Ref); // identifier metatype object[] 

    il.EmitCall(OpCodes.Callvirt, identifier.PropertyType.GetMethod("Find", AllInstance), null); // object 
    il.Emit(OpCodes.Ret); 

    return (Func<DataContext, Type, int, object>)quickFind.CreateDelegate(typeof(Func<DataContext, Type, int, object>)); 
} 
+5

... oh el horror :) –

Cuestiones relacionadas