Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions SubSonic.Extensions.Test/Models/Person.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using SubSonic.Collections;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
Expand Down Expand Up @@ -27,7 +28,7 @@ public class Person
[MaxLength(104)]
public string FullName { get; set; }

public virtual ICollection<Renter> Renters { get; set; }
public virtual ISubSonicCollection<Renter> Renters { get; set; }

public override string ToString() => FullName;
}
Expand Down
10 changes: 3 additions & 7 deletions SubSonic.Extensions.Test/Models/RealEstateProperty.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SubSonic.Infrastructure;
using SubSonic.Collections;
using SubSonic.Infrastructure;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
Expand All @@ -12,11 +13,6 @@ namespace SubSonic.Extensions.Test.Models
[DbCommandQuery(DbQueryType.Insert, typeof(InsertRealEstateProperty))]
public class RealEstateProperty
{
public RealEstateProperty()
{
Units = new HashSet<Unit>();
}

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
Expand All @@ -30,6 +26,6 @@ public RealEstateProperty()


[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "<Pending>")]
public virtual ICollection<Unit> Units { get; set; }
public virtual ISubSonicCollection<Unit> Units { get; set; }
}
}
2 changes: 1 addition & 1 deletion SubSonic.Extensions.Test/Models/Unit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ public class Unit
[ForeignKey(nameof(RealEstatePropertyID))]
public virtual RealEstateProperty RealEstateProperty { get;set;}

public virtual ICollection<Renter> Renters { get; set; }
public virtual ISubSonicCollection<Renter> Renters { get; set; }
}
}
2 changes: 1 addition & 1 deletion SubSonic.Extensions.Test/SubSonic.Extensions.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<RepositoryUrl>https://github.com/kccarter76/SubSonic-Core/tree/master/SubSonic.Extensions.Test</RepositoryUrl>
<PackageLicenseFile>LICENSE.MD</PackageLicenseFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>4.1.0-alpha.2</Version>
<Version>4.1.0-alpha.3</Version>
<ApplicationIcon />
<OutputType>Library</OutputType>
<NeutralLanguage>en</NeutralLanguage>
Expand Down
65 changes: 1 addition & 64 deletions SubSonic.Tests/DAL/DbContext/DbInsertTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,8 @@ public partial class DbContextTests
[Order(0)]
public void ShouldBeAbleToInsertOnePersonRecordWithNoUDTT()
{
string expected_cmd = @"INSERT INTO [dbo].[Person]
OUTPUT INSERTED.* INTO @output
VALUES
(@FirstName, @MiddleInitial, @FamilyName)";

Models.Person person = GetFakePerson.Generate();

Context.Database.Instance.AddCommandBehavior(expected_cmd, cmd =>
{
Models.Person data = new Models.Person()
{
FamilyName = cmd.Parameters["@FamilyName"].Value.ToString(),
FirstName = cmd.Parameters["@FirstName"].Value.ToString(),
MiddleInitial = cmd.Parameters["@MiddleInitial"].Value.IsNotNull(x => x.ToString())
};

People.Add(data);

data.ID = People.Count;

data.FullName = String.Format("{0}, {1}{2}",
data.FamilyName, data.FirstName,
string.IsNullOrEmpty(data.MiddleInitial?.Trim()) ? "" : $" {data.MiddleInitial}.");

return new[] { data }.ToDataTable();
});


Context.People.Add(person);

Context.ChangeTracking.SelectMany(x => x.Value).Count(x => x.IsNew).Should().Be(1);
Expand Down Expand Up @@ -187,33 +162,6 @@ OUTPUT INSERTED.* INTO @output
new Models.Person(){ FirstName = "First_4", FamilyName = "Last_4", FullName = "First_4 Last_4" }
};

Context.Database.Instance.AddCommandBehavior(expected_cmd, cmd =>
{
cmd.Parameters["@MiddleInitial"].DbType.Should().Be(DbType.AnsiString);

Models.Person[] _persons = new[]
{
new Models.Person()
{
FamilyName = cmd.Parameters["@FamilyName"].Value.ToString(),
FirstName = cmd.Parameters["@FirstName"].Value.ToString(),
MiddleInitial = cmd.Parameters["@MiddleInitial"].Value.IsNotNull(x => x.ToString())
}
};

foreach (var person in _persons)
{
People.Add(person);

person.ID = People.Count;
person.FullName = String.Format("{0}, {1}{2}",
person.FamilyName, person.FirstName,
person.MiddleInitial.IsNotNullOrEmpty() ? $" {person.MiddleInitial}." : "");
}

return _persons.ToDataTable();
});

Context.People.AddRange(people);

