EF 6和5中CLR类型到EDM类型的映射不明确?

85

请问有谁能帮我修复这个错误?

指定的模式无效。错误:

CLR 类型到 EDM 类型的映射是模糊的,因为多个 CLR 类型与 EDM 类型 'City_DAL' 匹配。之前找到了 CLR 类型 'CeossDAL.City_DAL',现在发现了 CLR 类型 'CeossBLL.City_DAL'。

我的主要问题是 DAL,它包含 EF 和 BLL,这两者包含相同的 DAL 类,但命名空间不同,这就导致了问题。

我不知道如何解决这些问题,请你帮帮我好吗?

如果有人能给我一个使用 EF 的 n 层架构示例,我将不胜感激。

谢谢

16个回答

78
不要使用相同的未限定名称的类 - EF 仅使用类名来标识在 EDMX 中映射的类型(名称空间将被忽略) - 这是一种约定,允许将不同命名空间的类映射到单个模型中。解决您的问题的方法是以 BLL 中不同的名称命名您的类。

2
EF不会在两个类之间进行映射,它是在图表中的实体之间进行映射,并寻找一个与名称相同的单一类。 - Ladislav Mrnka
3
我正在一个三层结构(数据访问层/业务逻辑层/表示层)的项目中工作,因此我有两个类:一个在数据访问层(DAL)中使用了 EF,另一个在业务逻辑层(BLL)中也使用了相同的 EF 类。在 BLL 中,每个类都包含用于调用 DAL 方法的方法。这些 DAL 方法需要一个来自 Product 类的对象,该类存在于 DAL 中,但我从 BLL 调用这些方法。因此,当我将该对象传递给 DAL 的方法时,我从 BLL 中创建了一个 Product 对象,这里引发了异常。 - Mahmoud Samir
4
如果没有你的 Stack Overflow 帖子,我可能已经放弃 EF 了。再次获救了。谢谢你。 - Neil Thompson
11
只有当两个类具有相同的名称和参数集时,才会发生EF碰撞。 - Nikos Tsokos
只要位于不同的物理层,添加具有相同名称的多个类应该是可以的。例如,您可以拥有一个名为Product的类,它存在于存储库层、域和表示层。您只需要一些映射框架来将数据从一层移动到另一层。在这种情况下,EF不会关心您为类命名的内容。 - Latin Warrior
显示剩余5条评论

50

解决方法:更改两个相同类的属性之一。

EF 匹配类名称和类属性。因此,我只需更改 EF 对象中的一个属性名称,错误即可消失。

正如 @Entrodus 在其他答案中评论的那样:

仅当两个类具有相同的名称和参数集时,才会发生 EF 冲突。


8
在我看来,这是最好的答案 - 我宁愿改动一个属性名而不是类名。 - OutstandingBill
2
我只是把它们放在不同的程序集中... 不需要搞这个。 - Erik Bergstedt
7
如果您在同一解决方案中使用这两个程序集,就会开始出现错误。 - Tundey
4
在EDMX中存在冲突的实体中,我尝试更改一个属性的名称,添加另一个属性,以及添加带有更多“虚拟”属性的Partial类……但它们都没有起作用。只有更改实体名称对我起作用… - Ymagine First
4
这是一个没有意义的说法。类没有参数。 - Suncat2000
删除可空属性似乎也不是一个解决方案。 我更喜欢选择一个在上下文中没有使用的属性,将其命名为DONOTUSE1等,并使其私有化。这很丑陋,但有效。您甚至可以为此添加一个无用的位列。 - CervEd

10

这个 MSDN论坛的问题可能会有所帮助。它建议将BLL和DAL类放在不同的程序集中。


