我正在尝试调试现有的ASP.NET Web应用程序,并且在登录时遇到异常:
不能从用法中推断出类型参数。尝试显式指定类型参数。缺少潜在的异常处理
据我所知,发生错误是因为在运行以下代码时,已将{strong> duplicate 程序集加载到varTypesToRegister
中:
var typesToRegister = Assembly.GetAssembly(assemblyClassType).GetTypes()
.Where(type => type.Namespace != null)
“结果”视图中有91个元素,而最后10个元素似乎是重复的,因为它们已存在于数组/列表的前0-80个项目中。第一个异常引发在元素81上(请参见下面的屏幕截图)。如您所见,元素81已经作为元素24存在。因此,当试图将已经存在的程序集添加到modelBuilder时,将引发异常。
注意:assemblyClassType
只是传入的一个程序集。此代码似乎可以获取所有项目程序集,尽管我不确定这是如何发生或为什么发生(我是这个项目和原始开发人员的新手不可用)。
问题:是否有办法防止将重复的程序集加载到typesToRegister
中?或者,有没有一种方法可以防止代码尝试将重复代码加载到modelBuilder中:
foreach (Type type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance); // Exception thrown here
}
GroupMap.cs
public class GroupMap : EntityTypeConfiguration<Group>
{
public GroupMap()
{
Property(group => group.Name).IsRequired();
HasMany(group => group.Roles)
.WithMany(role => role.Groups)
.Map(m =>
{
m.MapLeftKey("GroupId");
m.MapRightKey("RoleId");
m.ToTable("GroupRoles");
});
HasMany(group => group.Members)
.WithMany(user => user.Groups)
.Map(m =>
{
m.MapLeftKey("GroupId");
m.MapRightKey("PersonId");
m.ToTable("GroupMembers");
});
}
}
Group.cs
public class Group : BaseEntity
{
private ICollection<Person> _members;
private ICollection<Role> _roles;
public Group()
{
_members = new HashSet<Person>();
_roles = new HashSet<Role>();
}
[Display(Name = "Group Name")]
[Required(ErrorMessage = "Group Name is required.")]
[MaxLength(100, ErrorMessage = "Group Name allows only 100 characters.")]
public string Name { get; set; }
public virtual ICollection<Person> Members
{
get { return _members; }
set { _members = value; }
}
public virtual ICollection<Role> Roles
{
get { return _roles; }
set { _roles = value; }
}
}
BaseDbContext.cs
public class BaseDbContext<TContext> : DbContext where TContext : DbContext, IDbContext, IObjectContextAdapter
{
static BaseDbContext()
{
Database.SetInitializer<TContext>(null);
}
public void RunConventions(DbModelBuilder modelBuilder, Type assemblyClassType)
{
// Change default conventions for cascade deletes
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
// Id property in everyclass is named class + Id (i.e CustomerId, JobId, VendorId)
// Id is always first column in table
// Could also explicitly determine as key using .Configure(p => p.IsKey() but EF already looks for property of name Id as primary key
modelBuilder.Properties()
.Where(p => p.Name == "Id")
.Configure(p => p.HasColumnOrder(0).HasColumnName((p.ClrPropertyInfo.ReflectedType == null ? "" : p.ClrPropertyInfo.ReflectedType.Name) + "Id"));
// Add Domain Entity Mapping Configurations
//var typesToRegister = Assembly.GetAssembly(assemblyClassType).GetTypes()
// .Where(type => type.Namespace != null);
var typesToRegister = Assembly.GetAssembly(typeof(DbContext)).GetTypes()
.Where(type => type.Namespace != null && type.Namespace.Equals(typeof(BaseDbContext<TContext>).Namespace))
.Where(type => type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (Type type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
}
}
答案 0 :(得分:1)
我认为问题在于:
var typesToRegister = Assembly.GetAssembly(assemblyClassType).GetTypes()
.Where(type => type.Namespace != null)
这将提取所有类定义,而不仅仅是IEntityTypeConfiguration实现。
尝试将其更新为:
var typesToRegister = Assembly.GetAssembly(assemblyClassType).GetTypes()
.Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))).ToList();
这应该只是尝试注册实体类型配置。
另一个小细节是,您可能还应该添加一个Ignore(galaxyUser => galaxyUser.IsSysAdmin);
。
编辑:对不起,对于EF 6,您无需显式指定要注册的类型,即EF核心限制。对于EF 6:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.AddFromAssembly(Assembly.GetAssembly(assemblyClassType));
}
答案 1 :(得分:1)
如果要添加所有配置,那么我认为使用EF 4.5.x可以使用AddFromAssembly
,
modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);
//OR typeof(DBContext).Assembly
关于此问题,您可以这样尝试吗:
var typesToRegister = Assembly.GetAssembly(typeof(DbContext)).GetTypes()
.Where(type => type.Namespace != null
&& type.Namespace.Equals(typeof(DBContext).Namespace))
.Where(type => type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() ==
typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
答案 2 :(得分:0)
我找到了解决方案。在“结果视图”中四处搜寻之后,在朋友的帮助下,我们发现重复项实际上不是重复项-它们具有不同的GUID。两者的区别在于,一个嵌套,而另一个未嵌套。未加载的副本具有IsNested = True。因此,解决方案是过滤掉IsNested == false
var typesToRegister = Assembly.GetAssembly(assemblyClassType).GetTypes()
.Where(type => type.Namespace != null && type.IsNested == false);