zoukankan      html  css  js  c++  java
  • 异常跟踪之CLR 类型到 EDM 类型的映射不明确

    异常信息:

    "指定的架构无效。错误:
    CLR 类型到 EDM 类型的映射不明确,因为多个 CLR 类型与 EDM 类型“Person”匹配。
    以前找到的是 CLR 类型“A.Person”,
    新找到的则是 CLR 类型“B.Person”。

    这类异常信息在代码里面出现过几次,每次的解决方案都让人匪夷所思。不知道为什么出现,也不知道为什么被解决了。

    查阅了一些国外的资料,链接

    Don't use classes with the same name - EF uses only class names to identify the type mapped in EDMX (namespaces are ignored) - it is a convention to allow mapping classes from different namespaces to single model. The solution for your problem is to name your classes in BLL differently.

    但实际情况是,这类异常不总是出现,而是在一个偶然的情况下出现。所谓偶然的情况,却是一种很普通又简单的调用。

    using (var con = new MyContainer())
    {
        string sql = "select top 1 name from cat";
        var p = con.Database.SqlQuery<contract.Dog>(sql).FirstOrDefault();
        Console.WriteLine(p.Name);
    }

    查询cat数据,将第一个的name数据查询并存储在contract.Dog对象中。这类调用非常普通。

    整理一下思路:

    1. 出现"CLR 类型到 EDM 类型的映射不明确"异常,肯定是存在和ef模型中数据结构一样的类

    2. 与ef数据结构同名的类一直存在,但并非一直报错。

    做以下测试:

    测试一

    在ef数据模型所在项目中(以下用entity表示),建立模型Person

    同时,在entity项目中另外新建一个类,也命名为Person(当然名称空间不一样),属性一样(类型和名称)。

    调试时,会发现报错,报错内容同上。

    测试二

    在测试一的基础上,去掉entity中手动创建的Person类,在解决方案下新建另一个项目contract,在contract中新建类,命名Person,属性同上。

    调用代码:

    using (var con = new MyContainer())
    {
        string sql = "select top 1 * from person";
        var p = con.Database.SqlQuery<contract.Person>(sql).FirstOrDefault();
        Console.WriteLine(p.Name);
    }

    单独运行这段时,不会报错。加上下面这段:

    using (var con = new MyContainer())
    {
        string sql = "select top 1 * from person";
        var p = con.Database.SqlQuery<efentity.Person>(sql).FirstOrDefault();
        Console.WriteLine(p.Name);
    }

    执行完上面代码后,紧接着执行下面的代码。出现异常,异常同上。

    加断点,跟踪con的数据明细。

    在执行完第一段查询以前,con.base._internalContext.ObjectContext.MetadataWorkSpace._itemOCSpace.Value(以下简称MetaOCSpace)为空;

    执行完第一段查询后,MetaOCSpace的数量出现32条,具体如下:

    出现了Person的类型映射数据,此时Person类型映射到了contract.Person。

    省略其他测试过程,有如下结论:

    1. 当entity中出现同数据模型的类时,同类名同字段,无论什么时候用ef操作数据,都会报错。

    2. 当entity所在的assembly没有同名类,但其他assembly(例contract)有同名类时。先有查询结果放入entity的任意类对象,后有查询结果放入contract的任意类对象时,就会报错。操作的先后顺序调换,结果一样。

    这是因为DbContext的MetadataWorkSpace一旦生成会缓存起来。也就是说,在同一个应用程序域里面,一旦用dbcontext操作过数据库,它会自动读取类所在assembly里面的所有类,并尝试匹配数据库模型,然后将匹配结果保存起来(保存到上面的MetaOCSpace中)。当下次操作数据库时,返回数据对应类类所在其它assembly里面的类与当前已匹配数据库模型发生冲突时,便会报错。

    3. 当client引用entity + client引用contract时,有结论2的隐患。而当entity引用contract,然后client引用entity时,同样存在问题。

    这种情况一般出现在ef的枚举类型定义为引用外部类型(contract中定义的类型),这时就会出现entity引用contract,然后client引用entity的场景。配合以下代码:

    using (var con = new MyContainer())
    {
        var p = con.Person.Where(pp => pp.Status == contract.We.One).FirstOrDefault();
        Console.WriteLine(p.Name);
    }

    这时,也会出现报错。

    解决思路:

    1. 不要与entity中的模型同名,同字段。或者换过来entity中的模型加特殊标记

    2. ef操作数据库时,返回数据的数据类型必须用entity项目中定义的类型。

    以上内容,部分细节未仔细推敲,如有其他想法请留言。

  • 相关阅读:
    两道简单的机试题目
    C#二维数组(矩形数组,交错数组)
    用实例展示left Join,right join,inner join,join,cross join,union 的区别
    React 中的 Redux 详解:
    react 组件通信:
    vue 入门, todoList
    Vue 动画
    vue 框架,入门必看
    koa2 的使用方法:(一)
    git 的使用:
  • 原文地址:https://www.cnblogs.com/icyJ/p/CLRandEDM.html
Copyright © 2011-2022 走看看