【问题标题】:Is there any way to look up an item in the L2S identity map?有没有办法在 L2S 身份图中查找项目?
【发布时间】:2011-05-30 01:30:12
【问题描述】:

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

是否有询问 L2S 是否存在特定项目的身份映射?

我问这个原因是因为支持.Attach,它允许您将实体附加到上下文,但是如果该项目已存在于身份映射中,该方法将异常。

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

【问题讨论】:

    标签: c# .net linq-to-sql


    【解决方案1】:

    没有什么好办法……不过,你可以闯进去。例如,假设您有一个 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>));
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-26
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-02
      • 1970-01-01
      • 2012-11-02
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多