3
如果您在同一解决方案中使用这两个程序集,将会出现错误......我遇到了完全相同的问题。它们是不同的数据库,但却拥有相同的 tblSetting 表。我将其放在两个不同的程序集中(始终放在不同的程序集中),但它仍然无法正常工作 :( - Sam
我在同一解决方案中使用了这两个程序集,但错误没有出现,所以我不知道这个注释发生了什么问题... - Niklas

9
对于EF 6.x,我在https://github.com/aspnet/EntityFramework/issues/941上找到了一些笔记,并通过为EDM类型添加注释来修复了这个问题。 我手动编辑了EDMX文件并更改了如下行:
<EntityType Name="CartItem">

转换为:

<EntityType Name="CartItem" customannotation:ClrType="EntityModel.CartItem">

或者如果您已经在其他地方存在相同类型,请使用此选项:

<EntityType Name="CartItem" customannotation:ClrType="MyApp.CartItem, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">

其中EntityModel是我的EF模型所使用的命名空间,而MyApp是一个业务对象的命名空间。


1
这对我没有用(尝试了EF 6.0和6.3),正在使用SQLite数据库。 - Daniël Tulp
我只用它和MSSQL。 - Ekus
1
那个 Github 帖子还说要在 <EntityContainer> 中添加 customannotation:UseClrTypes。(在 EF 6 中对我仍然没有用) - Keith
1
它对于我使用的 MSSQL 和 EF 6.3.0 可以工作(其他组合尚未测试)。 - Peter Ivan

8
在某些情况下,这更像是症状而不是实际问题。对我来说,通常会在尝试在Linq查询中调用函数而未先调用.ToList()时弹出此错误。
例如,我遇到的错误是由于我这样做引起的:
var vehicles = DB.Vehicles.Select(x => new QuickSearchResult()
{
    BodyText = x.Make + " " + x.Model + "<br/>"
    + "VIN: " + x.VIN + "<br/>"
    + "Reg: " + x.RegistrationNumber +"<br/>"
    + x.AdditionalInfo
    type = QuickSearchResultType.Vehicle,//HERE. Can't use an enum in an IQueryable.
    UniqueId = x.VehicleID
});

我需要调用.ToList()方法,然后遍历每个项目并将类型分配给它。

2
谢谢!这正是我的问题,需要在LINQ语句中将其转换为枚举类型。 - Doug

2
我之前遇到了上述错误,原因是在我的主项目的配置文件中,对于两个连接字符串,我都指定了相同的元数据值,如下所示:
<add name="EntitiesA" connectionString="metadata=res://*/EntitiesA.csdl|res://*/EntitiesA.ssdl|res://*/EntitiesA.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=localhost;initial catalog=MyDatabase;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

<add name="EntitiesB" connectionString="metadata=res://*/EntitiesA.csdl|res://*/EntitiesA.ssdl|res://*/EntitiesA.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=localhost;initial catalog=MyDatabase;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

我最终从EntitiesB项目的配置文件中复制了正确的连接字符串。

1
我认为OP有实体名称的问题。我也有同样的问题......我确实在我的Web.config中放置了正确的连接字符串。但它仍然无法工作:( - Sam
在看到你的答案并花费了3个小时来解决问题后,我已经修复了这个问题。 - ChupChapCharli

1
这个解决方案可能在问题被问出时还不可用,但是另一个解决方案是删除EDMX并将其重新创建为基于代码的实体数据模型。在EF6中,使用code-first,您可以将来自不同模型命名空间的两个具有相同名称的类进行映射而不会创建冲突。
要在Visual Studio(2013)中创建实体数据模型,请转到“添加”>“新项目...”>“ADO.NET实体数据模型”。请务必选择“从数据库生成Code First”的选项。

这对我没有用(尝试了EF 6.0和6.3),正在使用SQLite数据库。 - Daniël Tulp
我不知道这是否有所不同,但我在使用 MS SQL Server 时执行了此操作。 - Tawab Wakil
这对我绝对有效。我遇到了其他解决方案似乎都不适用的情况。 - Dave
这是因为Code First的实体类型有不同的注释方式。请参考@Ekus在https://dev59.com/iGUp5IYBdhLWcg3w8LF4#44931349中的回答。 - Suncat2000

0

我发现使用自定义注释解决方案可以与EF 6.2.0一起使用。只需确保在ConceptualModels节点中进行更改并使用类型的完整命名空间即可。

<edmx:ConceptualModels>
  <Schema Namespace="Sample.Access.Data.Ef" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
    <EntityType Name="DbTableName" customannotation:ClrType="Sample.Access.Data.Ef.DbTableName, Sample.Access.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <Key>
        <PropertyRef Name="DbTableNameId" />
      </Key>
      <Property Name="DbTableNameId" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
      <Property Name="OptionName" Type="String" MaxLength="100" FixedLength="false" Unicode="false" Nullable="false" />
      <Property Name="Value" Type="String" MaxLength="500" FixedLength="false" Unicode="false" Nullable="false" />
      <Property Name="UpdatedDate" Type="DateTime" Nullable="false" Precision="3" />
    </EntityType>
    <EntityContainer Name="MyEntities" annotation:LazyLoadingEnabled="true" customannotation:UseClrTypes="true">
      <EntitySet Name="DbTableNames" EntityType="Self.DbTableName" />
    </EntityContainer>
  </Schema>
</edmx:ConceptualModels>

0
如果您的Web.config文件中有2个连接字符串,但您想使用一个连接字符串,则可以使用动态创建连接字符串的方式来处理其他实体。在我的解决方案中,我有一个EDMX(数据库优先)和代码优先的实体。我在代码优先实体中使用了这个类。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Entity.Core.EntityClient;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data
{
    public class SingleConnection
    {
        private SingleConnection() { }
        private static SingleConnection _ConsString = null;
        private String _String = null;

        public static string ConString
        {
            get
            {
                if (_ConsString == null)
                {
                    _ConsString = new SingleConnection { _String = SingleConnection.Connect() };
                    return _ConsString._String;
                }
                else
                    return _ConsString._String;
            }
        }

        public static string Connect()
        {
            string conString = ConfigurationManager.ConnectionStrings["YourConnectionStringsName"].ConnectionString;

            if (conString.ToLower().StartsWith("metadata="))
            {
                System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder efBuilder = new System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder(conString);
                conString = efBuilder.ProviderConnectionString;
            }

            SqlConnectionStringBuilder cns = new SqlConnectionStringBuilder(conString);
            string dataSource = cns.DataSource;
            SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
            {
                DataSource = cns.DataSource, // Server name
                InitialCatalog = cns.InitialCatalog,  //Database
                UserID = cns.UserID,         //Username
                Password = cns.Password,  //Password,
                MultipleActiveResultSets = true,
                ApplicationName = "EntityFramework",

            };
            //Build an Entity Framework connection string
            EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
            {
                Provider = "System.Data.SqlClient",
                Metadata = "res://*",
                ProviderConnectionString = sqlString.ToString()
            };
            return entityString.ConnectionString;
        }
    }
}

当我调用实体时

private static DBEntities context
{
get
{
    if (_context == null)
        _context = new DBEntities(SingleConnection.ConString);

    return _context;

}
set { _context = value; }
}

0

我认为你在实体模型中有一个名为"MyClass"的X类,以及在同一工作文件夹中或扩展第一个类的另一个名为"MyClass"的类。 这就是我的问题,我已经解决了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接