实体框架代码首次自我加入,'多重性在角色中无效'

Nav*_*utt 5 .net entity-framework code-first .net-4.5

我陷入了这个错误,无法找到解决方案.我尝试了几件事,但无法提出解决方案.

这是我的问题:

码:

namespace ProjectTracker.Database.Entities
{
    [DataContract]
    public class User
    {
        [DataMember]
        public int Id { get; set; }

        [Required]
        [MaxLength(50)]
        [DataMember]
        public string UserName { get; set; }

        [Required]
        [MaxLength(100)]
        [DataType(DataType.Password)]
        [DataMember]
        public string Password { get; set; }

        [DataMember]
        public bool IsPasswordExpired { get; set; }

        [Required]
        [DataMember]
        public DateTime CreatedDate { get; set; }

        [Required]
        [ForeignKey("CreatedBy")]
        [DataMember]
        public int CreatedByUserId { get; set; }

        [DataMember]
        public virtual User CreatedBy { get; set; }

        [Required]
        [DataMember]
        public DateTime LastUpdatedDate { get; set; }

        [ForeignKey("LastUpdatedBy")]
        [DataMember]
        public int? LastUpdatedByUserId { get; set; }

        [DataMember]
        public virtual User LastUpdatedBy { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是从Web服务调用时获取的异常详细信息:

请求错误服务器在处理请求时遇到错误.异常消息是'在模型生成期间检测到一个或多个验证错误:\ tSystem.Data.Entity.Edm.EdmAssociationEnd :: Multiplicity在关系'User_LastUpdatedBy'中的角色'User_LastUpdatedBy_Source'中无效.由于"从属角色"属性不是关键属性,因此从属角色的多重性的上限必须为"*".".请参阅服务器日志以获取更多详 异常堆栈跟踪是:

在System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest,DbProviderInfo providerInfo)处的System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)处的System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)处. Data.Entity.Internal.RetryLazy 2.GetValue(TInput input) at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) at System.Data.Entity.Internal.Linq.InternalSet1.Initialize()在System.Data.Entity.Linq.InternalSet 1.get_InternalContext() at System.Data.Entity.Infrastructure.DbQuery1.System.Linq.IQueryable.get_Provider()在System.Linq.Queryable.Where [TSource](IQueryable 1 source, Expression1谓词) )在ProjectTracker.Business.BLAccess.BLAccess.DoesUserExists的e:\ My Own\Projects\ProjectTracker\Database\ProjectTracker.Database.DataAccess\DLAccess.cs中的ProjectTracker.Database.DataAccess.DLAccess.DoesUserExist(String userName):第31行(字符串userName)在e:\ My Own\Projects\ProjectTracker\Business\ProjectTracker.Business.BLAccess\BLAccess.cs:第37行,位于e:\ My中的ProjectTracker.UI.Web.WS.WebAccess.DoesUserExist(String userName)自己的\项目\ ProjectTracker\UI\ProjectTracker.UI.Web\WS\WebAccess.svc.cs:L 在System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin的System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(对象实例,对象[]输入,对象[]和输出)处的SyncInvokeDoesUserExist(Object,Object [],Object [])中的ine 12 (MessageRpc&rpc)System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&rpc)at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&rpc)at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

请告诉我,我在这里做错了什么......

Sla*_*uma 11

EF映射约定试图推断User.CreatedBy和之间的一对一关系User.LastUpdatedBy.这会失败,因为两个导航属性都使用同时不是主键的外键表示,并且因为EF仅支持共享主键一对一关系.

无论如何,这并不重要,因为您不需要一对一的关系,而实际上是两个一对多关系:用户可以创建许多其他用户,用户可以修改许多其他用户.

要实现此目的,您必须通过使用Fluent API显式定义两个关系来覆盖约定:

modelBuilder.Entity<User>()
    .HasRequired(u => u.CreatedBy)  // this could be a problem, see below
    .WithMany()
    .HasForeignKey(u => u.CreatedByUserId);

modelBuilder.Entity<User>()
    .HasOptional(u => u.LastUpdatedBy)
    .WithMany()
    .HasForeignKey(u => u.LastUpdatedByUserId);
Run Code Online (Sandbox Code Playgroud)

可能需要创建CreatedBy可选项,即CreatedByUserId必须是类型,int?并且在上面的映射中必须替换HasRequiredHasOptional,否则您无法在不违反FK约束的情况下创建第一个用户.

可能你可以应用一个技巧,比如直接在DB中创建第一个CreatedByUserId允许NULL值的用户,然后将该用户指定为他自己的创建者,然后更改数据库模式以NULL禁止.

编辑

有关详细信息" EF映射约定尝试推断间的一种一对一关系User.CreatedByUser.LastUpdatedBy. ":

当EF在启动期间分析您的模型类时,它会使用

  1. 使用Fluent API配置,
  2. 您应用的数据注释,
  3. 一组用于从导航属性和属性名称推断关系的约定.

除非使用Fluent API或数据注释明确指定,否则将应用这些中心集.您可以在此处找到完整的约定:http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions(v=vs.103).aspx

对于您的原始User类,它AssociationInverseDiscoveryConvention适用于您的模型并检测一对一的关系.文件说:

当相关类型之间仅存在一对导航属性时,检测导航属性为彼此的反转的约定.

"唯一一对"导航属性CreatedByUser其中引用User- 而in User是第二个LastUpdatedBy引用的导航属性User.(这只是有点令人困惑,因为"相关类型"是相同的 - User而且User,这里的约定适用于不同类型之间的相同方式.)因为两者都是引用(而不是集合),EF假定关系必须是一个 - to-one(而不是一对多或多对多).

有时约定不会根据需要推断关系.然后,您必须使用Fluent API或数据注释覆盖映射约定.(在您的示例中,注释是不够的,您必须在此处使用Fluent API.)