Skip to content

Commit

Permalink
#60 added the ability to map an entity to a view or query
Browse files Browse the repository at this point in the history
  • Loading branch information
kccarter76 committed Aug 13, 2020
1 parent 88a8457 commit e1f6ecd
Show file tree
Hide file tree
Showing 21 changed files with 436 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.7" />
<PackageReference Include="SubSonic.Core.Abstractions" Version="4.2.2" />
<PackageReference Include="SubSonic.Core.Extensions" Version="1.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
<PackageReference Include="System.Data.Common" Version="4.3.0" />
<PackageReference Condition="'$(TargetFramework)'=='netstandard2.0'" Include="System.Data.DataSetExtensions" Version="4.5.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ await Scope.Connection.OpenAsync(cancellationToken)
{
if (reader.HasRows)
{
while (await reader.ReadAsync().ConfigureAwait(false))
while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
SubSonicContext.Current.ChangeTracking.Add(elementType, reader.ActivateAndLoadInstanceOf(elementType));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using SubSonic.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace SubSonic.CodeGenerator.Models
{
[DbView(Query = SQL)]
public class Relationship
{
public const string SQL =
@"SELECT
TableName = FK.TABLE_NAME,
ColumnName = CU.COLUMN_NAME,
ForiegnTableName = PK.TABLE_NAME,
ForiegnColumnName = PT.COLUMN_NAME,
ConstraintName = C.CONSTRAINT_NAME,
SchemaOwner = FK.TABLE_SCHEMA
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN
(
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
)
PT ON PT.TABLE_NAME = PK.TABLE_NAME";

public string TableName { get; set; }

public string ColumnName { get; set; }

public string ForiegnTableName { get; set; }

public string ForiegnColumnName { get; set; }

public string ConstraintName { get; set; }

public string SchemaOwner { get; set; }

[ForeignKey(nameof(TableName))]
public virtual Table Table { get; set; }

[ForeignKey(nameof(ForiegnTableName))]
public virtual Table ForiegnTable { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ namespace SubSonic.CodeGenerator.Models
public class Table
{
public const string SQL =
@"SELECT TABLE_SCHEMA [Schema], TABLE_NAME [Name]
@"SELECT
[Schema] = TABLE_SCHEMA,
[Name] = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE' and TABLE_NAME <> '__RefactorLog'";

Expand All @@ -22,5 +24,7 @@ public Table()
public string Schema { get; set; }

public string Name { get; set; }

public virtual ISubSonicSetCollection<Relationship> Relationships { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public sealed partial class SubSonicSetCollection<TEntity>
private readonly IDbEntityModel model;
private readonly ICollection<IEntityProxy<TEntity>> dataset;

private bool isLoaded = false;
private bool isLoaded;

public SubSonicSetCollection(ISubSonicQueryProvider<TEntity> provider)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,17 @@ public IEnumerable Where(Type elementKey, IQueryProvider provider, Expression ex

private IEnumerable<KeyValuePair<Type, IEnumerable<IEntityProxy>>> BuildEnumeration()
{
switch(dbQueryType)
var _collection = collection.Where(x => x.Value.Model.DbObjectType == Schema.DbObjectTypeEnum.Table);

switch (dbQueryType)
{
case DbQueryType.Update:
case DbQueryType.Insert:
return collection
return _collection
.OrderBy(x => x.Value.Model.ObjectGraphWeight)
.Select(set => new KeyValuePair<Type, IEnumerable<IEntityProxy>>(set.Key, set.Value.ToProxyCollection()));
case DbQueryType.Delete:
return collection
return _collection
.OrderByDescending(x => x.Value.Model.ObjectGraphWeight)
.Select(set => new KeyValuePair<Type, IEnumerable<IEntityProxy>>(set.Key, set.Value.ToProxyCollection()));
case DbQueryType.Unknown:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal static partial class InternalExtensions
public static TType GetService<TType>(this IServiceProvider provider)
where TType : class
{
return (TType)provider.GetService(typeof(TType));
return (TType)provider?.GetService(typeof(TType));
}
}
}
51 changes: 45 additions & 6 deletions SubSonic.Core.DataAccessLayer/src/Extensions/ServiceProviders.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;

namespace SubSonic
{
using Linq;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using SubSonic.Linq;
using SubSonic.Logging;

public static partial class SubSonicExtensions
{
Expand All @@ -29,6 +29,45 @@ public static DbContextOptionsBuilder ConfigureServiceCollection(this DbContextO
return builder;
}

public static DbContextOptionsBuilder AddLogging(this DbContextOptionsBuilder builder, Action<ILoggingBuilder> configure)
{
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
}

if (configure is null)
{
throw new ArgumentNullException(nameof(configure));
}

IServiceCollection services = builder.ServiceProvider.GetService<IServiceCollection>();

services.AddLogging(configure);

builder.ConfigureServiceCollection(services);

return builder;
}

public static ILoggingBuilder AddDebugLogger<TClassName>(this ILoggingBuilder builder)
{
#pragma warning disable CA2000 // Dispose objects before losing scope
builder.AddProvider(new DebugLogProvider<TClassName>());
#pragma warning restore CA2000 // Dispose objects before losing scope

return builder;
}

public static ILoggingBuilder AddTraceLogger<TClassName>(this ILoggingBuilder builder)
{
#pragma warning disable CA2000 // Dispose objects before losing scope
builder.AddProvider(new TraceLogProvider<TClassName>());
#pragma warning restore CA2000 // Dispose objects before losing scope

return builder;
}

public static TReturn GetService<TType, TReturn>(this IServiceProvider provider)
{
if (provider is null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using SubSonic.Attributes;
using SubSonic.Linq.Expressions;
using SubSonic.Linq.Expressions.Alias;
using SubSonic.Schema;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace SubSonic.Linq.Expressions
{
public class DbViewExpression
: DbTableExpression
{
protected internal DbViewExpression(IDbEntityModel model, TableAlias alias)
: base(model, alias)
{
}

public bool IsQuery => Query.IsNotNullOrEmpty();

public string Query
{
get
{
if (Model.EntityModelType.GetCustomAttribute<DbViewAttribute>() is DbViewAttribute dbView)
{
return dbView.Query;
}
return default;
}
}
}

public partial class DbExpression
{
public static DbExpression DbView(IDbEntityModel model, TableAlias alias)
{
return new DbViewExpression(model, alias);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public partial class TSqlFormatter
{
[ThreadStatic]
private static Stack<TSqlFormatter> __formatter_instances;
private int depth = 0;
private int depth;
private readonly TextWriter writer;
private readonly ISqlContext context;
private readonly TableAliasCollection aliases = new TableAliasCollection();
Expand Down Expand Up @@ -60,7 +60,7 @@ protected TSqlFormatter(TextWriter writer, ISqlContext context)

protected static int IndentationWidth => __formatter_instances.Count;

protected bool IsNested { get; set; } = false;
protected bool IsNested { get; set; }

protected ISqlFragment Fragments => context.Fragments;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ protected override Expression VisitSource(Expression source, bool cte = false)
{
Write($"@{dbTableType.QualifiedName}");
}
else if (dbTable is DbViewExpression dbView &&
dbView.IsQuery == true)
{
Write($"{Fragments.LEFT_PARENTHESIS}");
Write(dbView.Query);
Write($"{Fragments.RIGHT_PARENTHESIS}");
}
else
{
Write(dbTable.QualifiedName);
Expand Down
22 changes: 22 additions & 0 deletions SubSonic.Core.DataAccessLayer/src/Logging/DebugLogProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using SubSonic.Core.Logging;
using SubSonic.Logging;
using System;
using System.Collections.Generic;
using System.Text;

namespace SubSonic.Logging
{
public class DebugLogProvider<TClassName>
: LogProvider<TClassName, DebugLogger>
{
public DebugLogProvider()
: base() { }
}

public class TraceLogProvider<TClassName>
: LogProvider<TClassName, TraceLogger>
{
public TraceLogProvider()
: base() { }
}
}
26 changes: 26 additions & 0 deletions SubSonic.Core.DataAccessLayer/src/Logging/DebugLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;

namespace SubSonic.Logging
{
public class DebugLogger
: Logger
{
public DebugLogger()
: base(LogLevel.Debug) { }

public override void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (formatter is null)
{
throw new ArgumentNullException(nameof(formatter));
}

if (IsEnabled(logLevel))
{
Debug.WriteLine(formatter(state, exception));
}
}
}
}
57 changes: 57 additions & 0 deletions SubSonic.Core.DataAccessLayer/src/Logging/LogProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Microsoft.Extensions.Logging;
using SubSonic.Core.Logging;
using SubSonic.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;

namespace SubSonic.Logging
{
public class LogProvider<TClassName, TLogger>
: ILoggerProvider
where TLogger : Logger, new()
{
private readonly ConcurrentDictionary<string, ILogger> m_loggers;
private bool disposedValue;

protected LogProvider()
{
this.m_loggers = new ConcurrentDictionary<string, ILogger>();
}

public ILogger CreateLogger(string categoryName)
{
return m_loggers.GetOrAdd($"{typeof(TClassName).Name}::{categoryName}", new TLogger());
}

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
m_loggers.Clear();
}

// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}

// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~LogProvider()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
Loading

0 comments on commit e1f6ecd

Please sign in to comment.