I am stuck at this error and can not find the solution to this. I have tried several things but could not come up with a solution.
Here is my problem:
Code:
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; }
}
}
and Here are the exception details that I am getting while calling it from a web service:
Request Error The server encountered an error processing the request.
The exception message is ‘One or more validation errors were detected
during model generation: \tSystem.Data.Entity.Edm.EdmAssociationEnd: :
Multiplicity is not valid in Role ‘User_LastUpdatedBy_Source’ in
relationship ‘User_LastUpdatedBy’. Because the Dependent Role
properties are not the key properties, the upper bound of the
multiplicity of the Dependent Role must be ‘*’. ‘. See server logs for
more details. The exception stack trace is:at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest
providerManifest, DbProviderInfo providerInfo) at
System.Data.Entity.DbModelBuilder.Build(DbConnection
providerConnection) at
System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext
internalContext) at
System.Data.Entity.Internal.RetryLazy2.GetValue(TInput input) at1.Initialize() at
System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at
System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type
entityType) at
System.Data.Entity.Internal.Linq.InternalSet
System.Data.Entity.Internal.Linq.InternalSet1.get_InternalContext()1.System.Linq.IQueryable.get_Provider()
at
System.Data.Entity.Infrastructure.DbQuery
at System.Linq.Queryable.Where[TSource](IQueryable1 source,1 predicate) at
Expression
ProjectTracker.Database.DataAccess.DLAccess.DoesUserExist(String
userName) in e:\My
Own\Projects\ProjectTracker\Database\ProjectTracker.Database.DataAccess\DLAccess.cs:line
31 at ProjectTracker.Business.BLAccess.BLAccess.DoesUserExists(String
userName) in e:\My
Own\Projects\ProjectTracker\Business\ProjectTracker.Business.BLAccess\BLAccess.cs:line
37 at ProjectTracker.UI.Web.WS.WebAccess.DoesUserExist(String
userName) in e:\My
Own\Projects\ProjectTracker\UI\ProjectTracker.UI.Web\WS\WebAccess.svc.cs:line
12 at SyncInvokeDoesUserExist(Object , Object[] , Object[] ) at
System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object
instance, Object[] inputs, Object[]& outputs) at
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&
rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean
isOperationContextSet)
Please advise me, what I am doing wrong here…
EF mapping conventions try to infer a one-to-one relationship between
User.CreatedByandUser.LastUpdatedBy. This fails because both navigation properties are represented with foreign keys that are not primary keys at the same time and because EF only supports shared primary key one-to-one relationships.Anyway, this is not important because you don’t want a one-to-one relationship but actually two one-to-many relationships: A user can create many other users and a user can modify many other users.
To achieve this you must override the conventions by explicitly defining the two relationships with Fluent API:
It might be necessary to make
CreatedByoptional, i.e.CreatedByUserIdmust be of typeint?and in the mapping above you must replaceHasRequiredbyHasOptional, because otherwise you could not create the very first user without violating the FK constraint.Possibly you could apply a trick, like creating the first user directly in the DB with
CreatedByUserIdallowingNULLvalues, assigning this user then as his own creator and then changing the DB schema so thatNULLis forbidden.Edit
More details about “EF mapping conventions try to infer a one-to-one relationship between
User.CreatedByandUser.LastUpdatedBy.“:When EF analyzes your model classes during startup it uses
Those set of cenventions gets applied unless otherwise explitly specified with Fluent API or data annotations. You can find the full set of conventions here: http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions(v=vs.103).aspx
In case of your original
Userclass it is theAssociationInverseDiscoveryConventionthat is applied for your model and detects a one-to-one relationship. The documentation says:The “only one” pair of navigation properties is
CreatedByinUserthat refers toUser– and inUseris a second navigation propertyLastUpdatedBythat refers back toUser. (It’s just a bit confusing because the “related types” are the same –UserandUser, but the convention applies here the same way as between different types.) Because both are references (and not collections) EF assumes that the relationship must be one-to-one (and not one-to-many or many-to-many).Sometimes conventions don’t infer the relationship as you want it. Then you must override the mapping conventions with Fluent API or data annotations. (Annotations are not sufficient in your example, you must use Fluent API here.)