مفهوم READ_COMMITTED_SNAPSHOT در EF 6
CREATE TABLE [BlogComments]( [Id] [int] IDENTITY(1,1) NOT NULL, [Body] [nvarchar](max) NULL, [Date1] [datetime] NOT NULL, CONSTRAINT [PK_BlogComments] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
-- در پنجره اول BEGIN TRAN UPDATE [BlogComments] SET Body='Test' WHERE id=1
-- در پنجره دوم SELECT TOP 1000 [Id] ,[Body] ,[Date1] FROM [BlogComments]
- الان پنجره دوم را اجرا کنید.
مشاهده خواهید کرد که ... به جواب نمیرسید. کوئری اجرا نمیشود و سیستم قفل شده چون تراکنش اول commit نشده (مثلا یک تراکنش طولانی را اینجا شبیه سازی کردیم؛ یا حتی یک اشتباه در تعاریف T-SQL انجام شده).
در ادامه، عملیات این پنجرهها را دستی متوقف کنید. بعد مطابق دستوراتی که پیشتر ذکر شد، READ_COMMITTED_SNAPSHOT را روی دیتابیس فعال کنید.
مجددا دو مرحله قبل را اجرا کنید. در این حالت کوئری دوم اجرا خواهد شد، چون اطلاعات را از کپی فقط خواندنی بانک اطلاعاتی شما دریافت میکند؛ بر اساس آخرین اطلاعات commit شده در سیستم.
آماده سازی مقدمات پروژهی آزمون واحد
در ادامهی مثال این سری، پروژهی جدید NotifyPropertyChangedGenerator.Tests را از نوع class library با تنظیمات فایل csproj. زیر ایجاد میکنیم:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.2.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> <PackageReference Include="MSTest.TestFramework" Version="2.2.10" /> <PackageReference Include="MSTest.TestAdapter" Version="2.2.10" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NotifyPropertyChangedGenerator\NotifyPropertyChangedGenerator.csproj" /> </ItemGroup> </Project>
ایجاد یک کلاس کمکی برای اجرای Source Generators در پروژههای آزمون واحد
در اینجا میخواهیم همان کاری را که کامپایلر سیشارپ در پشت صحنه انجام میدهد، شبیه سازی کنیم تا بتوانیم یک تولید کنندهی کد را به مراحل کامپایل کد، معرفی و سپس آنرا اجرا کنیم:
internal static class SourceGeneratorTestsExtensions { public static (GeneratorDriver Driver, Compilation OutputCompilation, ImmutableArray<Diagnostic> Diagnostics) RunGenerators(this string source, params ISourceGenerator[] generators) { var references = AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => !assembly.IsDynamic) .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) .Cast<MetadataReference>(); var inputCompilation = CSharpCompilation.Create("compilation", new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest)) }, references, new CSharpCompilationOptions(OutputKind.ConsoleApplication)); GeneratorDriver driver = CSharpGeneratorDriver.Create(generators); driver = driver.RunGeneratorsAndUpdateCompilation( inputCompilation, out var outputCompilation, out var diagnostics); return (driver, outputCompilation, diagnostics); } }
نوشتن اولین آزمون واحد مخصوص یک تولید کنندهی کد
پس از تهیهی متدی که میتواند یک قطعه کد و تعدادی Source Generator را به کامپایلر سیشارپ، جهت پردازش معرفی کند، یک نمونه نحوهی استفادهی از آن جهت نوشتن آزمونهای واحد کاملا مستقل و متکی به خود، به صورت زیر است:
using Microsoft.VisualStudio.TestTools.UnitTesting; using PropertyChangedGenerator = NotifyPropertyChangedGenerator.NotifyPropertyChangedGenerator; namespace NotifyPropertyChangedGenerator.Tests; [TestClass] public class GeneratorTest { [TestMethod] public void SimpleGeneratorTest() { var userSource = @" using System; using System.ComponentModel; namespace NotifyPropertyChangedDemo { public class Test : INotifyPropertyChanged { private int regularField; private int IndexBackingField; } } "; var (driver, outputCompilation, diagnostics) = userSource.RunGenerators(new PropertyChangedGenerator()); var newFile = outputCompilation.SyntaxTrees .Single(x => Path.GetFileName(x.FilePath).EndsWith(".Test.cs")); Assert.IsNotNull(newFile); Assert.IsTrue(newFile.FilePath.EndsWith("Test.Notify.Test.cs")); var generatedSource = newFile.GetText().ToString(); Assert.IsTrue(generatedSource.Contains("namespace NotifyPropertyChangedDemo")); // We can now assert things about the resulting compilation: Assert.IsTrue(diagnostics.IsEmpty); // there were no diagnostics created by the generators // we have two syntax trees, the original 'user' provided one, and the one added by the generator Assert.IsTrue(outputCompilation.SyntaxTrees.Count() == 2); // verify the compilation with the added source has no diagnostics Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); } }
- سپس این قطعه کد و نمونهای از تولید کنندهی کد را به کامپایلر ارسال و اجرا کردهایم.
- اکنون بر اساس خروجی کامپایلر برای مثال میتوان به فایل تولید شده و SyntaxTrees آن دسترسی پیدا کرد و یا با کمک متد GetText، به کل محتوای این فایل تولید شده دسترسی یافت و برای مثال آنرا با مقداری که انتظار داریم مقایسه کرد تا به این ترتیب بتوان از صحت عملکرد تولید کنندهی کد، اطمینان حاصل نمود.
- همانطور که عنوان شد، اکنون قرار دادن break-point در قسمتهای مختلف آزمون واحد تهیه شده بسیار سادهاست و به این ترتیب میتوان یک چنین پروژههایی را در تمام IDEها دیباگ کرد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: SourceGeneratorTests-part5.zip
غروب log4net
As of April 1, 2020 Log4Net is a dormant project of Apache Logging Services. The dormant status means the project has been classified as inactive since it has had no recent development activity and there are no active volunteers to perform code reviews, commit code, or perform releases. Although it is possible volunteers might choose to participate in the future, it is best to assume there will be not future development or releases.
5.Visual Studio 2017 15.7 منتشر شد
These are the customer-reported issues addressed in 15.7.5:
- VS2017 15.7.0 Community debugger not showing variable values on hover.
- Exception block is optmized away causing a crash.
- cannot push to remote repository since update from 15.7.2 to 15.7.3.
- Sync commit: Git failed with a fatal error.
- Compiler bug related to math operations on NaN not conforming to standards, when optimization is enabled.
- Optimization error in x86 build reorders lines incorrectly.
حجم تقریبی بروزرسانی از نسخه 15.7.4 به 15.7.5 برابر با 1.7GB میباشد
On 28 of May, 2014, the first commit of Immutable.js was pushed in the facebook’s organization on GitHub. Immutable.js is a set of immutable data structures (List, Set, Map, etc.) implemented in JavaScript.
Plain JavaScript array
20 | 10 | 5 | 1 | تعداد watch - تعداد آرایه |
2.58 | 2.573 | 2.56 | 2.517 | 100 |
2.853 | 2.747 | 2.675 | 2.555 | 1000 |
15.68 | 7.736 | 4.025 | 2.861 | 10000 |
Immutable JavaScript list
20 | 10 | 5 | 1 | تعداد watch - تعداد آرایه |
2.569 | 2.562 | 2.507 | 2.696 | 100 |
2.49 | 2.569 | 2.54 | 2.715 | 1000 |
2.708 | 2.599 | 2.538 | 2.832 | 10000 |
انتقال SVN به یک سیستم جدید
1 - اساس کار متداول SVN بر اساس فولدر سازی به ازای هر تغییر نیست. به ازای هر تغییر شما میتونید موارد اصلاحی را commit کنید. بعد میشود بر اساس comment نوشته شده برای این commit گزارش گرفت و نگارش جاری را مثلا با 5 نگارش قبل مقایسه کرد. با همین ابزار diff ایی که معرفی کردم. ضمنا امکان export کامل پروژه به ازای هر نگارش commit شده وجود دارد.
البته مباحث انعشابات و غیره هم وجود دارد که در فصلی جداگانه به آن پرداخته شده.
میشود برچسب یا tag ایجاد کرد و کل پروژه را تا یک نگارش خاص در آن قرار داد. عموما برای ارائه نگارشهای عمومی این روش توصیه میشود.
یا میشود یک انعشاب درست کرد و جدا از خط اصلی کاری یا همان trunk کار کرد (مثلا آزمایش یک قابلیت جدید) و سپس این انعشاب تکمیل شده را با trunk و خط اصلی کاری یکی کرد.
هر کدام از این موارد (برچسب یا انشعاب) هم بر اساس پوشهها هستند البته در مخزن کد.
2 - افزونه Visual SVN این مورد را سادهتر کرده. خودش گزینهی ایجاد خودکار مخزن و افزودن به آنرا دارد و از این لحاظ در وقت صرفه جویی میشود.
آشنایی با Automapping در فریم ورک Fluent NHibernate
اگر قسمتهای قبل را دنبال کرده باشید، احتمالا به پروسه طولانی ساخت نگاشتها توجه کردهاید. با کمک فریم ورک Fluent NHibernate میتوان پروسه نگاشت domain model خود را به data model متناظر آن به صورت خودکار نیز انجام داد و قسمت عمدهای از کار به این صورت حذف خواهد شد. (این مورد یکی از تفاوتهای مهم NHibernate با نمونههای مشابهی است که مایکروسافت تا تاریخ نگارش این مقاله ارائه داده است. برای مثال در نگارشهای فعلی LINQ to SQL یا Entity framework ، اول دیتابیس مطرح است و بعد ساخت کد از روی آن، در حالیکه در اینجا ابتدا کد و طراحی سیستم مطرح است و بعد نگاشت آن به سیستم دادهای و دیتابیس)
امروز قصد داریم یک سیستم ساده ثبت خبر را از صفر با NHibernate پیاده سازی کنیم و همچنین مروری داشته باشیم بر قسمتهای قبلی.
مطابق کلاس دیاگرام فوق، این سیستم از سه کلاس خبر، کاربر ثبت کنندهی خبر و گروه خبری مربوطه تشکیل شده است.
ابتدا یک پروژه کنسول جدید را به نام NHSample2 آغاز کنید. سپس ارجاعاتی را به اسمبلیهای زیر به آن اضافه نمائید:
FluentNHibernate.dll
NHibernate.dll
NHibernate.ByteCode.Castle.dll
NHibernate.Linq.dll
و ارجاعی به اسمبلی استاندارد System.Data.Services.dll دات نت فریم ورک سه و نیم
سپس پوشهای را به نام Domain به این پروژه اضافه نمائید (کلیک راست روی نام پروژه در VS.Net و سپس مراجعه به منوی Add->New folder). در این پوشه تعاریف موجودیتهای برنامه را قرار خواهیم داد. سه کلاس جدید Category ، User و News را در این پوشه ایجاد نمائید. محتویات این سه کلاس به شرح زیر هستند:
namespace NHSample2.Domain
{
public class User
{
public virtual int Id { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
}
}
namespace NHSample2.Domain
{
public class Category
{
public virtual int Id { get; set; }
public virtual string CategoryName { get; set; }
}
}
using System;
namespace NHSample2.Domain
{
public class News
{
public virtual Guid Id { get; set; }
public virtual string Subject { get; set; }
public virtual string NewsText { get; set; }
public virtual DateTime DateEntered { get; set; }
public virtual Category Category { get; set; }
public virtual User User { get; set; }
}
}
اکنون کلاس جدید Config را به برنامه اضافه نمائید:
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
namespace NHSample2
{
class Config
{
public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
{
var cfg = dbType.ConfigureProperties(new Configuration());
new AutoPersistenceModel()
.Where(x => x.Namespace.EndsWith("Domain"))
.AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly).Configure(cfg);
return cfg;
}
public static void GenerateDbScript(Configuration config, string filePath)
{
bool script = true;//فقط اسکریپت دیتابیس تولید گردد
bool export = false;//نیازی نیست بر روی دیتابیس هم اجرا شود
new SchemaExport(config).SetOutputFile(filePath).Create(script, export);
}
public static void BuildDbSchema(Configuration config)
{
bool script = false;//آیا خروجی در کنسول هم نمایش داده شود
bool export = true;//آیا بر روی دیتابیس هم اجرا شود
bool drop = false;//آیا اطلاعات موجود دراپ شوند
new SchemaExport(config).Execute(script, export, drop);
}
public static void CreateSQL2008DbPlusScript(string connectionString, string filePath)
{
Configuration cfg =
GenerateMapping(
MsSqlConfiguration
.MsSql2008
.ConnectionString(connectionString)
.ShowSql()
);
GenerateDbScript(cfg, filePath);
BuildDbSchema(cfg);
}
public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer dbType)
{
return
Fluently.Configure().Database(dbType)
.Mappings(m => m.AutoMappings
.Add(
new AutoPersistenceModel()
.Where(x => x.Namespace.EndsWith("Domain"))
.AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly))
)
.BuildSessionFactory();
}
}
}
در متد GenerateMapping از قابلیت Automapping موجود در فریم ورک Fluent Nhibernate استفاده شده است (بدون نوشتن حتی یک سطر جهت تعریف این نگاشتها). این متد نوع دیتابیس مورد نظر را جهت ساخت تنظیمات خود دریافت میکند. سپس با کمک کلاس AutoPersistenceModel این فریم ورک، به صورت خودکار از اسمبلی برنامه نگاشتهای لازم را به کلاسهای موجود در پوشه Domain ما اضافه میکند (مرسوم است که این پوشه در یک پروژه Class library مجزا تعریف شود که در این برنامه جهت سهولت کار در خود برنامه قرار گرفته است). قسمت Where ذکر شده به این جهت معرفی گردیده است تا Fluent Nhibernate برای تمامی کلاسهای موجود در اسمبلی جاری، سعی در تعریف نگاشتهای لازم نکند. این نگاشتها تنها به کلاسهای موجود در پوشه دومین ما محدود شدهاند.
سه متد بعدی آن، جهت ایجاد اسکریپت دیتابیس از روی این نگاشتهای تعریف شده و سپس اجرای این اسکریپت بر روی دیتابیس جاری معرفی شده، تهیه شدهاند. برای مثال CreateSQL2008DbPlusScript یک مثال ساده از استفاده دو متد قبلی جهت ایجاد اسکریپت و دیتابیس متناظر اس کیوال سرور 2008 بر اساس نگاشتهای برنامه است.
با متد CreateSessionFactory در قسمتهای قبل آشنا شدهاید. تنها تفاوت آن در این قسمت، استفاده از کلاس AutoPersistenceModel جهت تولید خودکار نگاشتها است.
در ادامه دیتابیس متناظر با موجودیتهای برنامه را ایجاد خواهیم کرد:
using System;
namespace NHSample2
{
class Program
{
static void Main(string[] args)
{
Config.CreateSQL2008DbPlusScript(
"Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true",
"db.sql");
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
پس از اجرای برنامه، ابتدا فایل اسکریپت دیتابیس به نام db.sql در پوشه اجرایی برنامه تشکیل خواهد شد و سپس این اسکریپت به صورت خودکار بر روی دیتابیس معرفی شده اجرا میگردد. دیتابیس دیاگرام حاصل را در شکل زیر میتوانید ملاحظه نمائید:
همچنین اسکریپت تولید شده آن، صرفنظر از عبارات drop اولیه، به صورت زیر است:
create table [Category] (
Id INT IDENTITY NOT NULL,
CategoryName NVARCHAR(255) null,
primary key (Id)
)
create table [User] (
Id INT IDENTITY NOT NULL,
UserName NVARCHAR(255) null,
Password NVARCHAR(255) null,
primary key (Id)
)
create table [News] (
Id UNIQUEIDENTIFIER not null,
Subject NVARCHAR(255) null,
NewsText NVARCHAR(255) null,
DateEntered DATETIME null,
Category_id INT null,
User_id INT null,
primary key (Id)
)
alter table [News]
add constraint FKE660F9E1C9CF79
foreign key (Category_id)
references [Category]
alter table [News]
add constraint FKE660F95C1A3C92
foreign key (User_id)
references [User]
اکنون یک سری گروه خبری، کاربر و خبر را به دیتابیس خواهیم افزود:
using System;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHSample2.Domain;
namespace NHSample2
{
class Program
{
static void Main(string[] args)
{
using (ISessionFactory sessionFactory = Config.CreateSessionFactory(
MsSqlConfiguration
.MsSql2008
.ConnectionString("Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true")
.ShowSql()
))
{
using (ISession session = sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
//با توجه به کلیدهای خارجی تعریف شده ابتدا باید گروهها را اضافه کرد
Category ca = new Category() { CategoryName = "Sport" };
session.Save(ca);
Category ca2 = new Category() { CategoryName = "IT" };
session.Save(ca2);
Category ca3 = new Category() { CategoryName = "Business" };
session.Save(ca3);
//سپس یک کاربر را به دیتابیس اضافه میکنیم
User u = new User() { Password = "123$5@1", UserName = "VahidNasiri" };
session.Save(u);
//اکنون میتوان یک خبر جدید را ثبت کرد
News news = new News()
{
Category = ca,
User = u,
DateEntered = DateTime.Now,
Id = Guid.NewGuid(),
NewsText = "متن خبر جدید",
Subject = "عنوانی دلخواه"
};
session.Save(news);
transaction.Commit(); //پایان تراکنش
}
}
}
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
و یا میتوان از LINQ استفاده کرد:
برای مثال کاربر VahidNasiri تعریف شده را یافته، اطلاعات آنرا نمایش دهید؛ سپس نام او را به Vahid ویرایش کرده و دیتابیس را به روز کنید.
برای اینکه کوئریهای LINQ ما شبیه به LINQ to SQL شوند، کلاس NewsContext را به صورت ذیل تشکیل میدهیم. این کلاس از کلاس پایه NHibernateContext مشتق شده و سپس به ازای تمام موجودیتهای برنامه، یک متد از نوع IOrderedQueryable را تشکیل خواهیم داد.
using System.Linq;
using NHibernate;
using NHibernate.Linq;
using NHSample2.Domain;
namespace NHSample2
{
class NewsContext : NHibernateContext
{
public NewsContext(ISession session)
: base(session)
{ }
public IOrderedQueryable<News> News
{
get { return Session.Linq<News>(); }
}
public IOrderedQueryable<Category> Categories
{
get { return Session.Linq<Category>(); }
}
public IOrderedQueryable<User> Users
{
get { return Session.Linq<User>(); }
}
}
}
using System;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using System.Linq;
using NHSample2.Domain;
namespace NHSample2
{
class Program
{
static void Main(string[] args)
{
using (ISessionFactory sessionFactory = Config.CreateSessionFactory(
MsSqlConfiguration
.MsSql2008
.ConnectionString("Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true")
.ShowSql()
))
{
using (ISession session = sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
using (NewsContext db = new NewsContext(session))
{
var query = from x in db.Users
where x.UserName == "VahidNasiri"
select x;
//اگر چیزی یافت شد
if (query.Any())
{
User vahid = query.First();
//نمایش اطلاعات کاربر
Console.WriteLine("Id: {0}, UserName: {0}", vahid.Id, vahid.UserName);
//به روز رسانی نام کاربر
vahid.UserName = "Vahid";
session.Update(vahid);
transaction.Commit(); //پایان تراکنش
}
}
}
}
}
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
اگر به اسکریپت دیتابیس تولید شده دقت کرده باشید، عملیات AutoMapping یک سری پیش فرضهایی را اعمال کرده است. برای مثال فیلد Id را از نوع identity و به صورت کلید تعریف کرده، یا رشتهها را به صورت nvarchar با طول 255 ایجاد نموده است. امکان سفارشی سازی این موارد نیز وجود دارد.
مثال:
using FluentNHibernate.Conventions.Helpers;
public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
{
var cfg = dbType.ConfigureProperties(new Configuration());
new AutoPersistenceModel()
.Conventions.Add()
.Where(x => x.Namespace.EndsWith("Domain"))
.Conventions.Add(
PrimaryKey.Name.Is(x => "ID"),
DefaultLazy.Always(),
ForeignKey.EndsWith("ID"),
Table.Is(t => "tbl" + t.EntityType.Name)
)
.AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly)
.Configure(cfg);
return cfg;
}
تابع GenerateMapping معرفی شده را اینجا با قسمت Conventions.Add تکمیل کردهایم. به این صورت دقیقا مشخص شده است که فیلدهایی با نام ID باید primary key در نظر گرفته شوند، همواره lazy loading صورت گیرد و نام کلید خارجی به ID ختم شود. همچنین نام جداول با tbl شروع گردد.
روش دیگری نیز برای معرفی این قرار دادها و پیش فرضها وجود دارد. فرض کنید میخواهیم طول رشته پیش فرض را از 255 به 500 تغییر دهیم. برای اینکار باید اینترفیس IPropertyConvention را پیاده سازی کرد:
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
namespace NHSample2.Conventions
{
class MyStringLengthConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
instance.Length(500);
}
}
}
public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
{
var cfg = dbType.ConfigureProperties(new Configuration());
new AutoPersistenceModel()
.Conventions.Add()
.Where(x => x.Namespace.EndsWith("Domain"))
.Conventions.Add<MyStringLengthConvention>()
.AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly)
.Configure(cfg);
return cfg;
}
نکته:
اگر برای یافتن اطلاعات بیشتر در این مورد در وب جستجو کنید، اکثر مثالهایی را که مشاهده خواهید کرد بر اساس نگارش بتای fluent NHibernate هستند و هیچکدام با نگارش نهایی این فریم ورک کار نمیکنند. در نگارش رسمی نهایی ارائه شده، تغییرات بسیاری صورت گرفته که آنها را در این آدرس میتوان مشاهده کرد.
دریافت سورس برنامه قسمت ششم
ادامه دارد ...
سری آموزش 25 قسمتی Git و GitHub
Git Tutorial - 1 - How to Download and Install Git
Git Tutorial - 2 - Config Our Username and Email
Git Tutorial - 3 - Creating Our First Repository
Git Tutorial - 4 - Commit
Git Tutorial - 5 - Adding Files and the Commit Log
Git Tutorial - 6 - Git Workflow
Git Tutorial - 7 - How to Edit Files
Git Tutorial - 8 - Viewing the Changes That You Made
Git Tutorial - 9 - Comparing the Staging Area with the Repository
Git Tutorial - 10 - How to Delete Files
Git Tutorial - 11 - How to Move and Rename Files
Git Tutorial - 12 - Working with an Actual Website
Git Tutorial - 13 - How to Commit Directly to the Repository
Git Tutorial - 14 - Checkout this video (Git it?)
Git Tutorial - 15 - Unstage Files
Git Tutorial - 16 - Getting Old Versions from the Repository
Git Tutorial - 17 - GitHub
Git Tutorial - 18 - Pushing to a GitHub Repository
Git Tutorial - 19 - gitignore and GitHub Desktop
Git Tutorial - 20 - Committing Changes to GitHub
Git Tutorial - 21 - Branches
Git Tutorial - 22 - GitHub Watch Star and Fork
Git Tutorial - 23 - GitHub Issues and Labels
Git Tutorial - 24 - GitHub Wiki
Git Tutorial - 25 - GitHub Organizations and Teams
_categoryService.AddNewCategory(category); _uow.SaveAllChanges(); throw new InvalidOperationException(); return RedirectToAction("Index");
public interface IRunAtInit { void Execute(); } public interface IRunAfterEachRequest { void Execute(); } public interface IRunAtStartUp { void Execute(); } public interface IRunOnEachRequest { void Execute(); } public interface IRunOnError { void Execute(); }
public class TaskRegistry : StructureMap.Configuration.DSL.Registry { public TaskRegistry() { Scan(scan => { scan.Assembliy("yourAssemblyName"); scan.AddAllTypesOf<IRunAtInit>(); scan.AddAllTypesOf<IRunAtStartUp>(); scan.AddAllTypesOf<IRunOnEachRequest>(); scan.AddAllTypesOf<IRunOnError>(); scan.AddAllTypesOf<IRunAfterEachRequest>(); }); } }
ioc.AddRegistry(new TaskRegistry());
protected void Application_Start() { // other code foreach (var task in SmObjectFactory.Container.GetAllInstances<IRunAtInit>()) { task.Execute(); } } protected void Application_BeginRequest() { foreach (var task in SmObjectFactory.Container.GetAllInstances<IRunOnEachRequest>()) { task.Execute(); } } protected void Application_EndRequest(object sender, EventArgs e) { try { foreach (var task in SmObjectFactory.Container.GetAllInstances<IRunAfterEachRequest>()) { task.Execute(); } } finally { HttpContextLifecycle.DisposeAndClearAll(); MiniProfiler.Stop(); } } protected void Application_Error() { foreach (var task in SmObjectFactory.Container.GetAllInstances<IRunOnError>()) { task.Execute(); } }
public class TransactionPerRequest : IRunOnEachRequest, IRunOnError, IRunAfterEachRequest { private readonly IUnitOfWork _uow; private readonly HttpContextBase _httpContext; public TransactionPerRequest(IUnitOfWork uow, HttpContextBase httpContext) { _uow = uow; _httpContext = httpContext; } void IRunOnEachRequest.Execute() { _httpContext.Items["_Transaction"] = _uow.Database.BeginTransaction(System.Data.IsolationLevel.ReadCommitted); } void IRunOnError.Execute() { _httpContext.Items["_Error"] = true; } void IRunAfterEachRequest.Execute() { var transaction = (DbContextTransaction) _httpContext.Items["_Transaction"]; if (_httpContext.Items["_Error"] != null) { transaction.Rollback(); } else { transaction.Commit(); } } }
_categoryService.AddNewCategory(category); _uow.SaveAllChanges(); throw new InvalidOperationException(); return RedirectToAction("Index");