Added ContentType metadata feature to allow dynamic mapping.

--HG--
branch : dev
This commit is contained in:
khavas
2010-05-18 13:08:47 -07:00
parent 6fb9d48666
commit 5667e6a999
20 changed files with 425 additions and 12 deletions

103
src/Orchard.5.0.ReSharper Normal file
View File

@@ -0,0 +1,103 @@
<Configuration>
<CodeStyleSettings>
<ExternalPath IsNull="False">
</ExternalPath>
<Sharing>SOLUTION</Sharing>
<CSharp>
<FormatSettings>
<ANONYMOUS_METHOD_DECLARATION_BRACES>END_OF_LINE</ANONYMOUS_METHOD_DECLARATION_BRACES>
<CASE_BLOCK_BRACES>END_OF_LINE</CASE_BLOCK_BRACES>
<FORCE_FIXED_BRACES_STYLE>ALWAYS_ADD</FORCE_FIXED_BRACES_STYLE>
<FORCE_FOR_BRACES_STYLE>ALWAYS_ADD</FORCE_FOR_BRACES_STYLE>
<FORCE_FOREACH_BRACES_STYLE>ALWAYS_ADD</FORCE_FOREACH_BRACES_STYLE>
<FORCE_IFELSE_BRACES_STYLE>ALWAYS_ADD</FORCE_IFELSE_BRACES_STYLE>
<FORCE_USING_BRACES_STYLE>ALWAYS_ADD</FORCE_USING_BRACES_STYLE>
<FORCE_WHILE_BRACES_STYLE>ALWAYS_ADD</FORCE_WHILE_BRACES_STYLE>
<INITIALIZER_BRACES>END_OF_LINE</INITIALIZER_BRACES>
<INVOCABLE_DECLARATION_BRACES>END_OF_LINE</INVOCABLE_DECLARATION_BRACES>
<MODIFIERS_ORDER IsNull="False">
<Item>public</Item>
<Item>protected</Item>
<Item>internal</Item>
<Item>private</Item>
<Item>new</Item>
<Item>abstract</Item>
<Item>virtual</Item>
<Item>override</Item>
<Item>sealed</Item>
<Item>static</Item>
<Item>readonly</Item>
<Item>extern</Item>
<Item>unsafe</Item>
<Item>volatile</Item>
</MODIFIERS_ORDER>
<OTHER_BRACES>END_OF_LINE</OTHER_BRACES>
<TYPE_DECLARATION_BRACES>END_OF_LINE</TYPE_DECLARATION_BRACES>
</FormatSettings>
<UsingsSettings />
<Naming2>
<EventHandlerPatternLong>$object$_On$event$</EventHandlerPatternLong>
<EventHandlerPatternShort>$event$Handler</EventHandlerPatternShort>
<ExceptionName IsNull="False">
</ExceptionName>
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="TypesAndNamespaces" />
<PredefinedRule Inspect="True" Prefix="I" Suffix="" Style="AaBb" ElementKind="Interfaces" />
<PredefinedRule Inspect="True" Prefix="T" Suffix="" Style="AaBb" ElementKind="TypeParameters" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="MethodPropertyEvent" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="Locals" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="LocalConstants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="Parameters" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="PublicFields" />
<PredefinedRule Inspect="True" Prefix="_" Suffix="" Style="aaBb" ElementKind="PrivateInstanceFields" />
<PredefinedRule Inspect="True" Prefix="_" Suffix="" Style="aaBb" ElementKind="PrivateStaticFields" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="Constants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="PrivateConstants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="StaticReadonly" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="PrivateStaticReadonly" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="EnumMember" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="Other" />
</Naming2>
</CSharp>
<VB>
<FormatSettings />
<ImportsSettings />
<Naming2>
<EventHandlerPatternLong>$object$_On$event$</EventHandlerPatternLong>
<EventHandlerPatternShort>$event$Handler</EventHandlerPatternShort>
</Naming2>
</VB>
<Web>
<Naming2 />
</Web>
<Xaml>
<Naming2 />
</Xaml>
<XML>
<FormatSettings />
</XML>
<GenerateMemberBody />
<Naming2>
<EventHandlerPatternLong>$object$_On$event$</EventHandlerPatternLong>
<EventHandlerPatternShort>$event$Handler</EventHandlerPatternShort>
<ExceptionName IsNull="False">
</ExceptionName>
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="TypesAndNamespaces" />
<PredefinedRule Inspect="True" Prefix="I" Suffix="" Style="AaBb" ElementKind="Interfaces" />
<PredefinedRule Inspect="True" Prefix="T" Suffix="" Style="AaBb" ElementKind="TypeParameters" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="MethodPropertyEvent" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="Locals" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="LocalConstants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="aaBb" ElementKind="Parameters" />
<PredefinedRule Inspect="True" Prefix="_" Suffix="" Style="aaBb" ElementKind="PublicFields" />
<PredefinedRule Inspect="True" Prefix="_" Suffix="" Style="aaBb" ElementKind="PrivateInstanceFields" />
<PredefinedRule Inspect="True" Prefix="_" Suffix="" Style="aaBb" ElementKind="PrivateStaticFields" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="Constants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="PrivateConstants" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="StaticReadonly" />
<PredefinedRule Inspect="False" Prefix="" Suffix="" Style="AaBb" ElementKind="PrivateStaticReadonly" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="EnumMember" />
<PredefinedRule Inspect="True" Prefix="" Suffix="" Style="AaBb" ElementKind="Other" />
<Abbreviation Text="SQ" />
</Naming2>
</CodeStyleSettings>
</Configuration>

