[英]How to ensure that the WCF service will not communicate to the database in parallel
I have a WCF
service, which should return objects from database, but each entity should be returned only once. 我有一个
WCF
服务,该服务应该从数据库返回对象,但是每个实体只能返回一次。 I would like to avoid scenario, where many clients are using service, and they can get same Request
entity. 我想避免出现这样的情况:许多客户端正在使用服务,并且他们可以获得相同的
Request
实体。
public Request GetChangeRequest()
{
using (var context = new Data.Core.Context())
{
var request = context.Requests
.Where(r => r.IsAvaible)
.FirstOrDefault();
if (request != null)
{
request.IsAvaible = false;
context.SaveChanges();
}
return request;
}
}
I am really wondering if there is a reason to give additional security like locking database. 我真的很想知道是否有理由给予额外的安全性,例如锁定数据库。 To do this I have managed something like this:
为此,我已经管理了以下内容:
public Request GetChangeRequest()
{
using (var context = new Data.Core.Context())
{
context.OnLock<Request>(context.GetTableName<Request>(), () =>
{
var request = context.Requests
.Where(r => r.IsAvaible)
.FirstOrDefault();
if (request != null)
{
request.IsAvaible = false;
context.SaveChanges();
}
return request;
});
}
}
public static class DBContextExtensions
{
public static string GetTableName<T>(this DbContext context) where T : class
{
var type = typeof(T);
var entityName = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.CreateObjectSet<T>().EntitySet.Name;
var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.Schema.TableAttribute>().FirstOrDefault();
return tableAttribute == null ? entityName : tableAttribute.Name;
}
public static T OnLock<T>(this DbContext context, string tableName, Func<T> action)
{
T res;
using (DbContextTransaction scope = context.Database.BeginTransaction())
{
context.Database.ExecuteSqlCommand($"SELECT TOP 1 Id FROM {tableName} WITH (TABLOCKX, HOLDLOCK)");
res = action.Invoke();
scope.Commit();
}
return res;
}
}
I couldn't reproduce scenerio, when two request entity are returned to two different clients. 当两个请求实体返回给两个不同的客户端时,我无法重现Scenerio。 Does that mean, that
WCF
service performs requests sequentially? 这是否意味着
WCF
服务按顺序执行请求?
Instead of implementing a locking mechanism by yourself, one possible solution would be running the service as a singleton and not allowing parallel requests. 除了可能自己实现锁定机制之外,一种可能的解决方案是将服务作为单例运行,并且不允许并行请求。
You can achieve this by setting your WCF Service properties InstanceContextMode and ConcurrencyMode to Single . 您可以通过将WCF服务属性InstanceContextMode和ConcurrencyMode设置为Single来实现 。
For more information about Sessions, Instancing, and Concurrency see here . 有关会话,实例化和并发的更多信息,请参见此处 。
You should be able to use concurrency checking to make sure that only one entity is returned, without blocking the WCF to one query at a time. 您应该能够使用并发检查来确保仅返回一个实体,而不会一次阻止WCF一次查询。
You need a special field in you entity class with an attribute [Timestamp]
and then catch
the DbUpdateConcurrencyException
when saving, which will let you know that someone else has already returned that record, so you should get another one. 您在实体类中需要一个具有
[Timestamp]
属性的特殊字段,然后在DbUpdateConcurrencyException
时catch
DbUpdateConcurrencyException
,这将使您知道其他人已经返回了该记录,因此您应该获得另一个记录。
public class Request
{
...
[Timestamp]
public byte[] RowVersion { get; set; }
}
public Request GetChangeRequest()
{
using (var context = new Data.Core.Context())
{
while (true)
{
try
{
var request = context.Requests
.Where(r => r.IsAvaible)
.FirstOrDefault();
request.IsAvaible = false;
context.SaveChanges();
return request;
}
catch (DbUpdateConcurrencyException)
{
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.