有什么方法可以在L2S身份映射中查找项目吗

本文关键字:映射 查找 项目 身份 L2S 方法 什么 | 更新日期: 2023-09-27 17:58:07

LINQ-2-SQL维护一个标识映射,因此对entity.First(e => e.Id == id)的后续调用不会导致对上下文的第一个查询之外的其他查询。

是否有任何方法可以询问L2S身份映射中是否存在特定项目?

我之所以这么问,是因为支持.Attach,它允许您将实体附加到上下文,但是,如果该项已经存在于标识映射中,则该方法将异常。

在互操作性场景中,我可能希望在不同的、更快的orm中加载实体并进行连接,但是,如果实体已经在身份映射中,则查找它是没有意义的。

有什么方法可以在L2S身份映射中查找项目吗

没有好办法。。。不过你可以自己闯进去。例如,假设您有一个User对象,您知道该对象由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);

几乎所有访问都是非公开的;除非您使用DynamicMethod来欺骗来自另一种类型的访问,否则我预计这在性能方面会很糟糕。

作为DynamicMethod版本:

(是的,我正在对int键进行硬编码……您可以将int替换为object,使其成为任何单个值,然后删除OpCodes.Box, typeof(int),或者您可以将其作为params object[]参数并直接传入)

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>));
}