网站安全检测发生告警后邮局网站建设的目的
网站安全检测发生告警后,邮局网站建设的目的,网页插件开发,济南集团网站建设价格返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点#xff0c;它旨在成为一个通用的WEB应用程序框架和项目模板。 ABP的官方网站#xff1a;http://www.aspnetboilerp…返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点它旨在成为一个通用的WEB应用程序框架和项目模板。 ABP的官方网站http://www.aspnetboilerplate.com ABP官方文档http://www.aspnetboilerplate.com/Pages/Documents Github上的开源项目https://github.com/aspnetboilerplate 一、公共连接和事务管理方法 在使用了数据库的应用中连接和事务管理是最重要的概念之一。何时打开一个连接,何时开始一个事务如何释放连接等等。 你可能已经知道Net使用了连接池。因此创建一个连接实际上是从连接池中获取一个连接因为因为创建一个连接是有消耗的。如果在连接池中没有可用的连接那么会创建一个新的连接并将该连接加入连接池。当你释放连接时实际上是将该连接发送回给连接池并没有完全释放。这种机制是.Net提供的立即可用的功能。因此在我们使用完一个连接后应该立即释放在需要的时候才创建一个新的连接。总之最佳实践记住这八个字足矣尽晚打开尽早释放。 在一个应用中创建或者释放一个数据库连接通常有2种方法。 第一种方法当Web请求开始在Global.asax的Application_BeginRequest事件中的时候创建一个连接在所有的数据库操作时使用相同的连接并且在请求结束Application_EndRequest时关闭或者释放该连接。这种方法很简单但是不够高效。why 在一个请求中也许没有数据库操作但是连接已经打开了。这造成了连接池的无效使用。在一次请求中可能请求需要消耗很长的时间而数据库操作只花费很短的时间这也会造成连接池的无效使用这只在Web应用中是可行的。如果应用是一个Windows服务那么可能不会实现。以事务的方式执行数据库操作已被认为是一种最佳实践。如果一个操作失败了那么所有的操作都会回滚。因为一个事务可以锁定数据库中的一些行甚至表所以它必须是短暂存活的。 第二种方法当需要时仅在使用前创建一个连接使用后立即关闭。这是最有效的但是到处创建或者释放连接是一项重复乏味的工作。 二、ABP中的连接和事务管理 ABP兼备了这两种方法并且提供了一个简单而又有效的模型。 1、仓储类 仓储式执行数据库操作主要的类。当进入一个仓储方法时ABP会打开一个数据库连接可能不是立即打开但是在第一次使用数据库时肯定是打开的取决于ORM提供者的实现并开始一个事务。因此在一个仓储方法中可以安全地使用连接。在方法的结束事务被提交并且连接被释放。如果仓储方法抛出任何异常那么事务都会回滚且连接被释放。这样一来仓储方法就是原子的一个工作单元。ABP对于这些会自动处理。这里是一个简单的仓储 public class ContentRepository : NhRepositoryBaseContent, IContentRepository
{public ListContent GetActiveContents(string searchCondition){var query from content in Session.QueryContent()where content.IsActive !content.IsDeletedselect content;if (!string.IsNullOrEmpty(searchCondition)){query query.Where(content content.Text.Contains(searchCondition));}return query.ToList();}
} 这个例子使用了NHibernate作为ORM。正如上面演示的没有编写数据库连接在NHibernate中是Session打开或者关闭的代码。 如果一个仓储方法调用了其他的仓储方法一般而言如果一个工作单元调用了其他的工作单元方法那么它们共享相同的连接和事务。第一个进入的方法管理连接和事务其他方法使用相同的连接和事务。 2、应用服务 一个应用服务也被认为是一个工作单元。假设我们有一个像下面的应用服务 public class PersonAppService : IPersonAppService
{private readonly IPersonRepository _personRepository;private readonly IStatisticsRepository _statisticsRepository;public PersonAppService(IPersonRepository personRepository, IStatisticsRepository statisticsRepository){_personRepository personRepository;_statisticsRepository statisticsRepository;}public void CreatePerson(CreatePersonInput input){var person new Person { Name input.Name, EmailAddress input.EmailAddress };_personRepository.Insert(person);_statisticsRepository.IncrementPeopleCount();}
} 在CreatePerson方法中我们使用了person仓储插入了一个person而且使用statistics仓储增加总人数。在这里例子中这两个仓储共享相同的连接和事务因为它们在一个应用服务方法中。ABP在进入CreatePerson方法时打开一个数据库连接并开始一个事务如果没有抛出异常事务会在方法结尾时提交如果有任何异常发生将会回滚。这样一来在CreatePerson方法中的所有数据库操作都成了原子的工作单元。 3、工作单元 工作单元对于仓储和应用服务方法隐式有效。如果你想在其他地方控制数据库连接和事务那么可以显式使用它。 UnitOfWork特性: 最受人欢迎的方法是使用UnitOfWorkAttribute。例如 [UnitOfWork]
public void CreatePerson(CreatePersonInput input)
{var person new Person { Name input.Name, EmailAddress input.EmailAddress };_personRepository.Insert(person);_statisticsRepository.IncrementPeopleCount();
} 这样CreatePerson方法变成了工作单元并且管理数据库连接和事务两个仓储使用相同的工作单元注意的是如果这是一个应用服务方法就不需要UnitOfWork特性。 IUnitOfWorkManager: 第二种方法是使用IUnitOfWorkManager.Begin()方法例如 public class MyService
{private readonly IUnitOfWorkManager _unitOfWorkManager;private readonly IPersonRepository _personRepository;private readonly IStatisticsRepository _statisticsRepository;public MyService(IUnitOfWorkManager unitOfWorkManager, IPersonRepository personRepository, IStatisticsRepository statisticsRepository){_unitOfWorkManager unitOfWorkManager;_personRepository personRepository;_statisticsRepository statisticsRepository;}public void CreatePerson(CreatePersonInput input){var person new Person { Name input.Name, EmailAddress input.EmailAddress };using (var unitOfWork _unitOfWorkManager.Begin()){_personRepository.Insert(person);_statisticsRepository.IncrementPeopleCount();unitOfWork.Complete();}}
} 你可以注入然后使用IUnitOfWork正如这里演示的这样如果你的应用继承自ApplicationService类那么你可以直接使用CurrentUnitOfWork属性。如果没有你要先注入IUnitOfWorkManager。这样你就可以创建更多的限制作用域的工作单元。用这种方法你应该手动调用Complete方法。如果没有调用事务就会回滚改变就不会保存。 Begin方法有很多重载来设置工作单元选项。 如果找不到一个很好的理由建议还是使用UnitOfWork特性因为代码越短越好。 三、工作单元详解 1、关闭工作单元 有时候你可能想关闭应用服务方法的工作单元因为默认是开启的此时可以使用UnitOfWorkAttribute的IsDisabled属性。用法如下 [UnitOfWork(IsDisabled true)]
public virtual void RemoveFriendship(RemoveFriendshipInput input)
{_friendshipRepository.Delete(input.Id);
} 正常情况下不需要关闭数据单元因为应用服务方法应该是原子的且一般都会使用数据库。但也有些例外情况让你想要关闭应用服务方法的工作单元 方法不执行任何数据库操作而且你也不想打开一个没有必要的数据库连接。如上面描述的你想要在一个UnitOfWorkScope类的有限作用域内使用工作单元。注意如果一个工作单元方法调用了这个RemoveFriendship方法那么后者的关闭工作单元的功能将会失效并且也会使用和调用者方法相同的工作单元。因此要小心使用工作单元的关闭功能。 2、非事务的工作单元 工作单元默认是事务的本质如此。因此ABP会开始-提交-回滚一个显式的数据库级别的事务。在一些特殊场合事务可能会造成问题因为它可能会锁住数据库中的一些行或者表。在这种情况下你可能想关闭数据库级别的事务。UnitOfWork特性可以在构造函数中获得一个布尔值从而以非事务形式工作。用法如下 [UnitOfWork(isTransactional: false)]
public GetTasksOutput GetTasks(GetTasksInput input)
{var tasks _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);return new GetTasksOutput{Tasks Mapper.MapListTaskDto(tasks)};
} 建议使用[UnitOfWork(isTransactional: false)]因为它是更具可读性的但你也可以使用[UnitOfWork(false)]。 注意ORM框架如EF和NH内部使用了一条单一命令来保存更改。假设你以非事务的UOW工作单元更新了一些实体的情景甚至在这种情况下所有的更新都是在工作单元结束时以一个单一的数据库命令执行的。但是如果你直接执行一个SQL查询它会立即执行。 非事务的UOW有一个限制。如果你已经处于一个事务的工作单元的作用域内那么将isTransactional设置为false将会被忽略。 使用非事务的工作单元要小心因为大多数时候对于数据的集成是事务的。如果你的方法只是读数据不需要改变数据当然该方法是可以为非事务的了。 3、工作单元方法调用其它 如果一个工作单元的方法使用了UnitOfWork特性声明的方法调用另一个工作单元的方法那么它们共享相同的连接和事务。第一个方法管理连接其他方法使用连接。这个对于运行在相同线程的方法是成立的对于web应用则是相同的请求。实际上当一个工作单元作用域开始时在同一线程执行的所有代码都共享同一个连接和事务直到工作单元作用域结束。这对于UnitOfWork特性和UnitOfWorkScope类都是成立的。 4、工作单元作用域 在其他事务中可以创建一个不同而又隔离的事务或者可以在一个事务中创建一个非事务的作用域。.Net中定义了TransactionScopeOption你可以为工作单元设置作用域选项。 5、自动保存 当我们为一个方法使用了工作单元时ABP会在该方法结束时自动保存所有的更改。假设我们有一个更新person的name的方法 [UnitOfWork]
public void UpdateName(UpdateNameInput input)
{var person _personRepository.Get(input.PersonId);person.Name input.NewName;
} 你要做的就这么多person的name就改变了。我们甚至不用调用_personRepository.Update方法。ORM框架会跟踪工作单元中实体的所有改变并将改变反应给数据库。 注意没有必要为应用服务方法声明UnitOfWork特性因为它们默认已经是工作单元了。 6、IRepository.GetAll()方法 当在一个仓储方法之外调用GetAll()时必须存在一个打开的数据库连接因为GetAll返回了IQueryable而且IQueryable会延迟执行。直到调用ToList()方法或者在foreach循环中使用IQueryable,才会真正执行数据库查询。因此调用ToList()方法时数据库连接必须是活着的alive。 思考下面的例子 [UnitOfWork]
public SearchPeopleOutput SearchPeople(SearchPeopleInput input)
{//返回IQueryablePersonvar query _personRepository.GetAll();//添加一些过滤if (!string.IsNullOrEmpty(input.SearchedName)){query query.Where(person person.Name.StartsWith(input.SearchedName));}if (input.IsActive.HasValue){query query.Where(person person.IsActive input.IsActive.Value);}//获得分页结果列表var people query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();return new SearchPeopleOutput { People Mapper.MapListPersonDto(people) };
} 这里SearchPeople方法必须是工作单元因为IQueryable的ToList()在方法体内调用了当执行IQueryable.ToList()执行时数据库连接必须是打开的状态。 就像GetAll()方法一样如果在仓储之外需要数据库连接那么必须使用工作单元。应用服务方法默认是工作单元。 7、UnitOfWork特性的限制 UnitOfWork可以用于以下几个条件 所有用于接口的类的public或public virtual方法如用于用于服务接口的应用服务类的方法。自注入类的所有public virtual如MVC 控制器和Web Api控制器。所有的protected virtual方法。建议总是将方法声明为virtual但是不能用于private方法。因为ABP为virtual方法私有了动态代理private方法不能被派生的类访问到。如果你没有使用依赖注入且实例化类那么UnitOfWork特性和任何代理就不能工作。 四、选项 有很多可以用于改变工作单元行为的选项。 首先我们可以在启动配置中更改所有工作单元的默认值。这通常是在模块的PreInitialize方法中处理的。 public class SimpleTaskSystemCoreModule : AbpModule
{public override void PreInitialize(){Configuration.UnitOfWork.IsolationLevel IsolationLevel.ReadCommitted;Configuration.UnitOfWork.Timeout TimeSpan.FromMinutes(30);}//...其他模块方法
} 其次我们可以为一个特定的工作单元重写默认值。比如UnitOfWork特性的构造函数和IUnitOfWorkManager的Begin方法都有获得选项的重载。 五、方法 UnitOfWork系统无缝而不可见地工作。但是在某些场合你需要调用它的方法。 SaveChanges: ABP会在工作单元结束时保存所有更改我们根本不用做任何事情。但是有时候你可能想在工作单元操作的中间将更改保存到数据库中。在这种情况下你可以注入IUnitOfWorkManager然后调用IUnitOfWorkManager.Current.SaveChanges()方法。注意如果当前的工作单元是事务的那么如果有异常发生了事务中的所有改变都会回滚即使是已保存的改变。 六、事件 工作单元有Completed,Failed和Disposed事件。你可以注册这些事件然后执行需要的操作。通过注入IUnitOfWorkManager然后使用IUnitOfWorkManager.Current属性来获得激活的工作单元然后注册到它的事件。 在当前的工作单元成功完成时你可能想运行一些代码下面是一个例子 public void CreateTask(CreateTaskInput input)
{var task new Task { Description input.Description };if (input.AssignedPersonId.HasValue){task.AssignedPersonId input.AssignedPersonId.Value;_unitOfWorkManager.Current.Completed (sender, args) { /* TODO: 给派发的人发送邮件*/ };}_taskRepository.Insert(task);
} 转载于:https://www.cnblogs.com/yinrq/p/5543046.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/89371.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!