none
Insert Failed. RRS feed

  • Question

  • Hello,

    I have the following entities:

    public class User {
     Int32 Id { get; set; }
     String Email { get; set; }
     IList<Role> Roles { get; set; }
    }
    
    public class Roles {
     Int32 Id { get; set; }
     String Name { get; set; }
    }
    
    
    

    I created a User as follows:

    Role role1 = new Role { Id = 1 };
    Role role2 = new Role { Id = 3 };
    
    User user = new User { Email = "john@aaaa.net };
    user.Roles.Add(role1);
    user.Roles.Add(role2);
    
    userRepository.Add(user);
    

    When I add the user I get the following error:

    {" Cannot insert the value NULL into column 'Name',  table 'App.dbo.Roles'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}

    In this case I receive the Roles only with the Ids.

    How can I check if the Roles are ready to be added?

    And if not then do something so that the User is added without any problems?

    Thanks,

    Miguel

     

     

    Monday, September 6, 2010 1:14 AM

Answers

  • Hi Miguel,

    The problem is that the context doesn't know that you already have those roles in the database.

    If the role already exists in the database you can solve this issue using one of the following options:

    1.- First get the role from the context (this will execute a db query behind the scenes), and then add it to the roles collection.

    2.- Use the Attach method of the context in order to tell it that this role already exists in the database. More info: http://msdn.microsoft.com/en-us/library/bb896245.aspx

    On the other hand, if the role doesn't exist in the database, you should fill all the mandatory fields (in this case, the name field too).

    Regards,

    Jorge

     

    • Proposed as answer by Jorge Fioranelli Monday, September 6, 2010 7:26 AM
    • Marked as answer by liurong luo Tuesday, September 7, 2010 12:16 PM
    Monday, September 6, 2010 6:10 AM
  • Hi Miguel,

    As the role is part of the user graph, I think that when you attach each role, you are attaching also the user. So then, when you are trying to add the user, the context gets confused because it already has that object attached.

    I think the First option fits better in scenarios where you have a mix of "new" objects and "existing" ones.

    But, if you want to avoid the database query, you can add this new repository's method:

    public void MarkAsAdded(User user)
    {
     context.ChangeObjectState(user, System.Data.EntityState.Added);
    } 
    
    

    And to replace the _userRepostiroy.Add(user) call by the _userRepository.MarkAsAdded(user) call, so your code should be:

    foreach (Role role in user.Roles)
      _roleRepository.Attach(role);
    
      _userRepository.MarkAsAdded(user); // instead of _userRepository.Add(user);
      _userRepository.Save();
    
    

    If this doesn't work, you should check the following:

    • Be sure all roles already exist in the database
    • Be sure the user doesn't exist in the database
    • Be sure all roles have different ids

    Regards

    Jorge

    • Proposed as answer by Jorge Fioranelli Monday, September 6, 2010 3:00 PM
    • Marked as answer by liurong luo Tuesday, September 7, 2010 12:16 PM
    Monday, September 6, 2010 2:59 PM
  • Hi Miguel,

    If the profile doesn't exist in the DB, you shoud do the same you are doing with the user (change its state):

    context.ObjectStateManager.ChangeObjectState(user.Profile, System.Data.EntityState.Added);
    
    

    You should call the Attach method only when the object already exists in the database.

     

    Regards,

    Jorge

     

    • Proposed as answer by Jorge Fioranelli Tuesday, September 7, 2010 1:08 AM
    • Marked as answer by MDMoura Wednesday, September 8, 2010 2:11 PM
    Tuesday, September 7, 2010 1:08 AM

All replies

  • Hi Miguel,

    The problem is that the context doesn't know that you already have those roles in the database.

    If the role already exists in the database you can solve this issue using one of the following options:

    1.- First get the role from the context (this will execute a db query behind the scenes), and then add it to the roles collection.

    2.- Use the Attach method of the context in order to tell it that this role already exists in the database. More info: http://msdn.microsoft.com/en-us/library/bb896245.aspx

    On the other hand, if the role doesn't exist in the database, you should fill all the mandatory fields (in this case, the name field too).

    Regards,

    Jorge

     

    • Proposed as answer by Jorge Fioranelli Monday, September 6, 2010 7:26 AM
    • Marked as answer by liurong luo Tuesday, September 7, 2010 12:16 PM
    Monday, September 6, 2010 6:10 AM
  • Hello,

    I tried the second option which avoids the query.

    So I did the following:

       foreach (Role role in user.Roles)
        _roleRepository.Attach(role);
    
       _userRepository.Add(user);
       _userRepository.Save();
    
    But I get the following error on _userRepository.Save() which basically save the changes:

    An object with the same key already exists in the ObjectStateManager. The existing object is in the Unchanged state. An object can only be added to the ObjectStateManager again if it is in the added state.

    What am I doing wrong?

    Thanks,

    Miguel

    Monday, September 6, 2010 10:46 AM
  • Hi Miguel,

    As the role is part of the user graph, I think that when you attach each role, you are attaching also the user. So then, when you are trying to add the user, the context gets confused because it already has that object attached.

    I think the First option fits better in scenarios where you have a mix of "new" objects and "existing" ones.

    But, if you want to avoid the database query, you can add this new repository's method:

    public void MarkAsAdded(User user)
    {
     context.ChangeObjectState(user, System.Data.EntityState.Added);
    } 
    
    

    And to replace the _userRepostiroy.Add(user) call by the _userRepository.MarkAsAdded(user) call, so your code should be:

    foreach (Role role in user.Roles)
      _roleRepository.Attach(role);
    
      _userRepository.MarkAsAdded(user); // instead of _userRepository.Add(user);
      _userRepository.Save();
    
    

    If this doesn't work, you should check the following:

    • Be sure all roles already exist in the database
    • Be sure the user doesn't exist in the database
    • Be sure all roles have different ids

    Regards

    Jorge

    • Proposed as answer by Jorge Fioranelli Monday, September 6, 2010 3:00 PM
    • Marked as answer by liurong luo Tuesday, September 7, 2010 12:16 PM
    Monday, September 6, 2010 2:59 PM
  • I added the following to method to my generic Repository:

      public void Mark(T entity, EntityState state) {
       _context.ObjectStateManager.ChangeObjectState(entity, state);
      } // Mark
    

    I think you were missing the ObjectStateManager or not? I got an error when not using it ...

    Then in my service I changed it to the following:

       foreach (Role role in user.Roles)
        _roleRepository.Attach(role);
    
       _userRepository.Mark(user, EntityState.Added);
       _userRepository.Save();
    

    And I checked:

    1 - All roles exist in the database. Id 1 to 4. I am using only Id = 1 and Id = 2;

    2 - The Users table in the database is empty.

    3 - All roles have different Ids.

    Then I ran the new code I get the following error:

    The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'App.Domain.User'.

    Does this make sense?

    Thanks,

    Miguel

    Monday, September 6, 2010 3:19 PM
  • Hi Miguel,

    Do the Role and the User have references to other objects?

    Could you copy and paste the definition of both classes?

    Regards,

    Jorge

    Monday, September 6, 2010 3:33 PM
  • Yes, User has a reference to Profile. I created a test EF4 model and I am posting the entire code:

    //------------------------------------------------------------------------------
    // <auto-generated>
    //  This code was generated from a template.
    //
    //  Manual changes to this file may cause unexpected behavior in your application.
    //  Manual changes to this file will be overwritten if the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    using System;
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    using System.Data.EntityClient;
    using System.ComponentModel;
    using System.Xml.Serialization;
    using System.Runtime.Serialization;
    
    [assembly: EdmSchemaAttribute()]
    #region EDM Relationship Metadata
    
    [assembly: EdmRelationshipAttribute("Test.EF4", "Profiles_Users_FK", "Users", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(Domain.TEMP.User), "Profiles", System.Data.Metadata.Edm.RelationshipMultiplicity.ZeroOrOne, typeof(Domain.TEMP.Profile), true)]
    [assembly: EdmRelationshipAttribute("Test.EF4", "UsersRoles", "Roles", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(Domain.TEMP.Role), "Users", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(Domain.TEMP.User))]
    
    #endregion
    
    namespace Domain.TEMP
    {
    
      public partial class Context : ObjectContext
      {
        public Context() : base("name=Context", "Context")
        {
          this.ContextOptions.LazyLoadingEnabled = true;
          OnContextCreated();
        }
      
        public Context(string connectionString) : base(connectionString, "Context")
        {
          this.ContextOptions.LazyLoadingEnabled = true;
          OnContextCreated();
        }
      
        public Context(EntityConnection connection) : base(connection, "Context")
        {
          this.ContextOptions.LazyLoadingEnabled = true;
          OnContextCreated();
        }
        
        partial void OnContextCreated();
      
        public ObjectSet<Profile> Profiles
        {
          get
          {
            if ((_Profiles == null))
            {
              _Profiles = base.CreateObjectSet<Profile>("Profiles");
            }
            return _Profiles;
          }
        }
        private ObjectSet<Profile> _Profiles;
      
        public ObjectSet<Role> Roles
        {
          get
          {
            if ((_Roles == null))
            {
              _Roles = base.CreateObjectSet<Role>("Roles");
            }
            return _Roles;
          }
        }
        private ObjectSet<Role> _Roles;
      
        public ObjectSet<User> Users
        {
          get
          {
            if ((_Users == null))
            {
              _Users = base.CreateObjectSet<User>("Users");
            }
            return _Users;
          }
        }
        private ObjectSet<User> _Users;
      
        public void AddToProfiles(Profile profile)
        {
          base.AddObject("Profiles", profile);
        }
      
        public void AddToRoles(Role role)
        {
          base.AddObject("Roles", role);
        }
      
        public void AddToUsers(User user)
        {
          base.AddObject("Users", user);
        }
    
      }
      
      [EdmEntityTypeAttribute(NamespaceName="Test.EF4", Name="Profile")]
      [Serializable()]
      [DataContractAttribute(IsReference=true)]
      public partial class Profile : EntityObject
      {
      
        public static Profile CreateProfile(global::System.Int32 id, global::System.DateTime birthday, global::System.String name)
        {
          Profile profile = new Profile();
          profile.Id = id;
          profile.Birthday = birthday;
          profile.Name = name;
          return profile;
        }
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Int32 Id
        {
          get
          {
            return _Id;
          }
          set
          {
            if (_Id != value)
            {
              OnIdChanging(value);
              ReportPropertyChanging("Id");
              _Id = StructuralObject.SetValidValue(value);
              ReportPropertyChanged("Id");
              OnIdChanged();
            }
          }
        }
        private global::System.Int32 _Id;
        partial void OnIdChanging(global::System.Int32 value);
        partial void OnIdChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime Birthday
        {
          get
          {
            return _Birthday;
          }
          set
          {
            OnBirthdayChanging(value);
            ReportPropertyChanging("Birthday");
            _Birthday = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("Birthday");
            OnBirthdayChanged();
          }
        }
        private global::System.DateTime _Birthday;
        partial void OnBirthdayChanging(global::System.DateTime value);
        partial void OnBirthdayChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
        [DataMemberAttribute()]
        public global::System.String City
        {
          get
          {
            return _City;
          }
          set
          {
            OnCityChanging(value);
            ReportPropertyChanging("City");
            _City = StructuralObject.SetValidValue(value, true);
            ReportPropertyChanged("City");
            OnCityChanged();
          }
        }
        private global::System.String _City;
        partial void OnCityChanging(global::System.String value);
        partial void OnCityChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
        [DataMemberAttribute()]
        public global::System.String Mobile
        {
          get
          {
            return _Mobile;
          }
          set
          {
            OnMobileChanging(value);
            ReportPropertyChanging("Mobile");
            _Mobile = StructuralObject.SetValidValue(value, true);
            ReportPropertyChanged("Mobile");
            OnMobileChanged();
          }
        }
        private global::System.String _Mobile;
        partial void OnMobileChanging(global::System.String value);
        partial void OnMobileChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.String Name
        {
          get
          {
            return _Name;
          }
          set
          {
            OnNameChanging(value);
            ReportPropertyChanging("Name");
            _Name = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Name");
            OnNameChanged();
          }
        }
        private global::System.String _Name;
        partial void OnNameChanging(global::System.String value);
        partial void OnNameChanged();
    
        [XmlIgnoreAttribute()]
        [SoapIgnoreAttribute()]
        [DataMemberAttribute()]
        [EdmRelationshipNavigationPropertyAttribute("Test.EF4", "Profiles_Users_FK", "Users")]
        public User User
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<User>("Test.EF4.Profiles_Users_FK", "Users").Value;
          }
          set
          {
            ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<User>("Test.EF4.Profiles_Users_FK", "Users").Value = value;
          }
        }
    
        [BrowsableAttribute(false)]
        [DataMemberAttribute()]
        public EntityReference<User> UserReference
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<User>("Test.EF4.Profiles_Users_FK", "Users");
          }
          set
          {
            if ((value != null))
            {
              ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<User>("Test.EF4.Profiles_Users_FK", "Users", value);
            }
          }
        }
    
      }
      
      [EdmEntityTypeAttribute(NamespaceName="Test.EF4", Name="Role")]
      [Serializable()]
      [DataContractAttribute(IsReference=true)]
      public partial class Role : EntityObject
      {
        #region Factory Method
      
        public static Role CreateRole(global::System.Int32 id, global::System.String name)
        {
          Role role = new Role();
          role.Id = id;
          role.Name = name;
          return role;
        }
    
        #endregion
        #region Primitive Properties
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Int32 Id
        {
          get
          {
            return _Id;
          }
          set
          {
            if (_Id != value)
            {
              OnIdChanging(value);
              ReportPropertyChanging("Id");
              _Id = StructuralObject.SetValidValue(value);
              ReportPropertyChanged("Id");
              OnIdChanged();
            }
          }
        }
        private global::System.Int32 _Id;
        partial void OnIdChanging(global::System.Int32 value);
        partial void OnIdChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.String Name
        {
          get
          {
            return _Name;
          }
          set
          {
            OnNameChanging(value);
            ReportPropertyChanging("Name");
            _Name = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Name");
            OnNameChanged();
          }
        }
        private global::System.String _Name;
        partial void OnNameChanging(global::System.String value);
        partial void OnNameChanged();
    
        #endregion
      
        #region Navigation Properties
      
        [XmlIgnoreAttribute()]
        [SoapIgnoreAttribute()]
        [DataMemberAttribute()]
        [EdmRelationshipNavigationPropertyAttribute("Test.EF4", "UsersRoles", "Users")]
        public EntityCollection<User> Users
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<User>("Test.EF4.UsersRoles", "Users");
          }
          set
          {
            if ((value != null))
            {
              ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<User>("Test.EF4.UsersRoles", "Users", value);
            }
          }
        }
    
        #endregion
      }
      
      [EdmEntityTypeAttribute(NamespaceName="Test.EF4", Name="User")]
      [Serializable()]
      [DataContractAttribute(IsReference=true)]
      public partial class User : EntityObject
      {
        #region Factory Method
      
        public static User CreateUser(global::System.Int32 id, global::System.Boolean approved, global::System.DateTime created, global::System.String email, global::System.DateTime lastLock, global::System.DateTime lastLogin, global::System.DateTime lastPasswordChange, global::System.DateTime lastReset, global::System.Boolean locked, global::System.Byte[] password, global::System.Int32 passwordAttemptCount, global::System.DateTime passwordAttemptStart, global::System.Byte[] salt, global::System.DateTime updated, global::System.String username)
        {
          User user = new User();
          user.Id = id;
          user.Approved = approved;
          user.Created = created;
          user.Email = email;
          user.LastLock = lastLock;
          user.LastLogin = lastLogin;
          user.LastPasswordChange = lastPasswordChange;
          user.LastReset = lastReset;
          user.Locked = locked;
          user.Password = password;
          user.PasswordAttemptCount = passwordAttemptCount;
          user.PasswordAttemptStart = passwordAttemptStart;
          user.Salt = salt;
          user.Updated = updated;
          user.Username = username;
          return user;
        }
    
        #endregion
        #region Primitive Properties
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Int32 Id
        {
          get
          {
            return _Id;
          }
          set
          {
            if (_Id != value)
            {
              OnIdChanging(value);
              ReportPropertyChanging("Id");
              _Id = StructuralObject.SetValidValue(value);
              ReportPropertyChanged("Id");
              OnIdChanged();
            }
          }
        }
        private global::System.Int32 _Id;
        partial void OnIdChanging(global::System.Int32 value);
        partial void OnIdChanged();
     
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Boolean Approved
        {
          get
          {
            return _Approved;
          }
          set
          {
            OnApprovedChanging(value);
            ReportPropertyChanging("Approved");
            _Approved = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("Approved");
            OnApprovedChanged();
          }
        }
        private global::System.Boolean _Approved;
        partial void OnApprovedChanging(global::System.Boolean value);
        partial void OnApprovedChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
        [DataMemberAttribute()]
        public global::System.String Comment
        {
          get
          {
            return _Comment;
          }
          set
          {
            OnCommentChanging(value);
            ReportPropertyChanging("Comment");
            _Comment = StructuralObject.SetValidValue(value, true);
            ReportPropertyChanged("Comment");
            OnCommentChanged();
          }
        }
        private global::System.String _Comment;
        partial void OnCommentChanging(global::System.String value);
        partial void OnCommentChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime Created
        {
          get
          {
            return _Created;
          }
          set
          {
            OnCreatedChanging(value);
            ReportPropertyChanging("Created");
            _Created = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("Created");
            OnCreatedChanged();
          }
        }
        private global::System.DateTime _Created;
        partial void OnCreatedChanging(global::System.DateTime value);
        partial void OnCreatedChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.String Email
        {
          get
          {
            return _Email;
          }
          set
          {
            OnEmailChanging(value);
            ReportPropertyChanging("Email");
            _Email = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Email");
            OnEmailChanged();
          }
        }
        private global::System.String _Email;
        partial void OnEmailChanging(global::System.String value);
        partial void OnEmailChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime LastLock
        {
          get
          {
            return _LastLock;
          }
          set
          {
            OnLastLockChanging(value);
            ReportPropertyChanging("LastLock");
            _LastLock = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("LastLock");
            OnLastLockChanged();
          }
        }
        private global::System.DateTime _LastLock;
        partial void OnLastLockChanging(global::System.DateTime value);
        partial void OnLastLockChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime LastLogin
        {
          get
          {
            return _LastLogin;
          }
          set
          {
            OnLastLoginChanging(value);
            ReportPropertyChanging("LastLogin");
            _LastLogin = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("LastLogin");
            OnLastLoginChanged();
          }
        }
        private global::System.DateTime _LastLogin;
        partial void OnLastLoginChanging(global::System.DateTime value);
        partial void OnLastLoginChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime LastPasswordChange
        {
          get
          {
            return _LastPasswordChange;
          }
          set
          {
            OnLastPasswordChangeChanging(value);
            ReportPropertyChanging("LastPasswordChange");
            _LastPasswordChange = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("LastPasswordChange");
            OnLastPasswordChangeChanged();
          }
        }
        private global::System.DateTime _LastPasswordChange;
        partial void OnLastPasswordChangeChanging(global::System.DateTime value);
        partial void OnLastPasswordChangeChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime LastReset
        {
          get
          {
            return _LastReset;
          }
          set
          {
            OnLastResetChanging(value);
            ReportPropertyChanging("LastReset");
            _LastReset = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("LastReset");
            OnLastResetChanged();
          }
        }
        private global::System.DateTime _LastReset;
        partial void OnLastResetChanging(global::System.DateTime value);
        partial void OnLastResetChanged();
     
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Boolean Locked
        {
          get
          {
            return _Locked;
          }
          set
          {
            OnLockedChanging(value);
            ReportPropertyChanging("Locked");
            _Locked = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("Locked");
            OnLockedChanged();
          }
        }
        private global::System.Boolean _Locked;
        partial void OnLockedChanging(global::System.Boolean value);
        partial void OnLockedChanged();
     
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Byte[] Password
        {
          get
          {
            return StructuralObject.GetValidValue(_Password);
          }
          set
          {
            OnPasswordChanging(value);
            ReportPropertyChanging("Password");
            _Password = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Password");
            OnPasswordChanged();
          }
        }
        private global::System.Byte[] _Password;
        partial void OnPasswordChanging(global::System.Byte[] value);
        partial void OnPasswordChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Int32 PasswordAttemptCount
        {
          get
          {
            return _PasswordAttemptCount;
          }
          set
          {
            OnPasswordAttemptCountChanging(value);
            ReportPropertyChanging("PasswordAttemptCount");
            _PasswordAttemptCount = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("PasswordAttemptCount");
            OnPasswordAttemptCountChanged();
          }
        }
        private global::System.Int32 _PasswordAttemptCount;
        partial void OnPasswordAttemptCountChanging(global::System.Int32 value);
        partial void OnPasswordAttemptCountChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime PasswordAttemptStart
        {
          get
          {
            return _PasswordAttemptStart;
          }
          set
          {
            OnPasswordAttemptStartChanging(value);
            ReportPropertyChanging("PasswordAttemptStart");
            _PasswordAttemptStart = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("PasswordAttemptStart");
            OnPasswordAttemptStartChanged();
          }
        }
        private global::System.DateTime _PasswordAttemptStart;
        partial void OnPasswordAttemptStartChanging(global::System.DateTime value);
        partial void OnPasswordAttemptStartChanged();
      
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.Byte[] Salt
        {
          get
          {
            return StructuralObject.GetValidValue(_Salt);
          }
          set
          {
            OnSaltChanging(value);
            ReportPropertyChanging("Salt");
            _Salt = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Salt");
            OnSaltChanged();
          }
        }
        private global::System.Byte[] _Salt;
        partial void OnSaltChanging(global::System.Byte[] value);
        partial void OnSaltChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.DateTime Updated
        {
          get
          {
            return _Updated;
          }
          set
          {
            OnUpdatedChanging(value);
            ReportPropertyChanging("Updated");
            _Updated = StructuralObject.SetValidValue(value);
            ReportPropertyChanged("Updated");
            OnUpdatedChanged();
          }
        }
        private global::System.DateTime _Updated;
        partial void OnUpdatedChanging(global::System.DateTime value);
        partial void OnUpdatedChanged();
    
        [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
        [DataMemberAttribute()]
        public global::System.String Username
        {
          get
          {
            return _Username;
          }
          set
          {
            OnUsernameChanging(value);
            ReportPropertyChanging("Username");
            _Username = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Username");
            OnUsernameChanged();
          }
        }
        private global::System.String _Username;
        partial void OnUsernameChanging(global::System.String value);
        partial void OnUsernameChanged();
    
        [XmlIgnoreAttribute()]
        [SoapIgnoreAttribute()]
        [DataMemberAttribute()]
        [EdmRelationshipNavigationPropertyAttribute("Test.EF4", "Profiles_Users_FK", "Profiles")]
        public Profile Profile
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Profile>("Test.EF4.Profiles_Users_FK", "Profiles").Value;
          }
          set
          {
            ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Profile>("Test.EF4.Profiles_Users_FK", "Profiles").Value = value;
          }
        }
        /// <summary>
        /// No Metadata Documentation available.
        /// </summary>
        [BrowsableAttribute(false)]
        [DataMemberAttribute()]
        public EntityReference<Profile> ProfileReference
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Profile>("Test.EF4.Profiles_Users_FK", "Profiles");
          }
          set
          {
            if ((value != null))
            {
              ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<Profile>("Test.EF4.Profiles_Users_FK", "Profiles", value);
            }
          }
        }
    
        [XmlIgnoreAttribute()]
        [SoapIgnoreAttribute()]
        [DataMemberAttribute()]
        [EdmRelationshipNavigationPropertyAttribute("Test.EF4", "UsersRoles", "Roles")]
        public EntityCollection<Role> Roles
        {
          get
          {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<Role>("Test.EF4.UsersRoles", "Roles");
          }
          set
          {
            if ((value != null))
            {
              ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Role>("Test.EF4.UsersRoles", "Roles", value);
            }
          }
        }
      }
      
    }
    
    

    Do you need me to post the T-SQL code that generates these tables?

    Thanks,

    Miguel

     

    Monday, September 6, 2010 3:54 PM
  • Hello,

    I think I was able to identify the problem but not to solve it.

    To keep it simple I used the context directly instead of the repositories and services. So I have the following:

     Context context = new Context();
    
     User user = new User {
      Email = "john@xyz.com",
      Username = "johnusr",
      Profile = new Profile { Birthday = DateTime.UtcNow, City = "Lisbon" },
     };
      
     Role administrator = new Role { Id = 1 };
     Role collaborator = new Role { Id = 2 };
    

    I tried three options after this code:

    1) Didn't attach the roles. Just added them to the User entity:    

     

     user.Roles.Add(administrator);
     user.Roles.Add(collaborator);
      
     context.AddToUsers(user);
     context.SaveChanges();
    

     

        And I got the following error:

        Cannot insert the value NULL into column 'Name', table 'dbo.Roles'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}

    2) Attached the roles BEFORE adding them to the user:

     

      context.AttachTo("Roles", administrator);
      context.AttachTo("Roles", collaborator);
    
      user.Roles.Add(administrator);
      user.Roles.Add(collaborator);
      
      context.AddToUsers(user);
      context.SaveChanges();
    
    This works!

     

    3) Attached the roles AFTER adding them to the user:

     

      user.Roles.Add(administrator);
      user.Roles.Add(collaborator);
    
      context.AttachTo("Roles", administrator);
      context.AttachTo("Roles", collaborator);
      
      context.AddToUsers(user);
      context.SaveChanges();
    

     

        And I got the following error:

        An object with the same key already exists in the ObjectStateManager. The existing object is in the Unchanged state. An object can only be added to the ObjectStateManager again if it is in the added state.

     

    Now let me explain what I am doing:

    I am using ASP.NET MVC. So in a form the user inserts some information: Email, Username, Roles, etc.

    What I get is a View Model with the Email, Username and Roles IDs.

    Then I map the View Model to the Entity ... And I get an entity where the Roles have only the ID's.

    Should I, in the mapping, get the complete roles using the RoleRepository? In my opinion not ... The mapper shouldn't use repositories.

     

    So when I send the user to the service I get a User with Roles as in situation 3.

    It is in UserService that I would like to fill the blanks.

    So what I would like to make work is situation 3.

     

    I have been a lot of trouble when using ASP.NET MVC with EF4.

    Does all this make sense? Does anyone has a solution?

    Thanks,

    Miguel

     

    P.S: During this process I started to have suspect the problem was on my Repositories / Services implementation.

           So I created another posted which ended going in the same direction as this one:

           http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/ac59d90b-a881-4568-9a18-d684cdf1c64a/

           I am going to post this answer there to as I don't know if I could merge both posts.

           Thank You,

           Miguel

    Tuesday, September 7, 2010 12:11 AM
  • Hi Miguel,

    I have created an scenario similar to yours, and the code is working for me.

    User
    ----
    Id
    Name
    Roles
    Profiles

    Role
    ----
    Id
    Name
    Users

    Profile
    -------
    Id
    Name
    UserId
    User

    This is the code:

    var user = new User
        {
         Name = "User1",
         Roles =
          {
           new Role {Id = 1},
           new Role {Id = 2}
          }
        };
    
    using (var context = new EntityModelContainer())
    {
     foreach (var role in user.Roles)
      context.Roles.Attach(role);
    
     context.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Added);
    
     context.SaveChanges();
    }

    As you, I already had 4 roles in the DB (Ids 1 to 4) and 0 rows in the Users and Profiles tables

    After the execution of the previous code, a new row was added to the Users table.

    What about Profiles? Are you filling this association?

    Could you please try creating the project again?

     

    Regards,

    Jorge

    Tuesday, September 7, 2010 12:14 AM
  • Check the example I just posted on my last thread. In there I am setting the Profile.

    I also explain very well the circumstances in which the problem happens.

    I am going to try recreate my project to check if something changes.

    What do you think about the 3 scenarios I just posted?

    Does it help in any way?

    Tuesday, September 7, 2010 12:20 AM
  • I recreated the project and used your solution as follows:

       Context context = new Context();
    
       User user = new User {
        Email = "john@xyz.xyz",
        Profile = new Profile { Birthday = DateTime.UtcNow, City = "Lisbon", Name = "Miguel" },
        Username = "johnusr",
        Roles = { new Role {Id = 1}, new Role {Id = 2} }
       };
       
       foreach (var role in user.Roles)
        context.Roles.Attach(role);
    
       context.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Added);
    
       context.SaveChanges();
    

    It create the user but not the profile.

    And I got a warning:

    The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.

    Any idea why the profile is not being created? I suppose it needs to be attached to?

    But there is still this strange warning which I think it would be better to get rid of it ...

    Tuesday, September 7, 2010 12:32 AM
  • I tried the following:

       foreach (var role in user.Roles)
        context.Roles.Attach(role);
    
       context.Profiles.Attach(user.Profile);
    
       context.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Added);
    
    But the profile is not added ...

    Tuesday, September 7, 2010 12:34 AM
  • Hi Miguel,

    If the profile doesn't exist in the DB, you shoud do the same you are doing with the user (change its state):

    context.ObjectStateManager.ChangeObjectState(user.Profile, System.Data.EntityState.Added);
    
    

    You should call the Attach method only when the object already exists in the database.

     

    Regards,

    Jorge

     

    • Proposed as answer by Jorge Fioranelli Tuesday, September 7, 2010 1:08 AM
    • Marked as answer by MDMoura Wednesday, September 8, 2010 2:11 PM
    Tuesday, September 7, 2010 1:08 AM
  • Hi,

    I am away from my computer but I will give it a try later today and post here the result, ok?

    Thank You for the Help,

    Miguel

    Tuesday, September 7, 2010 12:41 PM
  • Hello,

    I made it work but I suppose something in EF4 could be improved. 

    I ended up with some code that seems to have a few hacks. Considerer the following:

     public class UserService : IUserService {
    
      private ProfileRepository _profileRepository;
      private RoleRepository _roleRepository;
      private UserRepository _userRepository;
    
      public UserService()
       : this(new ProfileRepository(), new RoleRepository(), new UserRepository()) {
      } // UserService
    
      public UserService(IProfileRepository profileRepository, IRoleRepository roleRepository, IUserRepository userRepository) {
    
       _profileRepository = (ProfileRepository)profileRepository;
       _roleRepository = (RoleRepository)roleRepository;
       _userRepository = (UserRepository)userRepository;
    
      } // UserService
    
      public void Create(User user) {
    
       foreach (Role role in user.Roles)
        _roleRepository.Attach(role);
    
       _profileRepository.Mark(user.Profile, EntityState.Added);
    
       _userRepository.Mark(user, EntityState.Added);
    
       _userRepository.Save();
    
      } // Create
    

    This only works if profileRepository, userRepository and roleRepository share all the same context.

    So the first constructor does not work.

    What it seems strange to me is that if I am creating a User I should be able to do it without needing to use the Profile and Role repositories since Profile and Role are child entities of User.

    I don't know but it seems, even if EF4 is a good improvement over EF3, it should be better in theses cases.

    Does this make sense?

    Tuesday, September 7, 2010 11:14 PM
  • Hi Miguel,

    Since you have an n-tier application, you have a "disconnected" entity graph with a mixed state (some entities are new and other ones aren't).

    In those scenarios, you need to specify which ones are new and which ones already exist in the database (you can also load from the context those entities that already exist, but you wanted to avoid the round trip).

    Regarding to share the context between repositories, I strongly believe that it is a good practise. Otherwise you are going to work with different instances of the same entity (each context has its own isolated store). I recommend you to use an IOC Container in order to inject the same context's instance in all the repositories.

     

    Regards,

    Jorge

    Wednesday, September 8, 2010 11:27 PM
  • Since you have an n-tier application, you have a "disconnected" entity graph with a mixed state (some entities are new and other ones aren't).

    In those scenarios, you need to specify which ones are new and which ones already exist in the database (you can also load from the context those entities that already exist, but you wanted to avoid the round trip).

    But what do you recommend? Is there an alternative to what I am doing?

    How would you do it even if it contains a round trip?

    I though that avoiding round trips would be the best way to avoid delays.

     

    In relation to IOC I am already using StructureMap to inject the Context.

    In relation to that I am injecting the Context in the Repositories. I only need to decide one of the two:

    1  - Inject the repositories in the services

          OR

    2 - Inject the context in the services and inside the service create repositories with that context

    What do you think is more correct?

    Thanks,

    Miguel

    Wednesday, September 8, 2010 11:33 PM
  • Hi Miguel,

    I agree that avoiding round trips is a good way to avoid delays, and avoiding delays is always good.

    The other option you could chose is to load the roles (the already persisted entities in your scenario) from the context (round trip) and replace the "disconected" ones before adding the user.

    Regarding the IOC, although both are ok I "personally" prefer the first option. But, since the "save" method is persisting the changes of all repositories (shared context) I would extract this behavior from the repository object and I would call it from the service.

    To do this, you can use the second IOC option in order to get access to the context inside the service, or even better, you could encapsulate the context using another object (e.g. UnitOfWork) and call it from the service.

    Some draft code:

    public class UnitOfWork<TContext> : IUnitOfWork
    {
      public TContext Context { get; set; }
    
      public void Save()
      {
        Context.SaveChanges();
      }
    }
    

    Regards,

    Jorge

    Thursday, September 9, 2010 12:47 AM
  • When you get this message it mean that the table field you try to insert into does not allow nulls do one of the following, either create a default value constraint on the column in the database, or create a function to handle null values...

     

    Example: here's a function that convert null values to empty strings.

     

            Public Function ToNonNullString(ByVal param As String) As String

                Return If(param Is Nothing, String.Empty, param)

            End Function

    when you have a value for example "email" then you just
    object = ToNonNullString(email)
    Hope this help!


    shurland moore
    Friday, July 1, 2011 11:44 AM
  • On 7/1/2011 7:44 AM, webxgrammer wrote:
    > When you get this message it mean that the table field you try to insert
    > into does not allow nulls do one of the following, either create a
    > default value constraint on the column in the database, or create a
    > function to handle null values...
    >
     
    EF is not going to trigger any default value when inserting a row in the
    database.
     
    Friday, July 1, 2011 1:57 PM