View File

@@ -0,0 +1,63 @@
using Autofac;
using NHibernate;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData.Records;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace Orchard.Tests.ContentManagement{
[TestFixture]
class ContentTypeMetaDataTests
{
private IContainer _container;
private ISessionFactory _sessionFactory;
private ISession _session;
[TestFixtureSetUp]
public void InitFixture()
{
var databaseFileName = System.IO.Path.GetTempFileName();
_sessionFactory = DataUtility.CreateSessionFactory(
databaseFileName,
typeof(ContentTypeRecord),
typeof(ContentItemRecord),
typeof(ContentTypePartRecord),
typeof(ContentItemVersionRecord));
}
[TestFixtureTearDown]
public void TermFixture()
{
}
[SetUp]
public void Init()
{
var builder = new ContainerBuilder();
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterType<ContentTypeService>().As<IContentTypeService>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
_container = builder.Build();
}
[Test]
public void MapandUnMapContentTypeToContentPart()
{
var contentTypeService = _container.Resolve<IContentTypeService>();
contentTypeService.MapContentTypeToContentPart("foo", "bar");
Assert.IsTrue(contentTypeService.ValidateContentTypeToContentPartMapping("foo","bar"),"Content Type not successfully mapped");
contentTypeService.UnMapContentTypeToContentPart("foo", "bar");
Assert.IsFalse(contentTypeService.ValidateContentTypeToContentPartMapping("foo", "bar"), "Content Type mapping not successfully deleted");
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TeamSystem.Data.UnitTesting;
namespace Orchard.Tests.ContentManagement
{
[TestClass()]
public class DatabaseSetup
{
[AssemblyInitialize()]
public static void IntializeAssembly(TestContext ctx)
{
// Setup the test database based on setting in the
// configuration file
DatabaseTestClass.TestService.DeployDatabaseProject();
DatabaseTestClass.TestService.GenerateData();
}
}
}

View File

@@ -64,6 +64,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.NHibernate.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<Reference Include="Microsoft.VisualStudio.TeamSystem.Data.UnitTesting, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\moq\Moq.dll</HintPath>
@@ -133,6 +135,8 @@
<Compile Include="ContentManagement\ContentQueryTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\ContentTypeMetaDataTests.cs" />
<Compile Include="ContentManagement\DatabaseSetup.cs" />
<Compile Include="ContentManagement\DefaultContentManagerTests.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -14,9 +14,6 @@ namespace Orchard.Comments.Handlers {
IRepository<HasCommentsRecord> hasCommentsRepository,
ICommentService commentService) {
Filters.Add(new ActivatingFilter<HasComments>("sandboxpage"));
Filters.Add(new ActivatingFilter<HasComments>("blogpost"));
Filters.Add(new ActivatingFilter<HasComments>("page"));
Filters.Add(StorageFilter.For(hasCommentsRepository));
OnActivated<HasComments>((ctx, x) => {

View File

@@ -3,6 +3,9 @@ using System.Linq;
using System.Web;
using Orchard.Comments.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Records;
using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Models;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Settings.Models;
@@ -14,6 +17,7 @@ using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models;
using Orchard.Localization;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Security;
using Orchard.Settings;
using Orchard.Themes;
@@ -159,6 +163,24 @@ namespace Orchard.Setup.Services {
var authenticationService = environment.Resolve<IAuthenticationService>();
authenticationService.SignIn(user, true);
}
//Add ContentType mappings
var contentTypeService = environment.Resolve<IContentTypeService>();
//Add ContentTypePartNames to MetaData
contentTypeService.AddContentTypePartNameToMetaData("HasComments");
contentTypeService.AddContentTypePartNameToMetaData("HasTags");
//Add mappings from ContentTypes to ContentParts to MetaData
contentTypeService.MapContentTypeToContentPart("blogpost","HasComments");
contentTypeService.MapContentTypeToContentPart("page", "HasComments");
contentTypeService.MapContentTypeToContentPart("sandboxpage", "HasComments");
contentTypeService.MapContentTypeToContentPart("blogpost", "HasTags");
contentTypeService.MapContentTypeToContentPart("page", "HasTags");
contentTypeService.MapContentTypeToContentPart("sandboxpage", "HasTags");
}
catch {
environment.Resolve<ITransactionManager>().Cancel();

View File

@@ -10,10 +10,7 @@ namespace Orchard.Tags.Handlers {
[UsedImplicitly]
public class HasTagsHandler : ContentHandler {
public HasTagsHandler(IRepository<Tag> tagsRepository, IRepository<TagsContentItems> tagsContentItemsRepository) {
Filters.Add(new ActivatingFilter<HasTags>("sandboxpage"));
Filters.Add(new ActivatingFilter<HasTags>("blogpost"));
Filters.Add(new ActivatingFilter<HasTags>("page"));
OnLoading<HasTags>((context, tags) => {
// provide names of all tags on demand

View File

@@ -1,5 +1,5 @@
namespace Orchard.ContentManagement.Drivers {
public abstract class AutomaticContentPartDriver<TPart> : ContentPartDriver<TPart> where TPart : class, IContent {
public abstract class AutomaticContentPartDriver<TPart> : ContentPartDriver<TPart> where TPart : ContentPart, new() {
protected override string Prefix {
get {
return (typeof (TPart).Name);

View File

@@ -5,7 +5,7 @@ using Orchard.ContentManagement.Handlers;
using Orchard.Mvc.ViewModels;
namespace Orchard.ContentManagement.Drivers {
public abstract class ContentItemDriver<TContent> : ContentPartDriver<TContent>, IContentItemDriver where TContent : class, IContent {
public abstract class ContentItemDriver<TContent> : ContentPartDriver<TContent>, IContentItemDriver where TContent : ContentPart, new() {
private readonly ContentType _contentType;
protected virtual bool UseDefaultTemplate { get { return false; } }

View File

@@ -1,13 +1,18 @@
using Orchard.ContentManagement.Handlers;
using System.Collections.Generic;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
namespace Orchard.ContentManagement.Drivers {
public interface IContentPartDriver : IEvents {
DriverResult BuildDisplayModel(BuildDisplayModelContext context);
DriverResult BuildEditorModel(BuildEditorModelContext context);
DriverResult UpdateEditorModel(UpdateEditorModelContext context);
IEnumerable<ContentPartInfo> GetPartInfo();
}
public abstract class ContentPartDriver<TContent> : IContentPartDriver where TContent : class, IContent {
public abstract class ContentPartDriver<TContent> : IContentPartDriver where TContent : ContentPart, new() {
protected virtual string Prefix { get { return ""; } }
protected virtual string Zone { get { return "body"; } }
@@ -46,5 +51,16 @@ namespace Orchard.ContentManagement.Drivers {
public CombinedResult Combined(params DriverResult[] results) {
return new CombinedResult(results);
}
public IEnumerable<ContentPartInfo> GetPartInfo()
{
var contentPartInfo = new List<ContentPartInfo>() {
new ContentPartInfo()
{partName = typeof(TContent).Name,Factory = () => new TContent()}
};
return contentPartInfo;
}
}
}

View File

@@ -15,5 +15,11 @@
_item.Weld(part);
return this;
}
public ContentItemBuilder Weld(ContentPart contentPart) {
_item.Weld(contentPart);
return this;
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Records;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Data;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement.MetaData
{
[UsedImplicitly]
public class ContentPartHandler : ContentHandler
{
private readonly IEnumerable<ContentPartInfo> _contentPartInfos;
private readonly IContentTypeService _contentTypeService;
public ContentPartHandler(IEnumerable<IContentPartDriver> contentPartDrivers, IOrchardServices orchardServices, IContentTypeService contentTypeService) {
_contentTypeService = contentTypeService;
_contentPartInfos = contentPartDrivers.SelectMany<IContentPartDriver, ContentPartInfo>(cpp => cpp.GetPartInfo());
}
protected override void Activating(ActivatingContentContext context) {
var contentTypeRecord = _contentTypeService.GetContentTypeRecord(context.ContentType) ?? new ContentTypeRecord();
if (contentTypeRecord.ContentParts != null){
foreach (var contentTypePartRecord in contentTypeRecord.ContentParts){
var record = contentTypePartRecord;
var contentPart = _contentPartInfos.Single(x => x.partName == record.PartName).Factory();
context.Builder.Weld(contentPart);
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
namespace Orchard.ContentManagement.MetaData
{
public class ContentPartInfo
{
public string partName;
public Func<ContentPart> Factory;
}
}

View File

@@ -0,0 +1,11 @@
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData.Records;
namespace Orchard.ContentManagement.MetaData.Models
{
public class ContentTypePart : ContentPart<ContentTypePartRecord>
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.ContentManagement.MetaData.Records {
public class ContentTypePartNameRecord {
public virtual int Id { get; set; }
public virtual string PartName { get; set; }
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.ContentManagement.MetaData.Records {
public class ContentTypePartRecord {
public virtual int Id { get; set; }
public virtual string PartName { get; set; }
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Linq;
using Orchard.ContentManagement.MetaData.Records;
using Orchard.Data;
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement.MetaData.Services
{
[UsedImplicitly]
public class ContentTypeService : IContentTypeService
{
private readonly IRepository<ContentTypeRecord> _contentTypeRecord;
private readonly IRepository<ContentTypePartNameRecord> _contentTypePartNameRecord;
private readonly IRepository<ContentTypePartRecord> _contentTypePartRecord;
public ContentTypeService(IRepository<ContentTypePartRecord> contentTypePartRecord, IRepository<ContentTypeRecord> contentTypeRecord, IRepository<ContentTypePartNameRecord> contentTypePartNameRecord)
{
_contentTypeRecord = contentTypeRecord;
_contentTypePartNameRecord = contentTypePartNameRecord;
_contentTypePartRecord = contentTypePartRecord;
}
public void MapContentTypeToContentPart(string contentType, string contentPart) {
var contentTypeRecord = GetContentTypeRecord(contentType) ?? new ContentTypeRecord();
contentTypeRecord.Name = contentType;
var contentTypePartRecord = new ContentTypePartRecord() {
PartName = contentPart
};
if (contentTypeRecord.ContentParts==null) {
contentTypeRecord.ContentParts = new List<ContentTypePartRecord> { contentTypePartRecord };
}
else {
contentTypeRecord.ContentParts.Add(contentTypePartRecord);
}
_contentTypeRecord.Update(contentTypeRecord);
}
public void UnMapContentTypeToContentPart(string contentType, string contentPart) {
var contentTypeRecord = GetContentTypeRecord(contentType) ?? new ContentTypeRecord();
var contentTypePartRecord = contentTypeRecord.ContentParts.Single(x => x.PartName == contentPart);
if (contentTypePartRecord != null)
{
_contentTypePartRecord.Delete(contentTypePartRecord);
contentTypeRecord.ContentParts.Remove(contentTypePartRecord);
}
}
public bool ValidateContentTypeToContentPartMapping(string contentType, string contentPart) {
var contentTypeRecord = GetContentTypeRecord(contentType) ?? new ContentTypeRecord();
if (contentTypeRecord.ContentParts.Count==0)
return false;
var contentTypePart = contentTypeRecord.ContentParts.Single(x => x.PartName == contentPart);
return contentTypePart != null;
}
public void AddContentTypePartNameToMetaData(string contentTypePartName) {
var contentTypePartNameRecord = new ContentTypePartNameRecord() {
PartName = contentTypePartName
};
_contentTypePartNameRecord.Update(contentTypePartNameRecord);
}
public ContentTypeRecord GetContentTypeRecord(string contentTypeName) {
var contentTypeCount = _contentTypeRecord.Table.Count(x => x.Name == contentTypeName);
if (contentTypeCount > 0) {
var contentTypeRecord = _contentTypeRecord.Table.Single(x => x.Name == contentTypeName);
return contentTypeRecord;
}
else {
return null;
}
}
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement.MetaData.Services
{
public interface IContentTypeService : IDependency {
void MapContentTypeToContentPart(string contentType, string contentPart);
void UnMapContentTypeToContentPart(string contentType, string contentPart);
void AddContentTypePartNameToMetaData(string contentTypePartName);
ContentTypeRecord GetContentTypeRecord(string contentTypeName);
bool ValidateContentTypeToContentPartMapping(string contentType, string contentPart);
}
}

View File

@@ -1,6 +1,12 @@
namespace Orchard.ContentManagement.Records {
using System.Collections.Generic;
using Orchard.ContentManagement.MetaData.Records;
using Orchard.Data.Conventions;
namespace Orchard.ContentManagement.Records {
public class ContentTypeRecord {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
[CascadeAllDeleteOrphan]
public virtual IList<ContentTypePartRecord> ContentParts { get; set; }
}
}

View File

@@ -152,6 +152,7 @@
<Compile Include="Caching\Weak.cs" />
<Compile Include="ContentManagement\DefaultContentManagerSession.cs" />
<Compile Include="ContentManagement\IContentManagerSession.cs" />
<Compile Include="ContentManagement\MetaData\Records\ContentTypePartNameRecord.cs" />
<Compile Include="ContentManagement\Utilities\LazyField.cs" />
<Compile Include="FileSystems\WebSite\WebSiteFolder.cs" />
<Compile Include="FileSystems\AppData\IAppDataFolder.cs" />
@@ -182,6 +183,12 @@
<Compile Include="ContentManagement\Handlers\PublishContentContext.cs" />
<Compile Include="ContentManagement\Handlers\RemoveContentContext.cs" />
<Compile Include="ContentManagement\Handlers\VersionContentContext.cs" />
<Compile Include="ContentManagement\MetaData\ContentPartHandler.cs" />
<Compile Include="ContentManagement\MetaData\ContentPartInfo.cs" />
<Compile Include="ContentManagement\MetaData\Models\ContentTypePart.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentTypeService.cs" />
<Compile Include="ContentManagement\MetaData\Services\IContentTypeService.cs" />
<Compile Include="ContentManagement\MetaData\Records\ContentTypePartRecord.cs" />
<Compile Include="Data\Conventions\RecordTableNameConvention.cs" />
<Compile Include="Data\Builders\AbstractBuilder.cs" />
<Compile Include="Data\Builders\SessionFactoryBuilder.cs" />