我在使用下面提到的代码时收到错误:InvalidOperationException:
using (MunimPlusContext context = new MunimPlusContext())
{
var dbGroup = context.GroupSet
.Where(x => x.GroupName.ToLower() == groupName.ToLower())
.SingleOrDefault();
if (dbGroup == null)
return true;
else
return dbGroup.GroupId == group.GroupId;
}
错误提供的详细信息是:
超时已过期。在获得a之前经过了超时时间 从游泳池连接。这可能是因为所有人都集中了 正在使用连接并达到最大池大小。
我使用下面提到的代码行来克服这个错误:
context.Database.Connection.Open();
我还使用了SQL Profiler,它按如下方式触发查询,但我不理解生成的SQL:
exec sp_executesql N'SELECT TOP(2) [Extent1]。[GroupId] AS [GroupId], [Extent1]。[GroupName] AS [GroupName], [Extent1]。[Alias] AS [Alias], [Extent1]。[ParentId] AS [ParentId], [Extent1]。[IsSystemGroup] AS [IsSystemGroup], [Extent1]。[NatureOfGroupId] AS [NatureOfGroupId], [Extent1]。[EffectId] AS [EffectId], [Extent1]。[BankDetailsVisibility] AS [BankDetailsVisibility], [Extent1]。[CreditLimitsVisibility] AS [CreditLimitsVisibility], [Extent1]。[GeneralDetailsVisibility] AS [GeneralDetailsVisibility], [Extent1]。[ContactDetailsVisibility] AS [ContactDetailsVisibility], [Extent1]。[TaxInformationVisibility] AS [TaxInformationVisibility] FROM [dbo]。[Group] AS [Extent1] WHERE((LOWER([Extent1]。[GroupName]))=(LOWER(@ p__linq__0)))OR((LOWER([Extent1]。[GroupName])IS NULL)AND(LOWER(@ p__linq__0)IS NULL)) ',N'@ p__linq__0 nvarchar(4000)',@ p__linq__0 = N'Primary' 去
当我尝试使用FluentValidation检查数据库中的重复项时,如下所示,我收到此错误:
RuleFor(obj => obj.GroupName).Must(UniqueName)
.WithMessage("Group with same name already exists. Please choose a different Group name");
以下是UniqueName方法,它是错误的来源:
private bool UniqueName(Group group, string groupName)
{
using (MunimPlusContext context = new MunimPlusContext())
{
var dbGroup = context.GroupSet
.Where(x => x.GroupName.ToLower() == groupName.ToLower())
.SingleOrDefault();
if (dbGroup == null)
return true;
else
return dbGroup.GroupId == group.GroupId;
}
}
这是完整的堆栈跟踪:
在 System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(的DbConnection owningConnection,TaskCompletionSource
1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource
1次重试,DbConnectionOptions userOptions)at at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(的DbConnection outerConnection,DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource
1 重试) System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource1 retry) at System.Data.SqlClient.SqlConnection.Open() at MunimPlus.Entities.Group.GroupValidator.UniqueName(Group group, String groupName) in H:\Work\Trial\New\MunimPlus\MunimPlusSolution\MunimPlus.Entities\Group.cs:line 274 at FluentValidation.DefaultValidatorExtensions.<>c__DisplayClass4
2.b__3(T x,TProperty val,PropertyValidatorContext propertyValidatorContext) 在 C:\项目\ FluentValidation \ SRC \ FluentValidation \ DefaultValidatorExtensions.cs:线 219在 FluentValidation.DefaultValidatorExtensions。&lt;&gt; c__DisplayClass72.<Must>b__6(Object instance, Object property, PropertyValidatorContext propertyValidatorContext) in c:\Projects\FluentValidation\src\FluentValidation\DefaultValidatorExtensions.cs:line 235 at FluentValidation.Validators.PredicateValidator.IsValid(PropertyValidatorContext context) in c:\Projects\FluentValidation\src\FluentValidation\Validators\PredicateValidator.cs:line 37 at FluentValidation.Validators.PropertyValidator.Validate(PropertyValidatorContext context) in c:\Projects\FluentValidation\src\FluentValidation\Validators\PropertyValidator.cs:line 71 at FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context, IPropertyValidator validator, String propertyName) in c:\Projects\FluentValidation\src\FluentValidation\Internal\PropertyRule.cs:line 346 at FluentValidation.Internal.PropertyRule.<Validate>d__10.MoveNext() in c:\Projects\FluentValidation\src\FluentValidation\Internal\PropertyRule.cs:line 234 at System.Linq.Enumerable.<SelectManyIterator>d__14
2.MoveNext()at System.Collections.Generic.List1..ctor(IEnumerable
1集合)
at System.Linq.Enumerable.ToList [TSource](IEnumerable1 source) at FluentValidation.AbstractValidator
1.Validate(ValidationContext1 context) in c:\Projects\FluentValidation\src\FluentValidation\AbstractValidator.cs:line 113 at FluentValidation.AbstractValidator
1.Validate(T instance)in C:\项目\ FluentValidation \ SRC \ FluentValidation \ AbstractValidator.cs:线 94点 FluentValidation.AbstractValidator1.FluentValidation.IValidator.Validate(Object instance) in c:\Projects\FluentValidation\src\FluentValidation\AbstractValidator.cs:line 55 at Core.Common.Core.EntityBase.Validate() in H:\Work\Trial\New\Core\Core.Common\Core\EntityBase.cs:line 206 at Core.Common.Core.EntityBase..ctor() in H:\Work\Trial\New\Core\Core.Common\Core\EntityBase.cs:line 25 at MunimPlus.Entities.Group..ctor() at lambda_method(Closure , Shaper ) at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func
2 constructEntityDelegate,EntityKey entityKey,EntitySet entitySet)
在lambda_method(Closure,Shaper)at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(整形 整形器)
如果我不使用context.Database.Connection.Open()
,那么我会收到另一个错误:
基础提供商无法开放。
但是在调用数据库之前,我还有一些其他调用工作正常。
如果我删除此验证,那么我的项目也可以正常工作。
我还想在这里显示我的连接字符串:
<connectionStrings>
<add name="MunimPlus"
connectionString="data source=.\SQLEXPRESS;Initial Catalog=Max;Integrated Security=SSPI"
providerName="System.Data.SqlClient" />
</connectionStrings>
对问题有一些暗示但没有解决方案。
我有一个名为EntityBase的基类。我的所有实体都继承自EntityBase。所以我的Group类看起来像:
public class Group : EntityBase
{
Fields.....
Properties....
class GroupValidator : AbstractValidator<T>
{
public GroupValidator()
{
RuleFor(obj => obj.GroupName).NotEmpty().WithMessage("Group name cannot be empty.");
RuleFor(obj => obj.GroupName).Must(UniqueName).WithMessage("Group with same name already exists. Please choose a different Group name");
RuleFor(obj => obj.ParentId).NotNull().WithMessage("Please select the group under which this group will appear")
.GreaterThan(0).WithMessage("Please select a valid/existing group name");
}
private bool UniqueName(Group group, string groupName)
{
if (groupName == null)
groupName = "";
using (MunimPlusContext context = new MunimPlusContext())
{
Group dbGroup = context.GroupSet.FirstOrDefault(x => x.GroupName.ToLower() == groupName.ToLower());
if (dbGroup == null)
return true;
else
return dbGroup.GroupId == group.GroupId;
}
}
}
protected override IValidator GetValidator()
{
return new GroupValidator();
}
}
查看最后一个名为GetValidator的方法,它是EntityBase类中定义的虚方法的重写版本。
现在,EntityBase类的一部分看起来像:
public abstract class EntityBase
{
public EntityBase()
{
_Validator = GetValidator();
Validate();
}
protected IValidator _Validator = null;
protected IEnumerable<ValidationFailure> _ValidationErrors = null;
protected virtual IValidator GetValidator()
{
return null;
}
public IEnumerable<ValidationFailure> ValidationErrors
{
get { return _ValidationErrors; }
set { }
}
public void Validate()
{
if (_Validator != null)
{
ValidationResult results = _Validator.Validate(this);
_ValidationErrors = results.Errors;
}
}
public virtual bool IsValid
{
get
{
if (_ValidationErrors != null && _ValidationErrors.Count() > 0)
return false;
else
return true;
}
}
}
现在在CarValidator类的UniqueName方法的行
中Group dbGroup = context.GroupSet.FirstOrDefault(x => x.GroupName.ToLower() == groupName.ToLower());
对于每个组,由于EntityBase类而创建并验证了新实例。因此,游标在using(MunimPlusContext context = new MunimPlusContext)
之间运行但从不关闭连接,因为它越来越深地创建组的新实例,因此达到了数据库中的最大连接。因此我得到连接池问题。
当我将Max Pool Size增加到999时,我得到另一个错误StackOverFlowException。
https://drive.google.com/file/d/0B5WyqSALui0bM252VXdveVVMMzQ/view?usp=sharing
答案 0 :(得分:1)
所以你现在拥有的是无限递归问题。所以它从这样开始:
EntityBase
中调用基础构造函数)。EntityBase
构造函数获取验证程序,然后调用其Validate
方法,最终调用UniqueName
。context.GroupSet.FirstOrDefault
行将创建一个新的Group
对象。这将使你再次回到第一步。这个制作对象的循环永远不会停止,直到你耗尽堆栈,这会导致你得到的堆栈溢出异常(在你遇到堆栈溢出之前达到连接池限制之前,连接池问题掩盖了真正的问题这里)。你可以试试几件事:
首先,将context.GroupSet.FirstOrDefault
更改为使用Any
而不是FirstOrDefault
。这样,第3步永远不会创建一个对象,也永远不会将您送回第1步。虽然这可以解决问题,但如果您需要在其他地方执行类似的操作,它可以轻松弹回。
第二个(并且到目前为止,更好)是不要在构造函数中调用Validate
。通常,您应该尝试在对象持久保存到数据库之前验证它,而不是在创建时(例如,验证一个全新的,空的对象在我填写它时不会对我有用。之后。我需要在保存之前进行验证,以确保我不会通过将某些数据组合放入对象来违反某些约束。)在我完成的项目中,我们做了类似的事情:
public class EntityBase
{
//...
public void Save()
{
//Validate here and check for errors
//If errors exist, throw an exception
//If no errors, persist to database.
}
}
显然,您必须弄清楚如何在项目中执行此操作。也许是通过存储库或服务,但在保存而不是创建之前,你最好不要进行验证。
(注意:我没有在您分享的代码中尝试任何此类代码,因为我无法运行我在互联网上传递的代码。)