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

以下是我从 Web 服务调用它时得到的异常详细信息:

请求错误 服务器在处理请求时遇到错误。异常消息是“在模型生成期间检测到一个或多个验证错误:\tSystem.Data.Entity.Edm.EdmAssociationEnd: : 多重性在关系“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) 在 System. 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.Internal.Linq.InternalSet 1.get_InternalContext() at System.Data.Entity.Infrastructure.DbQuery1.System.Linq.IQueryable.get_Provider() 在 System.Linq.Queryable.Where[TSource](IQueryable1 source, Expression1 谓词)在 ProjectTracker.Database.DataAccess.DLAccess.DoesUserExist(String userName) 在 e:\My Own\Projects\ProjectTracker\Database\ProjectTracker.Database.DataAccess\DLAccess.cs:ProjectTracker.Business.BLAccess.BLAccess 的第 31 行.DoesUserExists(String userName) in e:\My Own\Projects\ProjectTracker\Business\ProjectTracker.Business.BLAccess\BLAccess.cs: 第 37 行 ProjectTracker.UI.Web.WS.WebAccess.DoesUserExist(String userName) in e: \My Own\Projects\ProjectTracker\UI\ProjectTracker.UI.Web\WS\WebAccess.svc.cs:第 12 行 SyncInvokeDoesUserExist(Object , Object[] , Object[] ) 在 System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke( System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) 处 System.ServiceModel.Dispatcher 处的对象实例、Object[] 输入、Object[]& 输出)。System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) 上的 ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

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

4

1 回答 1

11

User.CreatedByEF 映射约定尝试推断和之间的一对一关系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);

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

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是应用于您的模型并检测一对一关系的。文档说:

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

“唯一”一对导航属性是CreatedByinUser指的是User- ,而 inUser是第二个导航属性LastUpdatedBy,它指的是User. (这有点令人困惑,因为“相关类型”是相同的 -UserUser,但约定在这里适用于不同类型之间的相同方式。)因为两者都是引用(而不是集合),EF 假定关系必须是一个 -一对一(而不是一对多或多对多)。

有时约定不会按照您的意愿推断关系。然后,您必须使用 Fluent API 或数据注释覆盖映射约定。(您的示例中注释不够,您必须在此处使用 Fluent API。)

于 2013-02-06T18:06:51.100 回答