Context.ChangeTracking.SelectMany(x => x.Value).Count(x => x.IsNew).Should().Be(3);
Expand Down Expand Up @@ -330,17 +278,6 @@ public void ShouldBeAbleToInsertRenterWithCompositeKey(bool withUDTT, string exp

renters.CopyTo(original, 0);

//if (!withUDTT)
//{
// // ubunto and windows format dates very differently
// for (int i = 0; i < renters.Length; i++)
// {
// expected = expected
// .Replace($"[StartDate_{i}]", renters[i].StartDate.ToString())
// .Replace($"[EndDate_{i}]", renters[i].EndDate.ToString());
// }
//}

Context.Database.Instance.AddCommandBehavior(expected, cmd =>
{
if (withUDTT)
Expand Down
1 change: 0 additions & 1 deletion SubSonic.Tests/DAL/DbModels/PersonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public void CanInsertPersonRecords(int count)
.RuleFor(p => p.FamilyName, x => x.PickRandom(DataSeed.Person.FamilyNames))
.RuleFor(p => p.FirstName, x => x.PickRandom(DataSeed.Person.FirstNames))
.RuleFor(p => p.MiddleInitial, x => x.PickRandom(DataSeed.Person.MiddleInitial))
.RuleFor(p => p.Renters, x => new HashSet<Models.Renter>())
.RuleFor(p => p.FullName, x => string.Empty);

Context.People.AddRange(people.Generate(count));
Expand Down
87 changes: 86 additions & 1 deletion SubSonic.Tests/DAL/DynamicProxy/DynamicProxyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace SubSonic.Tests.DAL
{
using Extensions.Test;
using Linq;
using SubSonic.Collections;
using SUT;

[TestFixture]
Expand Down Expand Up @@ -199,9 +200,93 @@ public void ProxyCollectionPropertyWillNotLoadWhenNotNullAndCountGreaterThanZero
{
RealEstateProperty instance = DynamicProxy.CreateProxyInstanceOf<RealEstateProperty>(Context);

instance.Units = new HashSet<Unit>(new[] { DynamicProxy.CreateProxyInstanceOf<Unit>(Context) });
instance.Units = new SubSonicCollection<Unit>(new[] { DynamicProxy.CreateProxyInstanceOf<Unit>(Context) });

instance.Units = new SubSonicCollection<Unit>()
{
DynamicProxy.CreateProxyInstanceOf<Unit>(Context)
};

instance.Units.Should().NotBeNull();
}

[Test]
public void ProxyInitializationViaContext()
{
RealEstateProperty instance = Context.NewEntity<RealEstateProperty>();

((IEntityProxy)instance).IsNew.Should().BeTrue();
}

private static IEnumerable<RealEstateProperty> ProxyInitializationViaContextSource()
{
yield return null;
yield return new RealEstateProperty() { ID = 0, StatusID = 1, HasParallelPowerGeneration = true };
}

[Test]
[TestCaseSource(nameof(ProxyInitializationViaContextSource))]
public void ProxyInitializationViaContext(RealEstateProperty source)
{
RealEstateProperty instance = Context.NewEntityFrom(source);

((IEntityProxy)instance).IsNew.Should().BeTrue();
((IEntityProxy)instance).IsDirty.Should().BeFalse();

IDbQuery query = null;

FluentActions.Invoking(() =>
{
if (instance.Units.Provider is ISubSonicQueryProvider provider)
{
query = provider.ToQuery(instance.Units.Expression);
}
}).Should().NotThrow();

query.Sql.Should().Be(@"SELECT [T1].[ID], [T1].[Bedrooms] AS [NumberOfBedrooms], [T1].[StatusID], [T1].[RealEstatePropertyID]
FROM [dbo].[Unit] AS [T1]
WHERE ([T1].[RealEstatePropertyID] = @realestatepropertyid_1)");
query.Parameters.Get("@realestatepropertyid_1").GetValue<int>().Should().Be(instance.ID);
}

[Test]
public void ProxyInitializationViaContextSavedToDb()
{
Person instance = GetFakePerson.Generate();

((IEntityProxy)instance).IsNew.Should().BeTrue();
((IEntityProxy)instance).IsDirty.Should().BeFalse();

IDbQuery query = null;

FluentActions.Invoking(() =>
{
if (instance.Renters.Provider is ISubSonicQueryProvider provider)
{
query = provider.ToQuery(instance.Renters.Expression);
}
}).Should().NotThrow();

query.Sql.Should().Be(@"SELECT [T1].[PersonID], [T1].[UnitID], [T1].[Rent], [T1].[StartDate], [T1].[EndDate]
FROM [dbo].[Renter] AS [T1]
WHERE ([T1].[PersonID] = @personid_1)");
query.Parameters.Get("@personid_1").GetValue<int>().Should().Be(instance.ID);

Context.People.Add(instance);

Context.SaveChanges();

instance.ID.Should().NotBe(0);

FluentActions.Invoking(() =>
{
if (instance.Renters.Provider is ISubSonicQueryProvider provider)
{
query = provider.ToQuery(instance.Renters.Expression);
}
}).Should().NotThrow();

query.Parameters.Get("@personid_1").GetValue<int>().Should().Be(instance.ID);
}
}
}
42 changes: 40 additions & 2 deletions SubSonic.Tests/DAL/SUT/BaseTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,20 @@ protected Bogus.Faker<Person> GetFakePerson
{
get
{
return new Bogus.Faker<Person>()
return new SubSonicFaker<Person>()
.UseDbContext()
.RuleFor(person => person.ID, set => 0)
.RuleFor(person => person.FirstName, set => set.PickRandom(DataSeed.Person.FirstNames))
.RuleFor(person => person.MiddleInitial, set => set.PickRandom(DataSeed.Person.MiddleInitial))
.RuleFor(person => person.FamilyName, set => set.PickRandom(DataSeed.Person.FamilyNames))
.RuleFor(person => person.FullName, set => null)
.RuleFor(person => person.Renters, set => new HashSet<Renter>());
.FinishWith((faker, person) =>
{
if (person is IEntityProxy proxy)
{
proxy.IsDirty = false;
}
});
}
}

Expand All @@ -47,6 +54,8 @@ public virtual void SetupTestFixture()

Context.Instance.GetService<DbProviderFactory, SubSonicMockDbClient>().ClearBehaviors();

SetInsertBehaviors();

Statuses = new List<Status>()
{
new Status() { ID = 1, Name = "Vacant", IsAvailableStatus = true },
Expand Down Expand Up @@ -88,6 +97,35 @@ public virtual void SetupTestFixture()
};
}

private void SetInsertBehaviors()
{
string
insert_person = @"INSERT INTO [dbo].[Person]
OUTPUT INSERTED.* INTO @output
VALUES
(@FirstName, @MiddleInitial, @FamilyName)";

Context.Database.Instance.AddCommandBehavior(insert_person, cmd =>
{
Person data = new Person()
{
FamilyName = cmd.Parameters["@FamilyName"].Value.ToString(),
FirstName = cmd.Parameters["@FirstName"].Value.ToString(),
MiddleInitial = cmd.Parameters["@MiddleInitial"].Value.IsNotNull(x => x.ToString())
};

People.Add(data);

data.ID = People.Count;

data.FullName = String.Format("{0}, {1}{2}",
data.FamilyName, data.FirstName,
string.IsNullOrEmpty(data.MiddleInitial?.Trim()) ? "" : $" {data.MiddleInitial}.");

return new[] { data }.ToDataTable();
});
}

protected IEnumerable<Status> Statuses { get; set; }
protected ICollection<Unit> Units { get; set; }
protected ICollection<Renter> Renters { get; set; }
Expand Down
22 changes: 22 additions & 0 deletions SubSonic.Tests/DAL/SUT/SubSonicFaker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Bogus;
using System;
using System.Collections.Generic;
using System.Text;

namespace SubSonic.Tests.DAL.SUT
{
class SubSonicFaker<TEntity>
: Faker<TEntity>
where TEntity: class
{
public SubSonicFaker<TEntity> UseDbContext()
{
if (base.CustomInstantiator(f => DbContext.Current.NewEntity<TEntity>()) is SubSonicFaker<TEntity> faker)
{
return faker;
}

throw Error.InvalidOperation();
}
}
}
2 changes: 1 addition & 1 deletion SubSonic/Data/DynamicProxies/DbContextAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public DbContextAccessor(DbContext dbContext)

private DbContext DbContext { get; }

public DbModel Model => DbContext.Model;
public DbSchemaModel Model => DbContext.Model;

public TProperty LoadProperty<TEntity, TProperty>(TEntity entity, PropertyInfo info)
where TEntity : class
Expand Down
23 changes: 21 additions & 2 deletions SubSonic/Data/DynamicProxies/DynamicProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,33 @@ public static TEntity CreateProxyInstanceOf<TEntity>(DbContext dbContext)

DynamicProxyWrapper proxy = GetProxyWrapper<TEntity>(dbContext);

TEntity entity;

if (dbContext.Options.EnableProxyGeneration && proxy.IsElegibleForProxy)
{
return (TEntity)Activator.CreateInstance(proxy.Type, new DbContextAccessor(dbContext));
entity = (TEntity)Activator.CreateInstance(proxy.Type, new DbContextAccessor(dbContext));
}
else
{
return Activator.CreateInstance<TEntity>();
entity = Activator.CreateInstance<TEntity>();
}

if (entity is IEntityProxy<TEntity> _entity)
{
_entity.IsNew = true;
}

return entity;
}

public static TEntity MapInstanceOf<TEntity>(TEntity source, TEntity proxy)
{
if (!(source.IsNull() == null))
{
proxy.Map(source);
}

return proxy;
}

public static TEntity MapInstanceOf<TEntity>(DbContext context, IEntityProxy<TEntity> instance)
Expand Down
Loading