简体   繁体   中英

Entity Framework - Model creation using class inheritance

Having a bit of a strange issue when trying to create a model object using inheritance with code first entity framework 6.1.

I've created a base User class in a shared code library and in my application I've created another User class inherited from the base class.

Base User class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using CSAMLib.Data.Entity;
using CSAMLib.Security.Cryptography;
using System.ComponentModel.DataAnnotations;

namespace CSAMLib.Security
{
    public class User : BaseEntity, CSAMLib.Security.IUser
    {
        public bool Active { get; set; }

        [Display(Name = "First name")]
        public String FirstName { get; set; }

        [Display(Name = "Last name")]
        public String LastName { get; set; }

        [Display(Name = "Full name")]
        public String FullName { get { return (FirstName == null ? String.Empty : FirstName + " ") + (LastName ?? String.Empty); } }

        [Display(Name = "Login", Prompt = "someone@example.com")]
        public String Login { get; set; }

        [Display(Name = "Email address")]
        public String EmailAddress { get; set; }

        public byte[] Password { get; set; }

        [Display(Name = "Last login date")]
        public DateTime? LastLoginDate { get; set; }

        [Display(Name = "Logged in")]
        public bool CurrentlyLoggedIn { get; set; }

        [Display(Name = "Signature filepath")]
        public byte[] SignatureFileContent { get; set; }

        [Display(Name = "Signature filename")]
        public String SignatureFileName { get; set; }

        [Display(Name = "Signature content")]
        public String SignatureContentType { get; set; }

        public String Qualification { get; set; }

        [NotMapped]
        public String NewPassword { get; set; }
        [NotMapped]
        public PasswordPolicy PasswordPolicy { get; set; }

        public virtual ICollection<UserRole> UserRoles
        {
            get;
            set;
        }

        public byte[] Salt { get; set; }

    }
}

User class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

namespace Muro.Models
{
    [Table("Users")]
    public class User : CSAMLib.Security.User
    {
        public bool ClientUser { get; set; }

        [Display(Name = "Company")]
        [ForeignKey("Company")]
        public Int64? CompanyID { get; set; }
        public virtual Company Company { get; set; }

        public new ICollection<UserRole> UserRoles
        {
            get;
            set;
        }


        public SystemUser CreateNewUser(string userName, string emailAddress, string firstName, string lastName)
        {
            var user = new Muro.Models.User();
            user.Login = userName;
            user.EmailAddress = emailAddress;
            user.Active = false;
            user.CurrentlyLoggedIn = false;
            user.FirstName = firstName;
            user.LastName = lastName;
            return user;
        }
    }

DBContext:

public DbSet<Muro.Models.User> Users { get; set; }

This approach resulted in the following error when running update-database:

The type 'CSAMLib.Security.User' and the type 'Muro.Models.User' both have the same simple name of 'User' and so cannot be used in the same model. All types in a given model must have unique simple names. Use 'NotMappedAttribute' or call Ignore in the Code First fluent API to explicitly exclude a property or type from the model.

I could understand this as both the class names share simple names. My next approach was to rename the application User class to SystemUser in order to get around this issue. However, I'm now getting the following error and not quite sure where to go next with this.

Error:

System.InvalidOperationException: Sequence contains more than one element
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Entity.ModelConfiguration.Conventions.ForeignKeyPrimitivePropertyAttributeConvention.Apply(PropertyInfo memberInfo, ConventionTypeConfiguration configuration, ForeignKeyAttribute attribute)
   at System.Data.Entity.ModelConfiguration.Conventions.PropertyAttributeConfigurationConvention`1.<.ctor>b__0(ConventionTypeConfiguration ec)
   at System.Data.Entity.ModelConfiguration.Conventions.TypeConvention.ApplyCore(Type memberInfo, ModelConfiguration modelConfiguration)
   at System.Data.Entity.ModelConfiguration.Conventions.TypeConventionBase.Apply(Type memberInfo, ModelConfiguration modelConfiguration)
   at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.ApplyModelConfiguration(Type type, ModelConfiguration modelConfiguration)
   at System.Data.Entity.ModelConfiguration.Conventions.Convention.ApplyModelConfiguration(Type type, ModelConfiguration modelConfiguration)
   at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.ApplyModelConfiguration(Type type, ModelConfiguration modelConfiguration)
   at System.Data.Entity.ModelConfiguration.Mappers.TypeMapper.MapEntityType(Type type)
   at System.Data.Entity.ModelConfiguration.Mappers.NavigationPropertyMapper.Map(PropertyInfo propertyInfo, EntityType entityType, Func`1 entityTypeConfiguration)
   at System.Data.Entity.ModelConfiguration.Mappers.TypeMapper.MapEntityType(Type type)
   at System.Data.Entity.ModelConfiguration.Mappers.NavigationPropertyMapper.Map(PropertyInfo propertyInfo, EntityType entityType, Func`1 entityTypeConfiguration)
   at System.Data.Entity.ModelConfiguration.Mappers.TypeMapper.MapEntityType(Type type)
   at System.Data.Entity.DbModelBuilder.<>c__DisplayClassd.<MapTypes>b__7(Type type)
   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
   at System.Data.Entity.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
   at System.Data.Entity.DbModelBuilder.MapTypes(EdmModel model)
   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.RetryLazy`2.GetValue(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   at System.Data.Entity.Internal.LazyInternalContext.get_ModelBeingInitialized()
   at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
   at System.Data.Entity.Utilities.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
   at System.Data.Entity.Utilities.DbContextExtensions.GetModel(Action`1 writeXml)
   at System.Data.Entity.Utilities.DbContextExtensions.GetModel(DbContext context)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
   at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
   at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Sequence contains more than one element

SystemUser class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

namespace Muro.Models
{
    [Table("Users")]
    public class SystemUser : CSAMLib.Security.User
    {
        public bool ClientUser { get; set; }

        [Display(Name = "Company")]
        [ForeignKey("Company")]
        public Int64? CompanyID { get; set; }
        public virtual Company Company { get; set; }

        public new ICollection<SystemUserRole> UserRoles
        {
            get;
            set;
        }


        public SystemUser CreateNewUser(string userName, string emailAddress, string firstName, string lastName)
        {
            var user = new Muro.Models.SystemUser();
            user.Login = userName;
            user.EmailAddress = emailAddress;
            user.Active = false;
            user.CurrentlyLoggedIn = false;
            user.FirstName = firstName;
            user.LastName = lastName;
            return user;
        }
    }
}

DBContext:

public DbSet<SystemUser> Users { get; set; }

Has anyone seen the same behaviour and has any tips to get around this?

Thanks!

I think the first problem has nothing to do with the second one (as you already solved that).

The exception tells you what the problem should be:
You call SingleOrDefault() on a collection which seems to have more then one item, which is not allowed by this method. You can do the following to solve this:

  • use FirstOrDefault to get the first element of the collection matching
  • adapt the search pattern so it only returns zero or one lement

If you show us the actual call to SingleOrDefault we may can help you better, but I can't find such a call in the posted code...

这是因为您的类具有[Table()]属性的相同值,尽管您重命名了类,但是您仍试图创建两个具有相同名称的表,这导致“序列包含多个元素”

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM